X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Famidxtaped.pl;h=79ea978767e1bf74ca760ccc1c764e323dbd39cd;hb=HEAD;hp=ea22fc28e9f88e564f22fca30f1c73be6f4bc69d;hpb=42ff24f2a525d5965e1841b2ebe3ee0f4b918ac6;p=debian%2Famanda diff --git a/server-src/amidxtaped.pl b/server-src/amidxtaped.pl index ea22fc2..79ea978 100644 --- a/server-src/amidxtaped.pl +++ b/server-src/amidxtaped.pl @@ -1,9 +1,10 @@ #! @PERL@ -# Copyright (c) 2010 Zmanda, Inc. All Rights Reserved. +# Copyright (c) 2010-2012 Zmanda, Inc. All Rights Reserved. # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 as published -# by the Free Software Foundation. +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY @@ -22,10 +23,10 @@ use strict; use warnings; ## -# Interactive class +# Interactivity class -package main::Interactive; -use base 'Amanda::Interactive'; +package main::Interactivity; +use base 'Amanda::Interactivity'; use Amanda::Util qw( weaken_ref ); use Amanda::MainLoop; use Amanda::Feature; @@ -59,7 +60,7 @@ sub user_request { my $buffer = ""; my $steps = define_steps - cb_ref => \$params{'finished_cb'}; + cb_ref => \$params{'request_cb'}; step send_message => sub { if ($params{'err'}) { @@ -73,7 +74,7 @@ sub user_request { # note that fe_amrecover_FEEDME implies fe_amrecover_splits if (!$self->{'clientservice'}->{'their_features'}->has( $Amanda::Feature::fe_amrecover_FEEDME)) { - return $params{'finished_cb'}->("remote cannot prompt for volumes", undef); + return $params{'request_cb'}->("remote cannot prompt for volumes", undef); } $steps->{'send_feedme'}->(); }; @@ -84,7 +85,7 @@ sub user_request { step read_response => sub { my ($err, $written) = @_; - return $params{'finished_cb'}->($err, undef) if $err; + return $params{'request_cb'}->($err, undef) if $err; $self->{'clientservice'}->getline_async( $self->{'clientservice'}->{'ctl_stream'}, $steps->{'got_response'}); @@ -92,18 +93,18 @@ sub user_request { step got_response => sub { my ($err, $line) = @_; - return $params{'finished_cb'}->($err, undef) if $err; + return $params{'request_cb'}->($err, undef) if $err; if ($line eq "OK\r\n") { - return $params{'finished_cb'}->(undef, undef); # carry on as you were + return $params{'request_cb'}->(undef, undef); # carry on as you were } elsif ($line =~ /^TAPE (.*)\r\n$/) { my $tape = $1; if ($tape eq getconf($CNF_AMRECOVER_CHANGER)) { $tape = $Amanda::Recovery::Scan::DEFAULT_CHANGER; } - return $params{'finished_cb'}->(undef, $tape); # use this device + return $params{'request_cb'}->(undef, $tape); # use this device } else { - return $params{'finished_cb'}->("got invalid response from remote", undef); + return $params{'request_cb'}->("got invalid response from remote", undef); } }; }; @@ -114,8 +115,11 @@ sub user_request { package main::ClientService; use base 'Amanda::ClientService'; +use Sys::Hostname; + use Amanda::Debug qw( debug info warning ); -use Amanda::Util qw( :constants ); +use Amanda::MainLoop qw( :GIOCondition ); +use Amanda::Util qw( :constants match_disk match_host ); use Amanda::Feature; use Amanda::Config qw( :init :getconf ); use Amanda::Changer; @@ -127,7 +131,6 @@ use Amanda::Recovery::Planner; use Amanda::Recovery::Scan; use Amanda::DB::Catalog; use Amanda::Disklist; -use Amanda::Logfile qw( match_disk match_host ); # Note that this class performs its control IO synchronously. This is adequate # for this service, as it never receives unsolicited input from the remote @@ -138,6 +141,7 @@ sub run { $self->{'my_features'} = Amanda::Feature::Set->mine(); $self->{'their_features'} = Amanda::Feature::Set->old(); + $self->{'all_filter'} = {}; $self->setup_streams(); } @@ -332,10 +336,12 @@ sub make_plan { $use_default = 1; } + my $tlf = Amanda::Config::config_dir_relative(getconf($CNF_TAPELIST)); + my $tl = Amanda::Tapelist->new($tlf); if ($use_default) { - $chg = Amanda::Changer->new(); + $chg = Amanda::Changer->new(undef, tapelist => $tl); } else { - $chg = Amanda::Changer->new($self->{'command'}{'DEVICE'}); + $chg = Amanda::Changer->new($self->{'command'}{'DEVICE'}, tapelist => $tl); } # if we got a bogus changer, log it to the debug log, but allow the @@ -345,11 +351,15 @@ sub make_plan { $chg = Amanda::Changer->new("chg-null:"); } } - my $inter = main::Interactive->new(clientservice => $self); + $self->{'chg'} = $chg; + + my $interactivity = main::Interactivity->new(clientservice => $self); my $scan = Amanda::Recovery::Scan->new( chg => $chg, - interactive => $inter); + interactivity => $interactivity); + $self->{'scan'} = $scan; + # XXX temporary $scan->{'scan_conf'}->{'driveinuse'} = Amanda::Recovery::Scan::SCAN_ASK; $scan->{'scan_conf'}->{'volinuse'} = Amanda::Recovery::Scan::SCAN_ASK; @@ -394,6 +404,7 @@ sub make_plan { return Amanda::Recovery::Planner::make_plan( filelist => $filelist, + chg => $chg, $spec? (dumpspec => $spec) : (), plan_cb => sub { $self->plan_cb(@_); }); } @@ -429,25 +440,33 @@ sub plan_cb { my $peer = $ENV{'AMANDA_AUTHENTICATED_PEER'}; if (defined $recovery_limit) { # undef -> no recovery limit if (!$peer) { - warning("a recovery limit is specified for this DLE, but no authenticted ". + warning("a recovery limit is specified for this DLE, but no authenticated ". "peer name is available; rejecting request."); $self->sendmessage("No matching dumps found"); return $self->quit(); } my $matched = 0; for my $rl (@$recovery_limit) { - if (!defined $rl) { + if ($rl eq $Amanda::Config::LIMIT_SAMEHOST) { # handle same-host with a case-insensitive string compare, not match_host if (lc($peer) eq lc($dump->{'hostname'})) { $matched = 1; last; } - } - - # otherwise use match_host to allow match expressions - if (match_host($rl, $peer)) { - $matched = 1; - last; + } elsif ($rl eq $Amanda::Config::LIMIT_SERVER) { + # handle server with a case-insensitive string compare, not match_host + my $myhostname = hostname; + debug("myhostname: $myhostname"); + if (lc($peer) eq lc($myhostname)) { + $matched = 1; + last; + } + } else { + # otherwise use match_host to allow match expressions + if (match_host($rl, $peer)) { + $matched = 1; + last; + } } } if (!$matched) { @@ -468,8 +487,9 @@ sub plan_cb { } # now set up the transfer + $self->{'dump'} = $plan->{'dumps'}[0]; $self->{'clerk'}->get_xfer_src( - dump => $plan->{'dumps'}[0], + dump => $self->{'dump'}, xfer_src_cb => sub { $self->xfer_src_cb(@_); }); } @@ -496,22 +516,33 @@ sub xfer_src_cb { if ($header->{'srv_encrypt'}) { push @filters, Amanda::Xfer::Filter::Process->new( - [ $header->{'srv_encrypt'}, $header->{'srv_decrypt_opt'} ], 0, 1); + [ $header->{'srv_encrypt'}, $header->{'srv_decrypt_opt'} ], 0); + $header->{'encrypted'} = 0; + $header->{'srv_encrypt'} = ''; + $header->{'srv_decrypt_opt'} = ''; + $header->{'clnt_encrypt'} = ''; + $header->{'clnt_decrypt_opt'} = ''; + $header->{'encrypt_suffix'} = 'N'; } elsif ($header->{'clnt_encrypt'}) { - push @filters, - Amanda::Xfer::Filter::Process->new( - [ $header->{'clnt_encrypt'}, $header->{'clnt_decrypt_opt'} ], 0, 1); + if (!$self->{'their_features'}->has($Amanda::Feature::fe_amrecover_receive_unfiltered)) { + push @filters, + Amanda::Xfer::Filter::Process->new( + [ $header->{'clnt_encrypt'}, + $header->{'clnt_decrypt_opt'} ], 0); + $header->{'encrypted'} = 0; + $header->{'srv_encrypt'} = ''; + $header->{'srv_decrypt_opt'} = ''; + $header->{'clnt_encrypt'} = ''; + $header->{'clnt_decrypt_opt'} = ''; + $header->{'encrypt_suffix'} = 'N'; + } else { + debug("Not decrypting client encrypted stream"); + } } else { $self->sendmessage("could not decrypt encrypted dump: no program specified"); return $self->quit(); } - $header->{'encrypted'} = 0; - $header->{'srv_encrypt'} = ''; - $header->{'srv_decrypt_opt'} = ''; - $header->{'clnt_encrypt'} = ''; - $header->{'clnt_decrypt_opt'} = ''; - $header->{'encrypt_suffix'} = 'N'; } if ($header->{'compressed'}) { @@ -522,22 +553,38 @@ sub xfer_src_cb { # TODO: this assumes that srvcompprog takes "-d" to decrypt push @filters, Amanda::Xfer::Filter::Process->new( - [ $header->{'srvcompprog'}, "-d" ], 0, 1); + [ $header->{'srvcompprog'}, "-d" ], 0); + # adjust the header + $header->{'compressed'} = 0; + $header->{'uncompress_cmd'} = ''; + $header->{'srvcompprog'} = ''; } elsif ($header->{'clntcompprog'}) { - # TODO: this assumes that clntcompprog takes "-d" to decrypt - push @filters, - Amanda::Xfer::Filter::Process->new( - [ $header->{'clntcompprog'}, "-d" ], 0, 1); + if (!$self->{'their_features'}->has($Amanda::Feature::fe_amrecover_receive_unfiltered)) { + # TODO: this assumes that clntcompprog takes "-d" to decrypt + push @filters, + Amanda::Xfer::Filter::Process->new( + [ $header->{'clntcompprog'}, "-d" ], 0); + # adjust the header + $header->{'compressed'} = 0; + $header->{'uncompress_cmd'} = ''; + $header->{'clntcompprog'} = ''; + } } else { - push @filters, - Amanda::Xfer::Filter::Process->new( - [ $Amanda::Constants::UNCOMPRESS_PATH, - $Amanda::Constants::UNCOMPRESS_OPT ], 0, 1); + my $dle = $header->get_dle(); + if ($dle && + (!$self->{'their_features'}->has($Amanda::Feature::fe_amrecover_receive_unfiltered) || + $dle->{'compress'} == $Amanda::Config::COMP_SERVER_FAST || + $dle->{'compress'} == $Amanda::Config::COMP_SERVER_BEST)) { + push @filters, + Amanda::Xfer::Filter::Process->new( + [ $Amanda::Constants::UNCOMPRESS_PATH, + $Amanda::Constants::UNCOMPRESS_OPT ], 0); + # adjust the header + $header->{'compressed'} = 0; + $header->{'uncompress_cmd'} = ''; + } } - # adjust the header - $header->{'compressed'} = 0; - $header->{'uncompress_cmd'} = ''; } $self->{'xfer_filters'} = [ @filters ]; @@ -557,6 +604,10 @@ sub send_header { # filter out some things the remote might not be able to process if (!$self->{'their_features'}->has($Amanda::Feature::fe_amrecover_dle_in_header)) { $header->{'dle_str'} = undef; + } else { + $header->{'dle_str'} = + Amanda::Disklist::clean_dle_str_for_client($header->{'dle_str'}, + Amanda::Feature::am_features($self->{'their_features'})); } if (!$self->{'their_features'}->has($Amanda::Feature::fe_amrecover_origsize_in_header)) { $header->{'orig_size'} = 0; @@ -627,13 +678,50 @@ sub start_xfer { } } + # start reading all filter stderr + foreach my $filter (@{$self->{'xfer_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 = ""; + $self->{'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 $self->{'all_filter'}->{$src}; + $src->remove(); + POSIX::close($fd); + if (!%{$self->{'all_filter'}} and $self->{'fetch_done'}) { + Amanda::MainLoop::quit(); + } + } else { + $buffer .= $b; + if ($b eq "\n") { + my $line = $buffer; + #print STDERR "filter stderr: $line"; + chomp $line; + $self->sendmessage("filter stderr: $line"); + debug("filter stderr: $line"); + $buffer = ""; + } + } + }); + } + # create and start the transfer $self->{'xfer'} = Amanda::Xfer->new([ $self->{'xfer_src'}, @{$self->{'xfer_filters'}}, $xfer_dest, ]); - $self->{'xfer'}->start(sub { $self->handle_xmsg(@_); }); + my $size = 0; + $size = $self->{'dump'}->{'bytes'} if exists $self->{'dump'}->{'bytes'}; + $self->{'xfer'}->start(sub { $self->handle_xmsg(@_); }, 0, $size); debug("started xfer; datapath=$self->{datapath}"); # send the data-path response, if we have a datapath @@ -702,13 +790,26 @@ sub quit { if ($self->{'clerk'}) { $self->{'clerk'}->quit(finished_cb => sub { my ($err) = @_; + $self->{'chg'}->quit() if defined $self->{'chg'}; if ($err) { # it's *way* too late to report this to amrecover now! warning("while quitting clerk: $err"); } - Amanda::MainLoop::quit(); + $self->quit1(); }); } else { + $self->{'scan'}->quit() if defined $self->{'scan'}; + $self->{'chg'}->quit() if defined $self->{'chg'}; + $self->quit1(); + } + +} + +sub quit1 { + my $self = shift; + + $self->{'fetch_done'} = 1; + if (!%{$self->{'all_filter'}}) { Amanda::MainLoop::quit(); } }