+ my $xfer_dest;
+ my @filters;
+
+ if (defined $opt_data_path and $opt_data_path eq 'directtcp' and !$directtcp_supported) {
+ return failure("The device can't do directtcp", $finished_cb);
+ }
+ $directtcp_supported = 0 if defined $opt_data_path and $opt_data_path eq 'amanda';
+ if ($opt_extract) {
+ my $program = uc(basename($hdr->{program}));
+ my @argv;
+ if ($program ne "APPLICATION") {
+ $directtcp_supported = 0;
+ my %validation_programs = (
+ "STAR" => [ $Amanda::Constants::STAR, qw(-x -f -) ],
+ "DUMP" => [ $Amanda::Constants::RESTORE, qw(xbf 2 -) ],
+ "VDUMP" => [ $Amanda::Constants::VRESTORE, qw(xf -) ],
+ "VXDUMP" => [ $Amanda::Constants::VXRESTORE, qw(xbf 2 -) ],
+ "XFSDUMP" => [ $Amanda::Constants::XFSRESTORE, qw(-v silent) ],
+ "TAR" => [ $Amanda::Constants::GNUTAR, qw(--ignore-zeros -xf -) ],
+ "GTAR" => [ $Amanda::Constants::GNUTAR, qw(--ignore-zeros -xf -) ],
+ "GNUTAR" => [ $Amanda::Constants::GNUTAR, qw(--ignore-zeros -xf -) ],
+ "SMBCLIENT" => [ $Amanda::Constants::GNUTAR, qw(-xf -) ],
+ "PKZIP" => undef,
+ );
+ if (!exists $validation_programs{$program}) {
+ return failure("Unknown program '$program' in header; no validation to perform",
+ $finished_cb);
+ }
+ @argv = $validation_programs{$program};
+ } else {
+ if (!defined $hdr->{application}) {
+ return failure("Application not set", $finished_cb);
+ }
+ my $program_path = $Amanda::Paths::APPLICATION_DIR . "/" .
+ $hdr->{application};
+ if (!-x $program_path) {
+ return failure("Application '" . $hdr->{application} .
+ "($program_path)' not available on the server",
+ $finished_cb);
+ }
+ my %bsu_argv;
+ $bsu_argv{'application'} = $hdr->{application};
+ $bsu_argv{'config'} = $opt_config;
+ $bsu_argv{'host'} = $hdr->{'name'};
+ $bsu_argv{'disk'} = $hdr->{'disk'};
+ $bsu_argv{'device'} = $dle->{'diskdevice'} if defined $dle->{'diskdevice'};
+ my ($bsu, $err) = Amanda::Extract::BSU(%bsu_argv);
+ if (defined $opt_data_path and $opt_data_path eq 'directtcp' and
+ !$bsu->{'data-path-directtcp'}) {
+ return failure("The application can't do directtcp", $finished_cb);
+ }
+ if ($directtcp_supported and !$bsu->{'data-path-directtcp'}) {
+ # application do not support directtcp
+ $directtcp_supported = 0;
+ }
+
+ push @argv, $program_path, "restore";
+ push @argv, "--config", $opt_config;
+ push @argv, "--host", $hdr->{'name'};
+ push @argv, "--disk", $hdr->{'disk'};
+ push @argv, "--device", $dle->{'diskdevice'} if defined ($dle->{'diskdevice'});
+ push @argv, "--level", $hdr->{'dumplevel'};
+ push @argv, "--directory", $opt_directory;
+
+ # add application_property
+ while (my($name, $value) = each(%application_property)) {
+ push @argv, "--".$name, $value if $value;
+ }
+
+ #merge property from header;
+ while (my($name, $value) = each (%{$dle->{'backup-program'}->{'property'}})) {
+ if (!exists $application_property{$name}) {
+ push @argv, "--".$name, $value->{'value'};
+ }
+ }
+
+ }
+ $directtcp = $directtcp_supported;
+ if ($directtcp_supported) {
+ $xfer_dest = Amanda::Xfer::Dest::DirectTCPListen->new();
+ @directtcp_command = @argv;
+ } else {
+ # set up the extraction command as a filter element, since
+ # we need its stderr.
+ debug("Running: ". join(' ',@argv));
+ push @filters, Amanda::Xfer::Filter::Process->new(\@argv, 0);
+
+ $dest_fh = \*STDOUT;
+ $xfer_dest = Amanda::Xfer::Dest::Fd->new($dest_fh);
+ }
+ } elsif ($opt_pipe) {