2 # Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved.
4 # This program is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License version 2 as published
6 # by the Free Software Foundation.
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
20 use lib '@amperldir@';
24 package Amanda::Application::Amzfs_sendrecv;
25 use base qw(Amanda::Application Amanda::Application::Zfs);
31 use Amanda::Constants;
32 use Amanda::Config qw( :init :getconf config_dir_relative );
33 use Amanda::Debug qw( :logging );
35 use Amanda::Util qw( :constants );
39 my ($config, $host, $disk, $device, $level, $index, $message, $collection, $record, $df_path, $zfs_path, $pfexec_path, $pfexec, $keep_snapshot) = @_;
40 my $self = $class->SUPER::new();
42 $self->{config} = $config;
43 $self->{host} = $host;
44 $self->{disk} = $disk;
45 $self->{device} = $device;
46 $self->{level} = [ @{$level} ];
47 $self->{index} = $index;
48 $self->{message} = $message;
49 $self->{collection} = $collection;
50 $self->{record} = $record;
51 $self->{df_path} = $df_path;
52 $self->{zfs_path} = $zfs_path;
53 $self->{pfexec_path} = $pfexec_path;
54 $self->{pfexec} = $pfexec;
55 $self->{keep_snapshot} = $keep_snapshot;
56 $self->{pfexec_cmd} = undef;
58 if ($self->{keep_snapshot} =~ /^YES$/i) {
59 $self->{keep_snapshot} = "YES";
60 if (!defined $self->{record}) {
61 $self->{keep_snapshot} = "NO";
68 sub check_for_backup_failure {
72 $self->zfs_destroy_snapshot($action);
81 print "MAX-LEVEL 9\n";
82 print "INDEX-LINE NO\n";
83 print "INDEX-XML NO\n";
84 print "MESSAGE-LINE YES\n";
85 print "MESSAGE-XML NO\n";
87 print "COLLECTION NO\n";
90 sub command_selfcheck {
93 $self->zfs_set_value("check");
94 if ($self->{error_status} == $Amanda::Script_App::GOOD) {
95 $self->zfs_create_snapshot("check");
96 $self->zfs_destroy_snapshot("check");
97 print "OK " . $self->{disk} . "\n";
98 print "OK " . $self->{device} . "\n";
102 sub command_estimate() {
107 $self->zfs_set_value("estimate");
108 $self->zfs_create_snapshot("estimate");
110 while (defined ($level = shift @{$self->{level}})) {
111 debug "Estimate of level $level";
112 my $size = $self->estimate_snapshot($level);
113 output_size($level, $size);
116 $self->zfs_destroy_snapshot("estimate");
125 print "$level -1 -1\n";
129 my($ksize) = int $size / (1024);
130 $ksize=32 if ($ksize<32);
131 print "$level $ksize 1\n";
139 open($mesgout_fd, '>&=3') || die();
140 $self->{mesgout} = $mesgout_fd;
142 $self->zfs_set_value("backup");
143 $self->zfs_create_snapshot("backup");
146 my $level = $self->{level}[0];
148 debug "Backup of level $level";
150 $cmd = "$self->{pfexec_cmd} $self->{zfs_path} send $self->{filesystem}\@$self->{snapshot} | $Amanda::Paths::amlibexecdir/teecount";
152 my $refsnapshotname = $self->zfs_find_snapshot_level($level-1);
153 debug "Referenced snapshot name: $refsnapshotname|";
154 if ($refsnapshotname ne "") {
155 $cmd = "$self->{pfexec_cmd} $self->{zfs_path} send -i $refsnapshotname $self->{filesystem}\@$self->{snapshot} | $Amanda::Paths::amlibexecdir/teecount";
157 $self->print_to_server_and_die("sendbackup", "cannot backup snapshot '$self->{filesystem}\@$self->{snapshot}': reference snapshot doesn't exists for level $level", $Amanda::Script_App::ERROR);
161 debug "running (backup): $cmd";
162 my($wtr, $err, $pid);
164 $err = Symbol::gensym;
165 $pid = open3($wtr, '>&STDOUT', $err, $cmd);
171 if (defined $errmsg) {
172 $self->print_to_server_and_die("sendbackup", $errmsg, $Amanda::Script_App::ERROR);
174 $self->print_to_server_and_die("sendbackup", "cannot backup snapshot '$self->{filesystem}\@$self->{snapshot}': unknown reason", $Amanda::Script_App::ERROR);
180 my($ksize) = int ($size/1024);
181 $ksize=32 if ($ksize<32);
183 print $mesgout_fd "sendbackup: size $ksize\n";
184 print $mesgout_fd "sendbackup: end\n";
186 # destroy all snapshot of this level and higher
187 $self->zfs_purge_snapshot($level, 9, "backup");
189 if ($self->{keep_snapshot} eq 'YES') {
190 $self->zfs_rename_snapshot($level, "backup");
192 $self->zfs_destroy_snapshot("backup");
198 sub estimate_snapshot
204 debug "\$filesystem = $self->{filesystem}";
205 debug "\$snapshot = $self->{snapshot}";
206 debug "\$level = $level";
210 $cmd = "$self->{pfexec_cmd} $self->{zfs_path} get -Hp -o value referenced $self->{filesystem}\@$self->{snapshot}";
212 my $refsnapshotname = $self->zfs_find_snapshot_level($level-1);
213 debug "Referenced snapshot name: $refsnapshotname|";
214 if ($refsnapshotname ne "") {
215 $cmd = "$self->{pfexec_cmd} $self->{zfs_path} send -i $refsnapshotname $self->{filesystem}\@$self->{snapshot} | /usr/bin/wc -c";
220 debug "running (estimate): $cmd";
221 my($wtr, $rdr, $err, $pid);
222 $err = Symbol::gensym;
223 $pid = open3($wtr, $rdr, $err, $cmd);
226 my ($errmsg) = <$err>;
231 if (defined $msg && defined $errmsg) {
232 $self->print_to_server_and_die($action, "$msg, $errmsg", $Amanda::Script_App::ERROR);
233 } elsif (defined $msg) {
234 $self->print_to_server_and_die($action, $msg, $Amanda::Script_App::ERROR);
235 } elsif (defined $errmsg) {
236 $self->print_to_server_and_die($action, $errmsg, $Amanda::Script_App::ERROR);
238 $self->print_to_server_and_die($action, "cannot estimate snapshot '$self->{snapshot}\@$self->{snapshot}': unknown reason", $Amanda::Script_App::ERROR);
245 sub command_index_from_output {
248 sub command_index_from_image {
251 sub command_restore {
254 sub command_print_command {
261 Usage: amzfs-sendrecv <command> --config=<config> --host=<host> --disk=<disk> --device=<device> --level=<level> --index=<yes|no> --message=<text> --collection=<no> --record=<yes|no> --df-path=<path/to/df> --zfs-path=<path/to/zfs> --pfexec-path=<path/to/pfexec> --pfexec=<yes|no> --keep-snapshot=<yes|no>.
276 my $zfs_path = 'zfs';
277 my $pfexec_path = 'pfexec';
279 my $opt_keep_snapshot = "YES";
281 Getopt::Long::Configure(qw{bundling});
283 'config=s' => \$opt_config,
284 'host=s' => \$opt_host,
285 'disk=s' => \$opt_disk,
286 'device=s' => \$opt_device,
287 'level=s' => \@opt_level,
288 'index=s' => \$opt_index,
289 'message=s' => \$opt_message,
290 'collection=s' => \$opt_collection,
291 'record' => \$opt_record,
292 'df-path=s' => \$df_path,
293 'zfs-path=s' => \$zfs_path,
294 'pfexec-path=s' => \$pfexec_path,
295 'pfexec=s' => \$pfexec,
296 'keep-snapshot=s' => \$opt_keep_snapshot
299 my $application = Amanda::Application::Amzfs_sendrecv->new($opt_config, $opt_host, $opt_disk, $opt_device, \@opt_level, $opt_index, $opt_message, $opt_collection, $opt_record, $df_path, $zfs_path, $pfexec_path, $pfexec, $opt_keep_snapshot);
301 $application->do($ARGV[0]);