Imported Upstream version 3.3.0
[debian/amanda] / server-src / amrestore.pl
index 6114336f163f9d59837bda5527d630cb8cb36a53..d7f2421dd6e796539ddb12698323dbf009fb0241 100644 (file)
@@ -30,9 +30,11 @@ use Amanda::Util qw( :constants );
 use Amanda::Changer;
 use Amanda::Constants;
 use Amanda::MainLoop;
+use Amanda::MainLoop qw( :GIOCondition );
 use Amanda::Header;
 use Amanda::Holding;
 use Amanda::Cmdline;
+use Amanda::Tapelist;
 use Amanda::Xfer qw( :constants );
 
 sub usage {
@@ -132,12 +134,16 @@ sub main {
 
     my $dev;
     my $hdr;
+    my $chg;
     my $filenum = $opt_filenum;
     $filenum = 1 if (!$filenum);
     $filenum = 0 + "$filenum"; # convert to integer
+    my %all_filter;
+    my $restore_done;
 
     my $steps = define_steps
-       cb_ref => \$finished_cb;
+       cb_ref => \$finished_cb,
+       finalize => sub { $chg->quit() if defined $chg };
 
     step start => sub {
        # first, return to the original working directory we were started in
@@ -148,7 +154,9 @@ sub main {
        if ($opt_holding) {
            $steps->{'read_header'}->();
        } else {
-           my $chg = Amanda::Changer->new($opt_restore_src);
+           my $tlf = Amanda::Config::config_dir_relative(getconf($CNF_TAPELIST));
+           my $tl = Amanda::Tapelist->new($tlf);
+           $chg = Amanda::Changer->new($opt_restore_src, tapelist => $tl);
            if ($chg->isa("Amanda::Changer::Error")) {
                return failure($chg, $finished_cb);
            }
@@ -175,11 +183,6 @@ sub main {
            return failure($dev->error_or_status, $finished_cb);
        }
 
-       $res->set_label(label => $dev->volume_label,
-                       finished_cb => $steps->{'set_labeled'});
-    };
-
-    step set_labeled => sub {
        if ($opt_label) {
            if ($dev->volume_label ne $opt_label) {
                my $got = $dev->volume_label;
@@ -286,11 +289,11 @@ sub main {
            if ($hdr->{'srv_encrypt'}) {
                push @filters,
                    Amanda::Xfer::Filter::Process->new(
-                       [ $hdr->{'srv_encrypt'}, $hdr->{'srv_decrypt_opt'} ], 0, 0);
+                       [ $hdr->{'srv_encrypt'}, $hdr->{'srv_decrypt_opt'} ], 0);
            } elsif ($hdr->{'clnt_encrypt'}) {
                push @filters,
                    Amanda::Xfer::Filter::Process->new(
-                       [ $hdr->{'clnt_encrypt'}, $hdr->{'clnt_decrypt_opt'} ], 0, 0);
+                       [ $hdr->{'clnt_encrypt'}, $hdr->{'clnt_decrypt_opt'} ], 0);
            } else {
                return failure("could not decrypt encrypted dump: no program specified",
                            $finished_cb);
@@ -310,17 +313,17 @@ sub main {
                # TODO: this assumes that srvcompprog takes "-d" to decompress
                push @filters,
                    Amanda::Xfer::Filter::Process->new(
-                       [ $hdr->{'srvcompprog'}, "-d" ], 0, 0);
+                       [ $hdr->{'srvcompprog'}, "-d" ], 0);
            } elsif ($hdr->{'clntcompprog'}) {
                # TODO: this assumes that clntcompprog takes "-d" to decompress
                push @filters,
                    Amanda::Xfer::Filter::Process->new(
-                       [ $hdr->{'clntcompprog'}, "-d" ], 0, 0);
+                       [ $hdr->{'clntcompprog'}, "-d" ], 0);
            } else {
                push @filters,
                    Amanda::Xfer::Filter::Process->new(
                        [ $Amanda::Constants::UNCOMPRESS_PATH,
-                         $Amanda::Constants::UNCOMPRESS_OPT ], 0, 0);
+                         $Amanda::Constants::UNCOMPRESS_OPT ], 0);
            }
            
            # adjust the header
@@ -335,7 +338,7 @@ sub main {
            @filters = (
                Amanda::Xfer::Filter::Process->new(
                    [ $Amanda::Constants::COMPRESS_PATH,
-                     $compress_opt ], 0, 0),
+                     $compress_opt ], 0),
            );
            
            # adjust the header
@@ -350,6 +353,40 @@ sub main {
            $hdr->{'blocksize'} = Amanda::Holding::DISK_BLOCK_BYTES;
            $dest_fh->syswrite($hdr->to_string(32768, 32768));
        }
+
+       # start reading all filter stderr
+       foreach my $filter (@filters) {
+           my $fd = $filter->get_stderr_fd();
+           $fd.="";
+           $fd = int($fd);
+           my $src = Amanda::MainLoop::fd_source($fd,
+                                                 $G_IO_IN|$G_IO_HUP|$G_IO_ERR);
+           my $buffer = "";
+           $all_filter{$src} = 1;
+           $src->set_callback( sub {
+               my $b;
+               my $n_read = POSIX::read($fd, $b, 1);
+               if (!defined $n_read) {
+                   return;
+               } elsif ($n_read == 0) {
+                   delete $all_filter{$src};
+                   $src->remove();
+                   POSIX::close($fd);
+                   if (!%all_filter and $restore_done) {
+                       $finished_cb->();
+                   }
+               } else {
+                   $buffer .= $b;
+                   if ($b eq "\n") {
+                       my $line = $buffer;
+                       print STDERR "filter stderr: $line";
+                       chomp $line;
+                       debug("filter stderr: $line");
+                       $buffer = "";
+                   }
+               }
+           });
+       }
        
        my $xfer = Amanda::Xfer->new([ $src, @filters, $dest ]);
        my $got_err = undef;
@@ -372,13 +409,14 @@ sub main {
        my ($err) = @_;
        return failure($err, $finished_cb) if $err;
 
-       $steps->{'next_file'}->();
+       $steps->{'next_file'}->('extracted');
     };
 
     step next_file => sub {
-       # amrestore does not loop over multiple files when reading from
-       # holding or when outputting to a pipe
-       if ($opt_holding or $opt_pipe) {
+       my ($extracted) = @_;
+       # amrestore does not loop over multiple files when reading from holding
+       # when outputting to a pipe amrestore extracts only the first file
+       if ($opt_holding or ($opt_pipe and $extracted)) {
            return $steps->{'finished'}->();
        }
 
@@ -397,10 +435,12 @@ sub main {
     step quit => sub {
        my ($err) = @_;
        $res = undef;
-
+       $restore_done = 1;
        return failure($err, $finished_cb) if $err;
 
-       $finished_cb->();
+       if (!%all_filter) {
+           $finished_cb->();
+       }
     };
 }
 main(\&Amanda::MainLoop::quit);