+ $src->{'scan'} = Amanda::Recovery::Scan->new(
+ chg => $src->{'chg'},
+ interactivity => $src->{'interactivity'});
+
+ $src->{'clerk'} = Amanda::Recovery::Clerk->new(
+ changer => $src->{'chg'},
+ feedback => $self,
+ scan => $src->{'scan'});
+ $self->{'cleanup'}{'quit_clerk'} = 1;
+
+ # translate "latest" into the most recent timestamp that wasn't created by amvault
+ if (defined $self->{'src_write_timestamp'} && $self->{'src_write_timestamp'} eq "latest") {
+ my $ts = $self->{'src_write_timestamp'} =
+ Amanda::DB::Catalog::get_latest_write_timestamp(types => ['amdump', 'amflush']);
+ return $self->failure("No dumps found")
+ unless defined $ts;
+
+ $self->vlog("Using latest timestamp: $ts");
+ }
+
+ # we need to combine fulls_only, src_write_timestamp, and the set
+ # of dumpspecs. If they contradict one another, then drop the
+ # non-matching dumpspec with a warning.
+ my @dumpspecs;
+ if ($self->{'opt_dumpspecs'}) {
+ my $level = $self->{'fulls_only'}? "0" : undef;
+ my $swt = $self->{'src_write_timestamp'};
+
+ # filter and adjust the dumpspecs
+ for my $ds (@{$self->{'opt_dumpspecs'}}) {
+ my $ds_host = $ds->{'host'};
+ my $ds_disk = $ds->{'disk'};
+ my $ds_datestamp = $ds->{'datestamp'};
+ my $ds_level = $ds->{'level'};
+ my $ds_write_timestamp = $ds->{'write_timestamp'};
+
+ if ($swt) {
+ # it's impossible for parse_dumpspecs to set write_timestamp,
+ # so there's no risk of overlap here
+ $ds_write_timestamp = $swt;
+ }
+
+ if (defined $level) {
+ if (defined $ds_level &&
+ !match_level($ds_level, $level)) {
+ $self->vlog("WARNING: dumpspec " . $ds->format() .
+ " specifies non-full dumps, contradicting --fulls-only;" .
+ " ignoring dumpspec");
+ next;
+ }
+ $ds_level = $level;
+ }
+
+ # create a new dumpspec, since dumpspecs are immutable
+ push @dumpspecs, Amanda::Cmdline::dumpspec_t->new(
+ $ds_host, $ds_disk, $ds_datestamp, $ds_level, $ds_write_timestamp);
+ }
+ } else {
+ # convert the timestamp and level to a dumpspec
+ my $level = $self->{'fulls_only'}? "0" : undef;
+ push @dumpspecs, Amanda::Cmdline::dumpspec_t->new(
+ undef, undef, undef, $level, $self->{'src_write_timestamp'});
+ }
+
+ # if we ignored all of the dumpspecs and didn't create any, then dump
+ # nothing. We do *not* want the wildcard "vault it all!" behavior.
+ if (!@dumpspecs) {
+ return $self->failure("No dumps to vault");
+ }
+
+ if (!$self->{'opt_dry_run'}) {
+ # summarize the requested dumps
+ my $request;
+ if ($self->{'src_write_timestamp'}) {
+ $request = "vaulting from volumes written " . $self->{'src_write_timestamp'};
+ } else {
+ $request = "vaulting";
+ }
+ if ($self->{'opt_dumpspecs'}) {
+ $request .= " dumps matching dumpspecs:";
+ }
+ if ($self->{'fulls_only'}) {
+ $request .= " (fulls only)";
+ }
+ log_add($L_INFO, $request);
+
+ # and log the dumpspecs if they were given
+ if ($self->{'opt_dumpspecs'}) {
+ for my $ds (@{$self->{'opt_dumpspecs'}}) {
+ log_add($L_INFO, " " . $ds->format());
+ }
+ }
+ }
+
+ Amanda::Recovery::Planner::make_plan(
+ dumpspecs => \@dumpspecs,
+ changer => $src->{'chg'},
+ plan_cb => sub { $self->plan_cb(@_) });