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 {
my ($opt_config, $opt_blocksize, $opt_raw, $opt_compress, $opt_compress_best,
$opt_pipe, $opt_header, $opt_filenum, $opt_label, $opt_holding, $opt_restore_src);
+
+debug("Arguments: " . join(' ', @ARGV));
Getopt::Long::Configure(qw(bundling));
GetOptions(
'version' => \&Amanda::Util::version_opt,
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
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);
}
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;
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);
# 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
@filters = (
Amanda::Xfer::Filter::Process->new(
[ $Amanda::Constants::COMPRESS_PATH,
- $compress_opt ], 0, 0),
+ $compress_opt ], 0),
);
# adjust the header
$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;
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'}->();
}
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);