+
+ # if these dumps were on the holding disk, then we're done
+ next if $logfile eq 'holding';
+
+ # re-read the logfile to extract dump-level info that's not captured by
+ # search_logfile
+ my $logh = Amanda::Logfile::open_logfile("$logfile_dir/$logfile");
+ die "logfile '$logfile' not found" unless $logh;
+ while (my ($type, $prog, $str) = Amanda::Logfile::get_logline($logh)) {
+ next unless $prog == $P_TAPER;
+ my $status;
+ if ($type == $L_DONE) {
+ $status = 'OK';
+ } elsif ($type == $L_PARTIAL) {
+ $status = 'PARTIAL';
+ } elsif ($type == $L_FAIL) {
+ $status = 'FAIL';
+ } elsif ($type == $L_SUCCESS) {
+ $status = "OK";
+ } else {
+ next;
+ }
+
+ # now extract the appropriate info; luckily these log lines have the same
+ # format, more or less
+ my ($hostname, $diskname, $dump_timestamp, $nparts, $level, $secs, $kb, $message);
+ ($hostname, $str) = Amanda::Util::skip_quoted_string($str);
+ ($diskname, $str) = Amanda::Util::skip_quoted_string($str);
+ ($dump_timestamp, $str) = Amanda::Util::skip_quoted_string($str);
+ if ($status ne 'FAIL' and $type != $L_SUCCESS) { # nparts is not in SUCCESS lines
+ ($nparts, $str) = Amanda::Util::skip_quoted_string($str);
+ } else {
+ $nparts = 0;
+ }
+ ($level, $str) = Amanda::Util::skip_quoted_string($str);
+ if ($status ne 'FAIL') {
+ my $s = $str;
+ ($secs, $kb, $str) = ($str =~ /^\[sec ([-0-9.]+) kb (\d+).*\] ?(.*)$/)
+ or die("'$s'");
+ $secs = 0.1 if ($secs <= 0);
+ }
+ if ($status ne 'OK') {
+ $message = $str;
+ } else {
+ $message = '';
+ }
+
+ $hostname = Amanda::Util::unquote_string($hostname);
+ $diskname = Amanda::Util::unquote_string($diskname);
+ $message = Amanda::Util::unquote_string($message) if $message;
+
+ # filter against dump criteria
+ next if ($params{'dump_timestamp_match'}
+ and !match_datestamp($params{'dump_timestamp_match'}, zeropad($dump_timestamp)));
+ next if (%dump_timestamps_hash
+ and !exists($dump_timestamps_hash{zeropad($dump_timestamp)}));
+
+ next if ($params{'hostname_match'}
+ and !match_host($params{'hostname_match'}, $hostname));
+ next if (%hostnames_hash
+ and !exists($hostnames_hash{$hostname}));
+
+ next if ($params{'diskname_match'}
+ and !match_disk($params{'diskname_match'}, $diskname));
+ next if (%disknames_hash
+ and !exists($disknames_hash{$diskname}));
+
+ next if (%levels_hash
+ and !exists($levels_hash{$level}));
+ # get_dumps filters on status
+
+ if ($params{'dumpspecs'}) {
+ my $ok = 0;
+ for my $ds (@{$params{'dumpspecs'}}) {
+ # (the "". are for SWIG's benefit - SWIGged functions don't like
+ # strings generated by SWIG. Long story.)
+ next if (defined $ds->{'host'}
+ and !match_host("".$ds->{'host'}, $hostname));
+ next if (defined $ds->{'disk'}
+ and !match_disk("".$ds->{'disk'}, $diskname));
+ next if (defined $ds->{'datestamp'}
+ and !match_datestamp("".$ds->{'datestamp'}, $dump_timestamp));
+ next if (defined $ds->{'level'}
+ and !match_level("".$ds->{'level'}, $level));
+ next if (defined $ds->{'write_timestamp'}
+ and !match_datestamp("".$ds->{'write_timestamp'}, $write_timestamp));
+ $ok = 1;
+ last;
+ }
+ next unless $ok;
+ }
+
+ my $dumpkey = join("\0", $hostname, $diskname, $write_timestamp,
+ $level, zeropad($dump_timestamp));
+ my $dump = $dumps{$dumpkey};
+ if (!defined $dump) {
+ # this will happen when a dump has no parts - a FAILed dump.
+ $dump = $dumps{$dumpkey} = {
+ dump_timestamp => zeropad($dump_timestamp),
+ write_timestamp => $write_timestamp,
+ hostname => $hostname,
+ diskname => $diskname,
+ level => $level+0,
+ orig_kb => undef,
+ status => "FAILED",
+ # message set below
+ nparts => $nparts, # hopefully 0?
+ # kb set below
+ # sec set below
+ };
+ }
+
+ $dump->{'message'} = $message;
+ if ($status eq 'FAIL') {
+ $dump->{'kb'} = 0;
+ $dump->{'sec'} = 0.0;
+ } else {
+ $dump->{'kb'} = $kb+0;
+ $dump->{'sec'} = $secs+0.0;
+ }
+ }
+ Amanda::Logfile::close_logfile($logh);