};
};
-##
-# Clerk Feedback class
-
-package main::Feedback;
-use Amanda::Recovery::Clerk;
-use Amanda::Util qw( weaken_ref );
-use base 'Amanda::Recovery::Clerk::Feedback';
-
-sub new {
- my $class = shift;
- my %params = @_;
-
- my $self = bless {
- clientservice => $params{'clientservice'}
- }, $class;
-
- # (weak ref here to eliminate reference loop)
- weaken_ref($self->{'clientservice'});
-
- return $self;
-}
-
-sub part_notif {
- my $self = shift;
-
- my ($label, $filenum, $hdr) = @_;
- $self->{'clientservice'}->sendmessage("restoring part $hdr->{'partnum'} " .
- "from '$label' file $filenum");
-}
-
-sub holding_notif {
- my $self = shift;
-
- my ($holding_file, $hdr) = @_;
- $self->{'clientservice'}->sendmessage("restoring from holding " .
- "file $holding_file");
-}
-
##
# ClientService class
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
$self->{'their_features'} = Amanda::Feature::Set->from_string($command->{'FEATURES'});
}
- if ($command->{'CONFIG'}) {
- config_init($CONFIG_INIT_EXPLICIT_NAME, $command->{'CONFIG'});
- my ($cfgerr_level, @cfgerr_errors) = config_errors();
- if ($cfgerr_level >= $CFGERR_ERRORS) {
- die "configuration errors; aborting connection";
- }
- Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER_PREFERRED);
+ # load the configuration
+ if (!$command->{'CONFIG'}) {
+ die "no CONFIG line given";
+ }
+ config_init($CONFIG_INIT_EXPLICIT_NAME, $command->{'CONFIG'});
+ my ($cfgerr_level, @cfgerr_errors) = config_errors();
+ if ($cfgerr_level >= $CFGERR_ERRORS) {
+ die "configuration errors; aborting connection";
+ }
+ Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER_PREFERRED);
+
+ # and the disklist
+ my $diskfile = Amanda::Config::config_dir_relative(getconf($CNF_DISKFILE));
+ $cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
+ if ($cfgerr_level >= $CFGERR_ERRORS) {
+ die "Errors processing disklist";
}
$self->setup_data_stream();
$self->{'command'}{'HOST'},
$disk,
$self->{'command'}{'DATESTAMP'},
- undef); # amidxtaped protocol does not provide a level (!?)
+ undef, # amidxtaped protocol does not provide a level (!?)
+ undef); # amidxtaped protocol does not provide a write timestamp
}
# figure out if this is a holding-disk recovery
$scan->{'scan_conf'}->{'notfound'} = Amanda::Recovery::Scan::SCAN_ASK;
$self->{'clerk'} = Amanda::Recovery::Clerk->new(
- feedback => main::Feedback->new($chg, undef),
+ # note that we don't have any use for clerk_notif's, so we don't pass
+ # a feedback object
scan => $scan);
if ($is_holding) {
return $self->quit();
}
+ # check that the request-limit for this DLE allows this recovery. because
+ # of the bass-ackward way that amrecover specifies the dump to us, we can't
+ # check the results until *after* the plan was created.
+ my $dump = $plan->{'dumps'}->[0];
+ my $dle = Amanda::Disklist::get_disk($dump->{'hostname'}, $dump->{'diskname'});
+ my $recovery_limit;
+ if ($dle && dumptype_seen($dle->{'config'}, $DUMPTYPE_RECOVERY_LIMIT)) {
+ debug("using DLE recovery limit");
+ $recovery_limit = dumptype_getconf($dle->{'config'}, $DUMPTYPE_RECOVERY_LIMIT);
+ } elsif (getconf_seen($CNF_RECOVERY_LIMIT)) {
+ debug("using global recovery limit as default");
+ $recovery_limit = getconf($CNF_RECOVERY_LIMIT);
+ }
+ 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 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) {
+ # handle same-host with a case-insensitive string compare, not match_host
+ if (lc($peer) eq lc($dump->{'hostname'})) {
+ $matched = 1;
+ last;
+ }
+ } else {
+ # otherwise use match_host to allow match expressions
+ if (match_host($rl, $peer)) {
+ $matched = 1;
+ last;
+ }
+ }
+ }
+ if (!$matched) {
+ warning("authenticated peer '$peer' did not match recovery-limit ".
+ "config; rejecting request");
+ $self->sendmessage("No matching dumps found");
+ return $self->quit();
+ }
+ }
+
if (!$self->{'their_features'}->has($Amanda::Feature::fe_recover_splits)) {
# if we have greater than one volume, we may need to prompt for a new
# volume in mid-recovery. Sadly, we have no way to inform the client of
if ($header->{'srv_encrypt'}) {
push @filters,
Amanda::Xfer::Filter::Process->new(
- [ $header->{'srv_encrypt'}, $header->{'srv_decrypt_opt'} ], 0);
+ [ $header->{'srv_encrypt'}, $header->{'srv_decrypt_opt'} ], 0, 1);
} elsif ($header->{'clnt_encrypt'}) {
push @filters,
Amanda::Xfer::Filter::Process->new(
- [ $header->{'clnt_encrypt'}, $header->{'clnt_decrypt_opt'} ], 0);
+ [ $header->{'clnt_encrypt'}, $header->{'clnt_decrypt_opt'} ], 0, 1);
} else {
$self->sendmessage("could not decrypt encrypted dump: no program specified");
return $self->quit();
# TODO: this assumes that srvcompprog takes "-d" to decrypt
push @filters,
Amanda::Xfer::Filter::Process->new(
- [ $header->{'srvcompprog'}, "-d" ], 0);
+ [ $header->{'srvcompprog'}, "-d" ], 0, 1);
} elsif ($header->{'clntcompprog'}) {
# TODO: this assumes that clntcompprog takes "-d" to decrypt
push @filters,
Amanda::Xfer::Filter::Process->new(
- [ $header->{'clntcompprog'}, "-d" ], 0);
+ [ $header->{'clntcompprog'}, "-d" ], 0, 1);
} else {
push @filters,
Amanda::Xfer::Filter::Process->new(
[ $Amanda::Constants::UNCOMPRESS_PATH,
- $Amanda::Constants::UNCOMPRESS_OPT ], 0);
+ $Amanda::Constants::UNCOMPRESS_OPT ], 0, 1);
}
# adjust the header