+ my $src = $self->{'src'} = {};
+
+ # put together a clerk, which of course requires a changer, scan,
+ # interactivity, and feedback
+ my $chg = Amanda::Changer->new();
+ return $self->failure("Error opening source changer: $chg")
+ if $chg->isa('Amanda::Changer::Error');
+ $src->{'chg'} = $chg;
+
+ $src->{'seen_labels'} = {};
+
+ $src->{'interactivity'} = main::Interactivity->new();
+
+ $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, $self->{'src_write_timestamp'}, $level, undef);
+ }