Imported Upstream version 3.3.2
[debian/amanda] / server-src / amstatus.pl
1 #!@PERL@
2 #
3
4 # Run perl.
5 eval '(exit $?0)' && eval 'exec @PERL@ -S $0 ${1+"$@"}'
6          & eval 'exec @PERL@ -S $0 $argv:q'
7                 if 0;
8
9 use warnings;
10 use lib '@amperldir@';
11 use Time::Local;
12 use Text::ParseWords;
13 use Amanda::Util;
14 use Amanda::Process;
15 use Getopt::Long;
16
17 delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV', 'PATH'};
18 $ENV{'PATH'} = "/bin:/usr/bin:/usr/sbin:/sbin";       # force known path
19
20 $confdir="@CONFIG_DIR@";
21 $prefix='@prefix@';
22 $prefix=$prefix;                # avoid warnings about possible typo
23 $exec_prefix="@exec_prefix@";
24 $exec_prefix=$exec_prefix;      # ditto
25 $sbindir="@sbindir@";
26
27 my $Amanda_process = Amanda::Process->new(0);
28 $Amanda_process->load_ps_table();
29
30 #$STATUS_STRANGE =  2;
31 $STATUS_FAILED  =  4;
32 $STATUS_MISSING =  8;
33 $STATUS_TAPE    = 16;
34 $exit_status    =  0;
35
36 my $opt_summary;
37 my $opt_stats;
38 my $opt_dumping;
39 my $opt_waitdumping;
40 my $opt_waittaper;
41 my $opt_dumpingtape;
42 my $opt_writingtape;
43 my $opt_finished;
44 my $opt_failed;
45 my $opt_estimate;
46 my $opt_gestimate;
47 my $opt_date;
48 my $opt_config;
49 my $opt_file;
50 my $opt_locale_independent_date_format;
51
52 sub usage() {
53         print "amstatus [--file amdump_file]\n";
54         print "         [--summary] [--dumping] [--waitdumping] [--waittaper]\n";
55         print "         [--dumpingtape] [--writingtape] [--finished] [--failed]\n";
56         print "         [--estimate] [--gestimate] [--stats] [--date]\n";
57         print "         [--locale-independent-date-format]\n";
58         print "         [--config] <config>\n";
59         exit 0;
60 }
61
62 Getopt::Long::Configure(qw{ bundling });
63 GetOptions(
64     'summary'                        => \$opt_summary,
65     'stats|statistics'               => \$opt_stats,
66     'dumping|d'                      => \$opt_dumping,
67     'waitdumping|wdumping'           => \$opt_waitdumping,
68     'waittaper|wtaper'               => \$opt_waittaper,
69     'dumpingtape|dtape'              => \$opt_dumpingtape,
70     'writingtape|wtape'              => \$opt_writingtape,
71     'finished'                       => \$opt_finished,
72     'failed|error'                   => \$opt_failed,
73     'estimate'                       => \$opt_estimate,
74     'gestimate|gettingestimate'      => \$opt_gestimate,
75     'date'                           => \$opt_date,
76     'config|c:s'                     => \$opt_config,
77     'file:s'                         => \$opt_file,
78     'locale-independent-date-format' => \$opt_locale_independent_date_format,
79     ) or usage();
80
81
82 if( defined $opt_config ) {
83         $conf = $opt_config;
84 }
85 else {
86         if($#ARGV == 0 ) {
87                 $conf=$ARGV[0];
88         }
89         else {
90                 &usage();
91         }
92 }
93
94 #untaint user input $ARGV[0]
95
96 if ($conf =~ /^([\w.-]+)$/) {          # $1 is untainted
97    $conf = $1;
98 } else {
99     die "filename '$conf' has invalid characters.\n";
100 }
101
102 if ( ! -e "$confdir/$conf" ) {
103     print "Configuration directory '$confdir/$conf' doesn't exist\n";
104     exit 1;
105 }
106 if ( ! -d "$confdir/$conf" ) {
107     print "Configuration directory '$confdir/$conf' is not a directory\n";
108     exit 1;
109  }
110
111
112 $pwd = `pwd`;
113 chomp $pwd;
114 chdir "$confdir/$conf";
115
116 $logdir=`$sbindir/amgetconf logdir`;
117 exit 1 if $? != 0;
118 chomp $logdir;
119 $errfile="$logdir/amdump";
120
121 $nb_options = defined( $opt_summary ) +
122                                   defined( $opt_stats ) +
123                                   defined( $opt_dumping ) +
124                                   defined( $opt_waitdumping ) +
125                                   defined( $opt_waittaper ) +
126                                   defined( $opt_dumpingtape ) +
127                                   defined( $opt_writingtape ) +
128                                   defined( $opt_finished ) +
129                                   defined( $opt_estimate ) +
130                                   defined( $opt_gestimate ) +
131                                   defined( $opt_failed );
132
133 if($nb_options == 0 ) {
134         $opt_summary     = 1;
135         $opt_stats       = 1; 
136         $opt_dumping     = 1;
137         $opt_waitdumping = 1;
138         $opt_waittaper   = 1;
139         $opt_dumpingtape = 1;
140         $opt_writingtape = 1;
141         $opt_finished    = 1;
142         $opt_failed      = 1;
143         $opt_gestimate   = 1;
144         $opt_estimate    = 1;
145 }
146
147 $unit=`$sbindir/amgetconf displayunit`;
148 chomp($unit);
149 $unit =~ tr/A-Z/a-z/;
150 $unitdivisor=1;
151 if($unit eq 'k') {
152   $unitdivisor = 1;
153 }
154 elsif($unit eq 'm') {
155   $unitdivisor = 1024;
156 }
157 elsif($unit eq 'g') {
158   $unitdivisor = 1024*1024;
159 }
160 elsif($unit eq 't') {
161   $unitdivisor = 1024*1024*1024;
162 }
163 else {
164   $unit = 'k';
165   $unitdivisor = 1;
166 }
167
168
169 my $dead_run = 0;
170 if( defined $opt_file) {
171         if( $opt_file =~ m,^/, ) {
172                 $errfile = $opt_file;
173         } else {
174                 $errfile = "$pwd/$opt_file";
175                 $errfile = "$logdir/$opt_file" if ( ! (-f $errfile ));
176         }
177 }
178 else {
179         $errfile="$logdir/amflush" if(! (-f $errfile));
180         if (! -f $errfile) {
181                 if (-f "$logdir/amflush.1" && -f "$logdir/amdump.1" &&
182                     -M "$logdir/amflush.1"  < -M "$logdir/amdump.1") {
183                         $errfile="$logdir/amflush.1";
184                 } else {
185                         $errfile="$logdir/amdump.1";
186                 }
187                 $dead_run = 1;
188         }
189 }
190
191 open(AMDUMP,"<$errfile") || die("$errfile: $!");
192 print "Using $errfile\n";
193
194 my $taper_status_file;
195
196 $start_degraded_mode = 0;
197
198 $label = "";                                    # -w fodder
199 $origsize = 0;                                  # -w fodder
200 $idle_dumpers = 0;
201 $status_driver = "";
202 $status_taper = "Searching for a new tape";
203 $estimate_done = 0;
204 $holding_space = 0;
205 $start_time = 0;
206 @dumpers_active = ();
207 $nb_tape = 0;
208 $ntpartition{$nb_tape} = 0;
209 $ntsize{$nb_tape} = 0;
210 $ntesize{$nb_tape} = 0;
211 $tape_size = 0;
212 $driver_finished = 0;
213 $generating_schedule = 0;
214
215 while($lineX = <AMDUMP>) {
216         chomp $lineX;
217         $lineX =~ s/[:\s]+$//g; #remove separator at end of line
218         next if $lineX eq "";
219         @line = &quotewords('[:\s]+', 0, $lineX);
220         next if !defined $line[0];
221
222         if($line[0] eq "amdump" || $line[0] eq "amflush") {
223                 if ($line[1] eq "start" && $line[2] eq "at") {
224                         $datestr = $lineX;
225                         $datestr =~ s/.*start at //g;
226                         if (!defined $opt_locale_independent_date_format) {
227                                 print "From " . $datestr . "\n";
228                         }
229                 } elsif($line[1] eq "datestamp") {
230                         $gdatestamp = $line[2];
231                         if(!defined $datestamp{$gdatestamp}) {
232                                 $datestamp{$gdatestamp} = 1;
233                                 push @datestamp, $gdatestamp;
234                         }
235                 } elsif($line[1] eq "starttime") {
236                         $starttime=&set_starttime($line[2]);
237                 } elsif($line[1] eq "starttime-locale-independent") {
238                         if (defined $opt_locale_independent_date_format) {
239                                 printf "From " . $line[2] . " " . $line[3] . ":" . $line[4] . ":" . $line[5] . " " . $line[6] . "\n";
240                         }
241                 }
242                 if($line[0] eq "amflush") {
243                         $estimate_done=1;
244                 }
245         } elsif($line[0] eq "planner") {
246                 if($line[1] eq "timestamp") {
247                         $gdatestamp = $line[2];
248                         if(!defined $datestamp{$gdatestamp}) {
249                                 $datestamp{$gdatestamp} = 1;
250                                 push @datestamp, $gdatestamp;
251                         }
252                 }
253                 elsif($line[1] eq "FAILED") {
254                         #2:host 3:disk 4:datestamp 5:level 6:errmsg
255                         $host=$line[2];
256                         $partition=$line[3];
257                         $datestamp=$line[4];
258                         $hostpart=&make_hostpart($host,$partition,$datestamp);
259                         $dump_started{$hostpart}=-1;
260                         $level{$hostpart}=$line[5];
261                         $error{$hostpart}="planner: " . $line[6];
262         } elsif($line[1] eq "time") {
263                 if($line[3] eq "got") {
264                                 if($line[4] eq "result") {
265                                         $host = $line[7];
266                                         $partition = $line[9];
267                                         $hostpart=&make_hostpart($host,$partition,$gdatestamp);
268                                         $estimate{$hostpart}=1;
269                                         $level{$hostpart}=$line[10];
270                                         $line[12] =~ /(\d+)K/;
271                                         $esize{$hostpart}=$1 / $unitdivisor;
272                                         $partialestimate{$hostpart}=0;
273                                         $getest{$hostpart} = "";
274                                 } elsif($line[4] eq "partial") {
275                                         $host = $line[8];
276                                         $partition = $line[10];
277                                         $hostpart=&make_hostpart($host,$partition,$gdatestamp);
278                                         $level1 = $line[11];
279                                         $line[13] =~ /(-?\d+)K/;
280                                         $size1 = $1;
281                                         $level2 = $line[14];
282                                         $line[16] =~ /(-?\d+)K/;
283                                         $size2 = $1;
284                                         $level3 = $line[17];
285                                         $line[19] =~ /(-?\d+)K/;
286                                         $size3 = $1;
287                                         if($size1 > 0 || $size2 > 0 || $size3 > 0) {
288                                                 $estimate{$hostpart}=1;
289                                                 $level{$hostpart}=$line[11];
290                                                 $esize{$hostpart}=$size1 / $unitdivisor;
291                                                 $partialestimate{$hostpart}=1;
292                                                 if($size1 > 0) { $getest{$hostpart} =~ s/:$level1://; }
293                                                 if($size2 > 0) { $getest{$hostpart} =~ s/:$level2://; }
294                                                 if($size3 > 0) { $getest{$hostpart} =~ s/:$level3://; }
295                                                 if($getest{$hostpart} eq "") {$partialestimate{$hostpart}=0;}
296                                         }
297                                 }
298                         } elsif($line[3] eq "getting" &&
299                                           $line[4] eq "estimates" &&
300                                           $line[5] eq "took") {
301                                 $estimate_done=1;
302                         }
303                 }
304         } elsif($line[0] eq "setup_estimate") {
305                 $host = $line[1];
306                 $partition = $line[2];
307                 $hostpart=&make_hostpart($host,$partition,$gdatestamp);
308                 $estimate{$hostpart}=0;
309                 $level{$hostpart}=0;
310                 $degr_level{$hostpart}=-1;
311                 $esize{$hostpart}=0;
312                 $dump_started{$hostpart}=0;
313                 $dump_finished{$hostpart}=0;
314                 $taper_started{$hostpart}=0;
315                 $taper_finished{$hostpart}=0;
316                 $partialestimate{$hostpart}=0;
317                 $error{$hostpart}="";
318                 if($line[7] eq "last_level") {
319                         $getest{$hostpart}="";
320                         $level1 = $line[15];
321                         $level2 = $line[17];
322                         $level3 = $line[19];
323                         if($level1 != -1) { $getest{$hostpart} .= ":$level1:" };
324                         if($level2 != -1) { $getest{$hostpart} .= ":$level2:" };
325                         if($level3 != -1) { $getest{$hostpart} .= ":$level3:" };
326                 }
327         } elsif($line[0] eq "GENERATING" &&
328                                 $line[1] eq "SCHEDULE") {
329                 $generating_schedule=1;
330         } elsif($line[0] eq "--------") {
331                 if ($generating_schedule == 1) {
332                         $generating_schedule = 2;
333                 } elsif ($generating_schedule == 2) {
334                         $generating_schedule = 3;
335                 }
336         } elsif($line[0] eq "DUMP") {
337                 if($generating_schedule == 2 ) {
338                         $host = $line[1];
339                         $partition = $line[3];
340                         $datestamp = $line[4];
341                         $hostpart=&make_hostpart($host,$partition,$datestamp);
342                         $level{$hostpart}=$line[6];
343                         $esize=$line[14];       #compressed size
344                         $esize=32 if $esize<32;
345                         $esize{$hostpart}=$esize / $unitdivisor;
346                         if(!defined($line[25])) {
347                                 $degr_level{$hostpart}=-1;
348                         } else {
349                                 $degr_level{$hostpart}=$line[17];
350                                 $esize=$line[25];       #compressed size
351                                 $esize=32 if $esize<32;
352                                 $degr_size{$hostpart}=$esize / $unitdivisor;
353                         }
354                 }
355         } elsif($line[0] eq "FLUSH") {
356                 $host = $line[1];
357                 $partition = $line[2];
358                 $datestamp = $line[3];
359                 $level = $line[4];
360                 $holding_file = $line[5];
361                 $hostpart=&make_hostpart($host,$partition,$datestamp);
362                 $flush{$hostpart}=0;
363                 $dump_finished{$hostpart}=0;
364                 $holding_file{$hostpart}=$holding_file;
365                 $level{$hostpart}=$level;
366         } elsif($line[0] eq "driver") {
367                 if($line[1] eq "pid") {
368                         $pid = $line[2];
369                         if (! $Amanda_process->process_alive($pid, "driver")) {
370                                 $dead_run = 1;
371                         }
372                 }
373                 elsif($line[1] eq "start" && $line[2] eq "time") {
374                         $start_time=$line[3];
375                         $current_time=$line[3];
376                         $dumpers_active[0]=0;
377                         $dumpers_held[0]={};
378                         $dumpers_active=0;
379                 }
380                 elsif($line[1] eq "tape" && $line[2] eq "size") {
381                         $lineX =~ /^driver: start time (\S+)/;
382                         $tape_size = $line[3] / $unitdivisor;
383                 }
384                 elsif($line[1] eq "adding" &&
385                            $line[2] eq "holding" &&
386                                 $line[3] eq "disk") {
387                         $holding_space += $line[8];
388                 }
389                 elsif($line[1] eq "send-cmd" && $line[2] eq "time") {
390                         #print "send-cmd: " , $line[5] . " " . $line[6] . " " . $line[7] . "\n" if defined $line[5] && defined $line[6] && defined $line[7];
391                         $current_time = $line[3];
392                         if($line[5] =~ /dumper\d*/) {
393                                 $dumper = $line[5];
394                                 if($line[6] eq "PORT-DUMP") {
395                                         #7:handle 8:port 9:host 10:amfeatures 11:disk 12:device 13:level ...
396                                         $host = $line[9];
397                                         $partition = $line[11];
398                                         $hostpart=&make_hostpart($host,$partition,$gdatestamp);
399                                         $serial=$line[7];
400                                         $dump_started{$hostpart}=1;
401                                         $dump_time{$hostpart}=$current_time;
402                                         $dump_finished{$hostpart}=0;
403                                         if(     $level{$hostpart} != $line[13] &&
404                                            $degr_level{$hostpart} == $line[13]) {
405                                                 $level{$hostpart}=$degr_level{$hostpart};
406                                                 $esize{$hostpart}=$degr_size{$hostpart};
407                                         }
408                                         if(! defined($busy_time{$dumper})) {
409                                                 $busy_time{$dumper}=0;
410                                         }
411                                         $running_dumper{$dumper} = $hostpart;
412                                         $error{$hostpart}="";
413                                         $taper_error{$hostpart}="";
414                                         $size{$hostpart} = 0;
415                                         $dumpers_active++;
416                                         if(! defined($dumpers_active[$dumpers_active])) {
417                                                 $dumpers_active[$dumpers_active]=0;
418                                         }
419                                         if(! defined($dumpers_held[$dumpers_active])) {
420                                                 $dumpers_held[$dumpers_active]={};
421                                         }
422                                 }
423                         }
424                         elsif($line[5] =~ /chunker\d*/) {
425                                 if($line[6] eq "PORT-WRITE") {
426                                         $host=$line[9];
427                                         $partition=$line[11];
428                                         $hostpart=&make_hostpart($host,$partition,$gdatestamp);
429                                         $serial=$line[7];
430                                         $serial{$serial}=$hostpart;
431                                         $holding_file{$hostpart}=$line[8];
432                                         #$chunk_started{$hostpart}=1;
433                                         $chunk_time{$hostpart}=$current_time;
434                                         #$chunk_finished{$hostpart}=0;
435                                         $size{$hostpart} = 0;
436                                 }
437                                 elsif($line[6] eq "CONTINUE") {
438                                         #7:handle 8:filename 9:chunksize 10:use
439                                         $serial=$line[7];
440                                         $hostpart=$serial{$serial};
441                                         if($hostpart ne "") {
442                                                 $dump_roomq{$hostpart}=undef;
443                                                 $error{$hostpart}="";
444                                         }
445                                 }
446                         }
447                         elsif($line[5] =~ /taper/) {
448                                 if($line[6] eq "START-TAPER") {
449                                         #7:name 8:timestamp
450                                         $gdatestamp=$line[8];
451                                         if(!defined $datestamp{$gdatestamp}) {
452                                                 $datestamp{$gdatestamp} = 1;
453                                                 push @datestamp, $gdatestamp;
454                                         }
455                                         $status_taper = "Searching for a new tape";
456                                 }
457                                 elsif($line[6] eq "NEW-TAPE") {
458                                         #7:name 8:handle
459                                         $status_taper = "Searching for a new tape";
460                                 }
461                                 elsif($line[6] eq "NO-NEW-TAPE") {
462                                         #7:name 8:handle 9:errmsg
463                                         $serial=$line[8];
464                                         $error=$line[9];
465                                         $status_taper = $error;
466                                 }
467                                 elsif($line[6] eq "FILE-WRITE") {
468                                         #7:name 8:handle 9:filename 10:host 11:disk 12:level 13:datestamp 14:splitsize
469                                         $serial=$line[8];
470                                         $host=$line[10];
471                                         $partition=$line[11];
472                                         $level=$line[12];
473                                         $ldatestamp=$line[13];
474                                         $status_taper = "Writing $host:$partition";
475                                         if(!defined $datestamp{$ldatestamp}) {
476                                                 $datestamp{$ldatestamp} = 1;
477                                                 push @datestamp, $ldatestamp;
478                                         }
479                                         $hostpart=&make_hostpart($host,$partition,$ldatestamp);
480                                         $serial{$serial}=$hostpart;
481                                         if(!defined $level{$hostpart}) {
482                                                 $level{$hostpart} = $level;
483                                         }
484                                         $taper_started{$hostpart}=1;
485                                         $taper_finished{$hostpart}=0;
486                                         $taper_time{$hostpart}=$current_time;
487                                         $taper_error{$hostpart}="";
488                                         $ntchunk_size = 0;
489                                 }
490                                 elsif($line[6] eq "PORT-WRITE") {
491                                         #7:name 8:handle 9:host 10:disk 11:level 12:datestamp 13:splitsize 14:diskbuffer 15:fallback_splitsize
492                                         $serial=$line[8];
493                                         $host=$line[9];
494                                         $partition=$line[10];
495                                         $level=$line[11];
496                                         $ldatestamp=$line[12];
497                                         $status_taper = "Writing $host:$partition";
498                                         $hostpart=&make_hostpart($host,$partition,$ldatestamp);
499                                         $serial{$serial}=$hostpart;
500                                         $taper_started{$hostpart}=1;
501                                         $taper_finished{$hostpart}=0;
502                                         $taper_time{$hostpart}=$current_time;
503                                         $taper_error{$hostpart}="";
504                                         $size{$hostpart} = 0;
505                                         $ntchunk_size = 0;
506                                 }
507                         }
508                 }
509                 elsif($line[1] eq "result" && $line[2] eq "time") {
510                         #print "result: " , $line[5] . " " . $line[6] . " " . $line[7] . "\n" if defined $line[5] && defined $line[6] && defined $line[7];
511                         $current_time = $line[3];
512                         if($line[5] =~ /dumper\d+/) {
513                                 if($line[6] eq "FAILED" || $line[6] eq "TRY-AGAIN") {
514                                         #7:handle 8:message
515                                         $serial = $line[7];
516                                         $error = $line[8];
517                                         $hostpart=$serial{$serial};
518                                         if ($taper_started{$hostpart} == 1) {
519                                                 $dump_finished{$hostpart}=-1;
520                                         } else {
521                                                 $dump_finished{$hostpart}=-3;
522                                         }
523                                         $busy_time{$line[5]}+=($current_time-$dump_time{$hostpart});
524                                         $running_dumper{$line[5]} = "0";
525                                         $dump_time{$hostpart}=$current_time;
526                                         if (!$taper_error{$hostpart}) {
527                                                 $error{$hostpart}="dumper: $error";
528                                         }
529                                         $dumpers_active--;
530
531                                 }
532                                 elsif($line[6] eq "DONE") {
533                                         #7:handle 8:origsize 9:size ...
534                                         $serial=$line[7];
535                                         $origsize=$line[8] / $unitdivisor;
536                                         $outputsize=$line[9] / $unitdivisor;
537                                         $hostpart=$serial{$serial};
538                                         $size{$hostpart}=$outputsize;
539                                         $dump_finished{$hostpart}=1;
540                                         $busy_time{$line[5]}+=($current_time-$dump_time{$hostpart});
541                                         $running_dumper{$line[5]} = "0";
542                                         $dump_time{$hostpart}=$current_time;
543                                         $error{$hostpart}="";
544                                         $dumpers_active--;
545                                 }
546                                 elsif($line[6] eq "ABORT-FINISHED") {
547                                         #7:handle
548                                         $serial=$line[7];
549                                         $hostpart=$serial{$serial};
550                                         $dump_started{$hostpart}=0;
551                                         if ($taper_started{$hostpart} == 1) {
552                                                 $dump_finished{$hostpart}=-1;
553                                         } else {
554                                                 $dump_finished{$hostpart}=-3;
555                                         }
556                                         $busy_time{$line[5]}+=($current_time-$dump_time{$hostpart});
557                                         $running_dumper{$line[5]} = "0";
558                                         $dump_time{$hostpart}=$current_time;
559                                         $error{$hostpart}="dumper: (aborted)";
560                                         $dumpers_active--;
561                                 }
562                         }
563                         elsif($line[5] =~ /chunker\d+/) {
564                                 if($line[6] eq "DONE" || $line[6] eq "PARTIAL") {
565                                         #7:handle 8:size
566                                         $serial=$line[7];
567                                         $outputsize=$line[8] / $unitdivisor;
568                                         $hostpart=$serial{$serial};
569                                         $size{$hostpart}=$outputsize;
570                                         if ($line[6] eq "DONE") {
571                                                 $dump_finished{$hostpart}=1;
572                                         } else {
573                                                 $dump_finished{$hostpart}=-3;
574                                         }
575                                         $busy_time{$line[5]}+=($current_time-$chunk_time{$hostpart});
576                                         $running_dumper{$line[5]} = "0";
577                                         $chunk_time{$hostpart}=$current_time;
578                                         if ($line[6] eq "PARTIAL") {
579                                                 $partial{$hostpart} = 1;
580                                         }
581                                         else {
582                                                 $partial{$hostpart} = 0;
583                                                 $error{$hostpart}="";
584                                         }
585                                 }
586                                 elsif($line[6] eq "FAILED") {
587                                         $serial=$line[7];
588                                         $hostpart=$serial{$serial};
589                                         $dump_finished{$hostpart}=-1;
590                                         $busy_time{$line[5]}+=($current_time-$chunk_time{$hostpart});
591                                         $running_dumper{$line[5]} = "0";
592                                         $chunk_time{$hostpart}=$current_time;
593                                         $error{$hostpart}="chunker: " .$line[8] if $error{$hostpart} eq "";
594                                 }
595                                 elsif($line[6] eq "RQ-MORE-DISK") {
596                                         #7:handle
597                                         $serial=$line[7];
598                                         $hostpart=$serial{$serial};
599                                         $dump_roomq{$hostpart}=1;
600                                         $error{$hostpart}="(waiting for holding disk space)";
601                                 }
602                         }
603                         elsif($line[5] eq "taper") {
604                                 if($line[6] eq "DONE" || $line[6] eq "PARTIAL") {
605                                         #DONE:    7:handle 8:label 9:filenum 10:errstr
606                                         #PARTIAL: 7:handle 8:INPUT-* 9:TAPE-* 10:errstr 11:INPUT-MSG 12:TAPE-MSG
607                                         $serial=$line[7];
608
609                                         $status_taper = "Idle";
610                                         $hostpart=$serial{$serial};
611                                         $line[10] =~ /sec (\S+) (kb|bytes) (\d+) kps/;
612                                         if ($2 eq 'kb') {
613                                                 $size=$3 / $unitdivisor;
614                                         } else {
615                                                 $size=$3 / ( $unitdivisor * 1024);
616                                         }
617                                         $taper_finished{$hostpart}=1;
618                                         $busy_time{"taper"}+=($current_time-$taper_time{$hostpart});
619                                         $taper_time{$hostpart}=$current_time;
620                                         if(!defined $size{$hostpart}) {
621                                                 $size{$hostpart}=$size;
622                                         }
623                                         $ntpartition{$nb_tape}++;
624                                         $ntsize{$nb_tape} += $size{$hostpart} - $ntchunk_size;
625                                         if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
626                                                 $ntesize{$nb_tape} += $esize{$hostpart} - $ntchunk_size;
627                                         }
628                                         else {
629                                                 $ntesize{$nb_tape} += $size{$hostpart} - $ntchunk_size;
630                                         }
631                                         if ($line[6] eq "PARTIAL") {
632                                                 $partial{$hostpart} = 1;
633                                                 if ($line[9] eq "TAPE-ERROR") {
634                                                         $error{$hostpart} = "taper: $line[12]";
635                                                         $taper_error{$hostpart} = "taper: $line[12]";
636                                                 }
637                                         }
638                                         else {
639                                                 $partial{$hostpart} = 0;
640                                         }
641                                         if ($ntchunk_size > 0) {
642                                                 $ntchunk{$nb_tape}++;
643                                         }
644                                         undef $taper_status_file;
645                                 }
646                                 elsif($line[6] eq "PARTDONE") {
647                                         #7:handle 8:label 9:filenum 10:ksize 11:errstr
648                                         $serial=$line[7];
649                                         $hostpart=$serial{$serial};
650                                         #$line[11] =~ /.*kb (\d*) kps/;
651                                         #$size=$1 / $unitdivisor;
652                                         $size=$line[10] / $unitdivisor;
653                                         $tapedsize{$hostpart} += $size;
654                                         $ntchunk{$nb_tape}++;
655                                         $ntsize{$nb_tape} += $size;
656                                         $ntesize{$nb_tape} += $size;
657                                         $ntchunk_size += $size;
658                                 }
659                                 elsif($line[6] eq "REQUEST-NEW-TAPE") {
660                                         #7:serial
661                                         $serial=$line[7];
662                                         $old_status_taper = $status_taper;
663                                         $status_taper = "Asking for a new tape";
664                                         $hostpart=$serial{$serial};
665                                         if (defined $hostpart) {
666                                                 $olderror{$hostpart} = $error{$hostpart};
667                                                 $error{$hostpart} = "waiting for a new tape";
668                                         }
669                                 }
670                                 elsif($line[6] eq "NEW-TAPE") {
671                                         #7:serial #8:label
672                                         $serial=$line[7];
673                                         $status_taper = $old_status_taper;
674                                         $hostpart=$serial{$serial};
675                                         if (defined $hostpart) {
676                                                 $error{$hostpart} = $olderror{$hostpart};
677                                         }
678                                 }
679                                 elsif($line[6] eq "TAPER-OK") {
680                                         #7:name #8:label
681                                         $status_taper = "Idle";
682                                 }
683                                 elsif($line[6] eq "TAPE-ERROR") {
684                                         #7:name 8:errstr
685                                         $error=$line[8];
686                                         $status_taper = $error;
687                                         $exit_status |= $STATUS_TAPE;
688                                         undef $taper_status_file;
689                                 }
690                                 elsif($line[6] eq "FAILED") {
691                                         #7:handle 8:INPUT- 9:TAPE- 10:input_message 11:tape_message
692                                    $serial=$line[7];
693                                         $hostpart=$serial{$serial};
694                                         if(defined $hostpart) {
695                                                 if($line[9] eq "TAPE-ERROR") {
696                                                         $error=$line[11];
697                                                         $taper_finished{$hostpart} = -2;
698                                                         $status_taper = $error;
699                                                 }
700                                                 else {
701                                                         $error=$line[10];
702                                                         $taper_finished{$hostpart} = -1;
703                                                         $status_taper = "Idle";
704                                                 }
705                                                 $busy_time{"taper"}+=($current_time-$taper_time{$hostpart});
706                                                 $taper_time{$hostpart}=$current_time;
707                                                 $error{$hostpart}="$error";
708                                         }
709                                         undef $taper_status_file;
710                                 }
711                         }
712                 }
713                 elsif($line[1] eq "finished-cmd" && $line[2] eq "time") {
714                         $current_time=$line[3];
715                         if($line[4] =~ /dumper\d+/) {
716                         }
717                 }
718                 elsif($line[1] eq "dump" && $line[2] eq "failed") {
719                         #3:handle 4: 5: 6:"too many dumper retry"
720                         $serial=$line[3];
721                         $hostpart=$serial{$serial};
722                         $dump_started{$hostpart}=-1;
723                         $dump_finished{$hostpart}=-2;
724                         $error{$hostpart} .= "(" . $line[6] . ")";
725                 }
726                 elsif($line[1] eq "tape" && $line[2] eq "failed") {
727                         #3:handle 4: 5: 6:"too many dumper retry"
728                         $serial=$line[3];
729                         $hostpart=$serial{$serial};
730                         $taper_started{$hostpart}=-1;
731                         $taper_finished{$hostpart}=-2;
732                         $error{$hostpart} .= "(" . $line[6] . ")";
733                 }
734                 elsif($line[1] eq "state" && $line[2] eq "time") {
735                         #3:time 4:"free" 5:"kps" 6:free 7:"space" 8:space 9:"taper" 10:taper 11:"idle-dumpers" 12:idle-dumpers 13:"qlen" 14:"tapeq" 15:tapeq 16:"runq" 17:runq 18:"roomq" 19:roomq 20:"wakeup" 21:wakeup 22:"driver-idle" 23:driver-idle
736                         $current_time=$line[3];
737                         $idle_dumpers=$line[12];
738
739                         $free{"kps"} = $line[6];
740                         $free{"space"} = $line[8];
741                         $qlen{"tapeq"} = $line[15];
742                         $qlen{"runq"} = $line[17];
743                         $qlen{"roomq"} = $line[19];
744
745                         if(defined($dumpers_active)) {
746                                 if($status_driver ne "") {
747                                         $dumpers_active[$dumpers_active_prev]
748                                                 +=$current_time-$state_time_prev;
749                                         $dumpers_held[$dumpers_active_prev]{$status_driver}
750                                                 +=$current_time-$state_time_prev;
751                                 }
752                                 $state_time_prev=$current_time;
753                                 $dumpers_active_prev=$dumpers_active;
754                                 $status_driver=$line[23];
755                                 if(! defined($dumpers_held[$dumpers_active]{$status_driver})) {
756                                         $dumpers_held[$dumpers_active]{$status_driver}=0;
757                                 }
758                         }
759                 }
760            elsif($line[1] eq "FINISHED") {
761                         $driver_finished = 1;
762                 }
763         }
764         elsif($line[0] eq "dump") {
765                 if($line[1] eq "of" &&
766                         $line[2] eq "driver" &&
767                         $line[3] eq "schedule" &&
768                         $line[4] eq "after" &&
769                         $line[5] eq "start" &&
770                         $line[6] eq "degraded" &&
771                         $line[7] eq "mode") {
772                         $start_degraded_mode=1;
773                 }
774         }
775         elsif($line[0] eq "taper") {
776                 if($line[1] eq "wrote") {
777                         #1:"wrote" 2:"label" 3:label
778                         $nb_tape++;
779                         $label = $line[3];
780                         $ntlabel{$nb_tape} = $label;
781                         $ntpartition{$nb_tape} = 0;
782                         $ntsize{$nb_tape} = 0;
783                         $ntesize{$nb_tape} = 0;
784                 }
785                 elsif($line[1] eq "status" && $line[2] eq "file") {
786                         #1:"status" #2:"file:" #3:hostname #4:diskname #5:filename
787                         $taper_status_file = $line[5];
788                 }
789         }
790         elsif($line[0] eq "splitting" &&
791                          $line[1] eq "chunk" &&
792                          $line[2] eq "that" &&
793                          $line[3] eq "started" &&
794                          $line[4] eq "at" &&
795                          $line[6] eq "after") {
796                 $line[7] =~ /(\d*)kb/;
797                 $size = $1;
798                 $ntchunk{$nb_tape}++;
799                 $ntsize{$nb_tape} += $size / $unitdivisor;
800                 $ntesize{$nb_tape} += $size / $unitdivisor;
801                 $ntchunk_size += $size / $unitdivisor;
802         }
803         else {
804                 #print "Ignoring: $lineX\n";
805         }
806 }
807
808 close(AMDUMP);
809
810 if(defined $current_time) {
811         for ($d = 0; $d < $#dumpers_active; $d++) {
812                 $the_dumper = "dumper$d";
813                 if(defined($running_dumper{$the_dumper}) &&
814                    $running_dumper{$the_dumper} ne "0") {
815                         $busy_time{$the_dumper}+=($current_time-$dump_time{$running_dumper{$the_dumper}});
816                 }
817         }
818 }
819
820 print "\n";
821
822 $nb_partition = 0;
823
824 $epartition = 0;
825 $estsize = 0;
826 $fpartition = 0;
827 $fsize = 0;
828 $wpartition = 0;
829 $wsize = 0;
830
831 $flpartition = 0;
832 $flsize = 0;
833 $wfpartition = 0;
834 $wfsize = 0;
835
836 $dtpartition = 0;
837 $dtesize = 0;
838 $dupartition = 0;
839 $dusize = 0;
840 $duesize = 0;
841 $dpartition = 0;
842 $dsize = 0;
843 $desize = 0;
844
845 $twpartition = 0;
846 $twsize = 0;
847 $twesize = 0;
848 $tapartition = 0;
849 $tasize = 0;
850 $taesize = 0;
851 $tfpartition = 0;
852 $tfsize = 0;
853 $tfesize = 0;
854 $tpartition = 0;
855 $tsize = 0;
856 $tesize = 0;
857
858 $maxnamelength = 10;
859 foreach $host (sort @hosts) {
860         foreach $partition (sort @$host) {
861                 foreach $datestamp (sort @datestamp) {
862                         $hostpart=&make_hostpart($host,$partition,$datestamp);
863                         next if(!defined $estimate{$hostpart} && !defined $flush{$hostpart});
864                         if(length("$host:$partition") > $maxnamelength) {
865                                 $maxnamelength = length("$host:$partition");
866                         }
867                 }
868         }
869 }
870
871 foreach $host (sort @hosts) {
872         foreach $partition (sort @$host) {
873            $qpartition = Amanda::Util::quote_string($partition);
874            foreach $datestamp (sort @datestamp) {
875                         $hostpart=&make_hostpart($host,$partition,$datestamp);
876                         next if(!defined $estimate{$hostpart} && !defined $flush{$hostpart});
877                         $nb_partition++;
878                         if( (!defined $size{$hostpart} || $size{$hostpart} == 0) &&
879                                  defined $holding_file{$hostpart}) {
880                                 $size{$hostpart} = &dump_size($holding_file{$hostpart}) / (1024 * $unitdivisor);
881                         }
882                         $in_flush=0;
883                         if($estimate_done != 1 && !defined $flush{$hostpart}) {
884                                 if(defined $estimate{$hostpart}) {
885                                         if($estimate{$hostpart} != 1) {
886                                                 if( defined $opt_gestimate ||
887                                                          defined $opt_failed && $dead_run != 0) {
888                                                         printf "%8s ", $datestamp if defined $opt_date;
889                                                         printf "%-${maxnamelength}s", "$host:$qpartition";
890                                                         print "             ";
891                                                         if ($dead_run) {
892                                                                 print " failed: killed while";
893                                                                 $exit_status |= $STATUS_FAILED;
894                                                         }
895                                                         print " getting estimate\n";
896                                                 }
897                                         }
898                                         else {
899                                                 if(defined $opt_estimate ||
900                                                         (defined $opt_gestimate && $partialestimate{$hostpart} == 1) ||
901                                                         (defined $opt_failed && $dead_run != 0 && $partialestimate{$hostpart} == 1)) {
902                                                         printf "%8s ", $datestamp if defined $opt_date;
903                                                         printf "%-${maxnamelength}s", "$host:$qpartition";
904                                                         printf "%2d ",  $level{$hostpart};
905                                                         printf "%9d$unit", $esize{$hostpart};
906                                                         if($partialestimate{$hostpart} == 1) {
907                                                                 if ($dead_run) {
908                                                                         print " failed: killed while";
909                                                                         $exit_status |= $STATUS_FAILED;
910                                                                 }
911                                                                 print " partial";
912                                                         }
913                                                         print " estimate done\n";
914                                                 }
915                                                 $epartition++;
916                                                 $estsize += $esize{$hostpart};
917                                         }
918                                 }
919                         }
920                         else {
921                                 if(defined $estimate{$hostpart}) {
922                                         if($estimate{$hostpart} == 1) {
923                                                 $epartition++;
924                                                 $estsize += $esize{$hostpart};
925                                         }
926                                         elsif (!defined $dump_started{$hostpart} || $dump_started{$hostpart} == 0) {
927                                                 if( defined $opt_failed) {
928                                                         printf "%8s ", $datestamp if defined $opt_date;
929                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
930                                                         printf "           no estimate\n";
931                                                 }
932                                                 $exit_status |= $STATUS_FAILED;
933                                                 $fpartition++;
934                                                 $fsize+=$esize{$hostpart};
935                                         }
936                                 }
937                                 else {
938                                         $flpartition++;
939                                         $flsize += $size{$hostpart};
940                                         $in_flush=1;
941                                 }
942                                 if(defined $taper_started{$hostpart} &&
943                                                 $taper_started{$hostpart}==1 &&
944                                                 $dump_finished{$hostpart}!=-3) {
945                                         if(defined $dump_started{$hostpart} &&
946                                                 $dump_started{$hostpart} == 1 &&
947                                                         $dump_finished{$hostpart} == -1) {
948                                                 if(defined $opt_failed) {
949                                                         printf "%8s ", $datestamp if defined $opt_date;
950                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
951                                                         printf "%9d$unit", $esize{$hostpart};
952                                                         print " dump to tape failed: " . $error{$hostpart};
953                                                         print "\n";
954                                                 }
955                                                 $exit_status |= $STATUS_FAILED;
956                                                 $fpartition++;
957                                                 $fsize+=$esize{$hostpart};
958                                         } elsif(defined $dump_started{$hostpart} &&
959                                                 $dump_started{$hostpart} == 1 &&
960                                                         $dump_finished{$hostpart} == 0 &&
961                                                         $taper_started{$hostpart} == 1) {
962                                                 if( defined $opt_dumpingtape ||
963                                                          defined $opt_failed && $dead_run != 0) {
964                                                         printf "%8s ", $datestamp if defined $opt_date;
965                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
966                                                         printf "%9d$unit", $esize{$hostpart};
967                                                         if ($dead_run) {
968                                                                 print " failed: killed while";
969                                                                 $exit_status |= $STATUS_FAILED;
970                                                         }
971                                                         print " dumping to tape";
972                                                         $size = $tapedsize{$hostpart};
973                                                         if ($taper_status_file && -f $taper_status_file &&
974                                                                 open FF, "<$taper_status_file") {
975                                                                 $line = <FF>;
976                                                                 if (defined $line) {
977                                                                         chomp $line;
978                                                                         $value = $line / ($unitdivisor * 1024);
979                                                                         if ($value) {
980                                                                                 $size = $value if (!defined($size) || $value > $size);
981                                                                         }
982                                                                 }
983                                                                 close FF;
984                                                         }
985                                                         if(defined($size)) {
986                                                                 printf " (%d$unit done (%0.2f%%))", $size, 100.0 * $size/$esize{$hostpart};
987                                                                 $dtsize += $size;
988                                                         }
989                                                         if( defined $starttime ) {
990                                                                 print " (", &showtime($taper_time{$hostpart}), ")";
991                                                         }
992                                                         print "\n";
993                                                 }
994                                                 $dtpartition++;
995                                                 $dtesize += $esize{$hostpart};
996                                         }
997                                         elsif($taper_finished{$hostpart} == 0) {
998                                                 if( defined $opt_writingtape ||
999                                                          defined $opt_failed && $dead_run != 0) {
1000                                                         printf "%8s ", $datestamp if defined $opt_date;
1001                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1002                                                         printf "%9d$unit", $size{$hostpart};
1003                                                         if ($dead_run) {
1004                                                                 print " failed: killed while";
1005                                                                 $exit_status |= $STATUS_FAILED;
1006                                                         }
1007                                                         if($in_flush == 0) {
1008                                                                 print " dump done," if defined $dump_finished{$hostpart} && $dump_finished{$hostpart} == 1;
1009                                                                 print " writing to tape";
1010                                                         }
1011                                                         else {
1012                                                                 print " flushing to tape";
1013                                                         }
1014                                                         $size = $tapedsize{$hostpart};
1015                                                         if ($taper_status_file &&  -f $taper_status_file &&
1016                                                                 open FF, "<$taper_status_file") {
1017                                                                 $line = <FF>;
1018                                                                 if (defined $line) {
1019                                                                         chomp $line;
1020                                                                         $value = $line / ($unitdivisor * 1024);
1021                                                                         if ($value) {
1022                                                                                 $size = $value if (!defined($size) || $value > $size);
1023                                                                         }
1024                                                                 }
1025                                                                 close FF;
1026                                                         }
1027                                                         if(defined($size)) {
1028                                                                 printf " (%d$unit done (%0.2f%%))", $size, 100.0 * $size/$size{$hostpart};
1029                                                         }
1030                                                         if( defined $starttime ) {
1031                                                                 print " (", &showtime($taper_time{$hostpart}), ")";
1032                                                         }
1033                                                         print ", ", $error{$hostpart} if (defined($error{$hostpart}) &&
1034                                                                                                                                             $error{$hostpart} ne "");
1035                                                         print "\n";
1036                                                 }
1037                                                 $tapartition++;
1038                                                 $tasize += $size{$hostpart};
1039                                                 if(defined $esize{$hostpart}) {
1040                                                         $taesize += $esize{$hostpart};
1041                                                 }
1042                                                 else {
1043                                                         $taesize += $size{$hostpart};
1044                                                 }
1045                                                 if (defined $dump_finished{$hostpart} && $dump_finished{$hostpart} == 1) {
1046                                                         $dpartition++;
1047                                                         $dsize += $size{$hostpart};
1048                                                         if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
1049                                                                 $desize += $esize{$hostpart};
1050                                                         } else {
1051                                                                 $desize += $size{$hostpart};
1052                                                         }
1053                                                 }
1054                                         }
1055                                         elsif($taper_finished{$hostpart} < 0) {
1056
1057                                                 if(defined $size{$hostpart}) {
1058                                                         $xsize = $size{$hostpart};
1059                                                 }
1060                                                 elsif(defined $esize{$hostpart}) {
1061                                                         $xsize = $esize{$hostpart};
1062                                                 }
1063                                                 else {
1064                                                         $xsize = 0;
1065                                                 }
1066
1067                                                 if(defined $esize{$hostpart}) {
1068                                                         $exsize += $esize{$hostpart};
1069                                                 }
1070                                                 else {
1071                                                         $exsize += $xsize;
1072                                                 }
1073
1074                                                 if( defined $opt_failed  ||
1075                                                          (defined $opt_waittaper && ($taper_finished{$hostpart} == -1))) {
1076                                                         printf "%8s ", $datestamp if defined $opt_date;
1077                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1078                                                         printf "%9d$unit", $xsize;
1079                                                     print " dump done," if defined $dump_finished{$hostpart} && $dump_finished{$hostpart} == 1;
1080                                                         if($in_flush == 0) {
1081                                                                 print " failed to tape";
1082                                                         }
1083                                                         else {
1084                                                                 print " failed to flush";
1085                                                         }
1086                                                         print ": ",$error{$hostpart} if defined $error{$hostpart};
1087
1088                                                         print " (will retry)" unless $taper_finished{$hostpart} < -1;
1089                                                         if( defined $starttime ) {
1090                                                                 print " (", &showtime($taper_time{$hostpart}), ")";
1091                                                         }
1092                                                         print "\n";
1093                                                 }
1094                                                 $exit_status |= $STATUS_TAPE;
1095
1096                                                 $tfpartition++;
1097                                                 $tfsize += $xsize;
1098                                                 $tfesize += $exsize;
1099
1100                                                 if($in_flush == 0) {
1101                                                         $twpartition++;
1102                                                         $twsize += $xsize;
1103                                                         $twesize += $exsize;
1104                                                 }
1105                                                 else {
1106                                                         $wfpartition++;
1107                                                         $wfsize += $xsize;
1108                                                 }
1109                                                 if (defined $dump_finished{$hostpart} && $dump_finished{$hostpart} == 1) {
1110                                                         $dpartition++;
1111                                                         $dsize += $size{$hostpart};
1112                                                         if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
1113                                                                 $desize += $esize{$hostpart};
1114                                                         } else {
1115                                                                 $desize += $size{$hostpart};
1116                                                         }
1117                                                 }
1118                                         }
1119                                         elsif($taper_finished{$hostpart} == 1) {
1120                                                 if( defined $opt_finished ) {
1121                                                         printf "%8s ", $datestamp if defined $opt_date;
1122                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1123                                                         printf "%9d$unit", $size{$hostpart};
1124                                                         if($in_flush == 0) {
1125                                                                 print " finished";
1126                                                         }
1127                                                         else {
1128                                                                 print " flushed";
1129                                                         }
1130                                                         if( defined $starttime ) {
1131                                                                 print " (", &showtime($taper_time{$hostpart}), ")";
1132                                                         }
1133                                                         if(defined $partial{$hostpart} && $partial{$hostpart} == 1) {
1134                                                                 print ", PARTIAL";
1135                                                                 $exit_status |= $STATUS_FAILED;
1136                                                         }
1137                                                         print "\n";
1138                                                 }
1139                                                 if (defined $dump_finished{$hostpart} && $dump_finished{$hostpart} == 1) {
1140                                                         $dpartition++;
1141                                                         $dsize += $size{$hostpart};
1142                                                         if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
1143                                                                 $desize += $esize{$hostpart};
1144                                                         } else {
1145                                                                 $desize += $size{$hostpart};
1146                                                         }
1147                                                 }
1148                                                 $tpartition++;
1149                                                 $tsize += $size{$hostpart};
1150                                                 if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
1151                                                         $tesize += $esize{$hostpart};
1152                                                 }
1153                                                 else {
1154                                                         $tesize += $size{$hostpart};
1155                                                 }
1156                                         }
1157                                         else {
1158                                                 printf "%8s ", $datestamp if defined $opt_date;
1159                                                 printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1160                                                 print " unknown state TAPER\n";
1161                                         }
1162                                 }
1163                                 elsif(defined $dump_started{$hostpart}) {
1164                                         if($dump_started{$hostpart} == -1) {
1165                                                 if( defined $opt_failed ) {
1166                                                         printf "%8s ", $datestamp if defined $opt_date;
1167                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1168                                                         printf "failed: " . $error{$hostpart} . "\n";
1169                                                 }
1170                                                 $exit_status |= $STATUS_FAILED;
1171
1172                                                 $fpartition++;
1173                                                 $fsize+=$esize{$hostpart};
1174                                         }
1175                                         elsif($dump_started{$hostpart} == 0) {
1176                                                 if($estimate{$hostpart} == 1) {
1177                                                         if( defined $opt_waitdumping ) {
1178                                                                 printf "%8s ", $datestamp if defined $opt_date;
1179                                                                 printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1180                                                                 printf "%9d$unit", $esize{$hostpart};
1181                                                                 if ($dead_run) {
1182                                                                         print " failed: process terminated while";
1183                                                                         $exit_status |= $STATUS_FAILED;
1184                                                                 }
1185                                                                 print " waiting for dumping $error{$hostpart}\n";
1186                                                         }
1187                                                         if($driver_finished == 1) {
1188                                                                 $exit_status |= $STATUS_MISSING;
1189                                                         }
1190                                                         $wpartition++;
1191                                                         $wsize += $esize{$hostpart};
1192                                                 }
1193                                         }
1194                                         elsif($dump_started{$hostpart} == 1 &&
1195                                                         ($dump_finished{$hostpart} == -1 ||
1196                                                     $dump_finished{$hostpart} == -3)) {
1197                                                 if( defined $opt_failed ) {
1198                                                         printf "%8s ", $datestamp if defined $opt_date;
1199                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1200                                                         print "backup failed: ", $error{$hostpart};
1201                                                         if( defined $starttime ) {
1202                                                                 print " (", &showtime($dump_time{$hostpart}), ")";
1203                                                         }
1204                                                         print "\n";
1205                                                 }
1206                                                 $exit_status |= $STATUS_FAILED;
1207                                                 $fpartition++;
1208                                                 $fsize+=$esize{$hostpart};
1209                                         }
1210                                         elsif($dump_started{$hostpart} == 1 &&
1211                                                         $dump_finished{$hostpart} == 0) {
1212                                                 if( defined $opt_dumping ||
1213                                                          defined $opt_failed && $dead_run != 0) {
1214                                                         printf "%8s ", $datestamp if defined $opt_date;
1215                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1216                                                         printf "%9d$unit", $esize{$hostpart};
1217                                                         if ($dead_run) {
1218                                                                 print " failed: killed while";
1219                                                                 $exit_status |= $STATUS_FAILED;
1220                                                         }
1221                                                         printf " dumping %8d$unit", $size{$hostpart};
1222                                                         if($size{$hostpart} != 0) {
1223                                                                 printf " (%6.2f%%)", (100.0*$size{$hostpart})/$esize{$hostpart};
1224                                                         }
1225                                                         if( defined $starttime ) {
1226                                                                 print " (", &showtime($dump_time{$hostpart}), ")";
1227                                                         }
1228                                                         if(defined $dump_roomq{$hostpart}) {
1229                                                                 print " " . $error{$hostpart};
1230                                                         }
1231                                                         print "\n";
1232                                                 }
1233                                                 $dupartition++;
1234                                                 $dusize += $size{$hostpart};
1235                                                 $duesize += $esize{$hostpart};
1236                                         }
1237                                         elsif($dump_finished{$hostpart} == 1 &&
1238                                                         $taper_started{$hostpart} != 1) {
1239                                                 if( defined $opt_waittaper ) {
1240                                                         printf "%8s ", $datestamp if defined $opt_date;
1241                                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1242                                                         printf "%9d$unit", $size{$hostpart};
1243                                                         print " dump done";
1244                                                         if( defined $starttime ) {
1245                                                                 print " (", &showtime($dump_time{$hostpart}), ")";
1246                                                         }
1247                                                         print ",";
1248                                                         if ($dead_run) {
1249                                                                 print " process terminated while";
1250                                                         }
1251                                                         print " waiting for writing to tape";
1252                                                         if(defined $partial{$hostpart} && $partial{$hostpart} == 1) {
1253                                                                 print ", PARTIAL";
1254                                                                 $exit_status |= $STATUS_FAILED;
1255                                                         }
1256                                                         print "\n";
1257                                                 }
1258                                                 $dpartition++;
1259                                                 $dsize += $size{$hostpart};
1260                                                 $desize += $esize{$hostpart};
1261                                                 $twpartition++;
1262                                                 $twsize += $size{$hostpart};
1263                                                 $twesize += $esize{$hostpart};
1264                                         }
1265                                         else {
1266                                                 printf "%8s ", $datestamp if defined $opt_date;
1267                                                 printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1268                                                 print " unknown state DUMPER\n";
1269                                         }
1270                                 }
1271                                 elsif(defined $flush{$hostpart}) {
1272                                         if( defined $opt_waittaper ) {
1273                                                 printf "%8s ", $datestamp if defined $opt_date;
1274                                                 printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1275                                                 printf "%9d$unit", $size{$hostpart};
1276                                                 if ($dead_run) {
1277                                                         print " process terminated while";
1278                                                 }
1279                                                 print " waiting to flush";
1280                                                 if(defined $partial{$hostpart} && $partial{$hostpart} == 1) {
1281                                                         print ", PARTIAL";
1282                                                         $exit_status |= $STATUS_FAILED;
1283                                                 }
1284                                                 print "\n";
1285                                         }
1286                                         $wfpartition++;
1287                                         $wfsize += $size{$hostpart};
1288                                 }
1289                                 elsif(defined $level{$hostpart}) {
1290                                         printf "%8s ", $datestamp if defined $opt_date;
1291                                         printf "%-${maxnamelength}s%2d ", "$host:$qpartition", $level{$hostpart};
1292                                         print " unknown state\n";
1293                                 }
1294                         }
1295                 }
1296         }
1297 }
1298
1299 if (defined $opt_summary) {
1300         print "\n";
1301         print  "SUMMARY          part      real  estimated\n";
1302         print  "                           size       size\n";
1303         printf "partition       : %3d\n", $nb_partition;
1304         printf "estimated       : %3d %20d$unit\n", $epartition , $estsize;
1305         printf "flush           : %3d %9d$unit\n", $flpartition, $flsize;
1306         printf "failed          : %3d %20d$unit           (%6.2f%%)\n",
1307                 $fpartition , $fsize,
1308                 $estsize ? ($fsize * 1.0 / $estsize) * 100 : 0.0;
1309         printf "wait for dumping: %3d %20d$unit           (%6.2f%%)\n",
1310                 $wpartition , $wsize,
1311                 $estsize ? ($wsize * 1.0 / $estsize) * 100 : 0.0;
1312         if(defined($dtsize)) {
1313                 printf "dumping to tape : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1314                         $dtpartition, $dtsize, $dtesize,
1315                         $dtsize ? ($dtsize * 1.0 / $dtesize) * 100 : 0.0,
1316                         $estsize ? ($dtesize * 1.0 / $estsize) * 100 : 0.0;
1317         } else {
1318                 printf "dumping to tape : %3d %20d$unit           (%6.2f%%)\n",
1319                         $dtpartition, $dtesize,
1320                         $estsize ? ($dtesize * 1.0 / $estsize) * 100 : 0.0;
1321         }
1322         printf "dumping         : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1323                 $dupartition, $dusize, $duesize,
1324                 $duesize ? ($dusize * 1.0 / $duesize) * 100 : 0.0,
1325                 $estsize ? ($dusize * 1.0 / $estsize) * 100 : 0.0;
1326         printf "dumped          : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1327                 $dpartition , $dsize , $desize,
1328                 $desize ? ($dsize * 1.0 / $desize) * 100 : 0.0,
1329                 $estsize ? ($dsize * 1.0 / $estsize) * 100 : 0.0;
1330         printf "wait for writing: %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1331                 $twpartition, $twsize, $twesize,
1332                 $twesize ? ($twsize * 1.0 / $twesize) * 100 : 0.0,
1333                 $estsize ? ($twsize * 1.0 / $estsize) * 100 : 0.0;
1334         printf "wait to flush   : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1335                 $wfpartition, $wfsize, $wfsize, 100, 0;
1336         printf "writing to tape : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1337                 $tapartition, $tasize, $taesize,
1338                 $taesize ? ($tasize * 1.0 / $taesize) * 100 : 0.0,
1339                 $estsize ? ($tasize * 1.0 / $estsize) * 100 : 0.0;
1340         printf "failed to tape  : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1341                 $tfpartition, $tfsize, $tfesize,
1342                 $tfesize ? ($tfsize * 1.0 / $tfesize) * 100 : 0.0,
1343                 $estsize ? ($tfsize * 1.0 / $estsize) * 100 : 0.0;
1344         printf "taped           : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
1345                 $tpartition , $tsize , $tesize,
1346                 $tesize ? ($tsize * 1.0 / $tesize) * 100 : 0.0,
1347                 ($estsize+$flsize) ? ($tsize * 1.0 / ($estsize + $flsize)) * 100 : 0.0;
1348         if($nb_tape > 1 || $tape_size != 0) {
1349                 for($i=1; $i <= $nb_tape; $i++) {
1350                         if($tape_size != 0) {
1351                                 printf "  tape %-3d      : %3d %9d$unit %9d$unit (%6.2f%%) %s",
1352                                         $i, $ntpartition{$i}, $ntsize{$i}, $ntesize{$i}, 100*$ntsize{$i}/$tape_size, $ntlabel{$i};
1353                         }
1354                         else {
1355                                 printf "  tape %-3d      : %3d %9d$unit %9d$unit %s",
1356                                         $i, $ntpartition{$i}, $ntsize{$i}, $ntesize{$i}, $ntlabel{$i};
1357                         }
1358                         if(defined($ntchunk{$i}) && $ntchunk{$i} > 0) {
1359                                 printf " (%d chunks)", $ntchunk{$i};
1360                         }
1361                         print "\n";
1362                 }
1363         }
1364         if($idle_dumpers == 0) {
1365                 printf "all dumpers active\n";
1366         }
1367         else {
1368                 $c1 = ($idle_dumpers == 1) ? "" : "s";
1369                 $c2 = ($idle_dumpers < 10) ? " " : "";
1370                 $c3 = ($idle_dumpers == 1) ? " " : "";
1371                 printf "%d dumper%s idle%s %s: %s\n", $idle_dumpers, $c1, $c2, $c3, $status_driver;
1372         }
1373
1374         printf "taper status: $status_taper\n";
1375         if (defined $qlen{"tapeq"}) {
1376                 printf "taper qlen: %d\n", $qlen{"tapeq"};
1377         }
1378         if (defined ($free{"kps"})) {
1379                 printf "network free kps: %9d\n", $free{"kps"};
1380         }
1381         if (defined ($free{"space"})) {
1382                 if ($holding_space) {
1383                         $hs = ($free{"space"} * 1.0 / $holding_space) * 100;
1384                 } else {
1385                         $hs = 0.0;
1386                 }
1387                 printf "holding space   : %9d$unit (%6.2f%%)\n", ($free{"space"}/$unitdivisor), $hs;
1388         }
1389 }
1390
1391 if(defined $opt_stats) {
1392         if(defined($current_time) && $current_time != $start_time) {
1393                 $total_time=$current_time-$start_time;
1394                 foreach $key (sort byprocess keys %busy_time) {
1395                         printf "%8s busy   : %8s  (%6.2f%%)\n",
1396                                 $key, &busytime($busy_time{$key}),
1397                                 ($busy_time{$key} * 1.0 / $total_time) * 100;
1398                 }
1399                 for ($d = 0; $d <= $#dumpers_active; $d++) {
1400                         $l = sprintf "%2d dumper%s busy%s : %8s  (%6.2f%%)",
1401                                 $d, ($d == 1) ? "" : "s", ($d == 1) ? " " : "",
1402                                 &busytime($dumpers_active[$d]),
1403                                 ($dumpers_active[$d] * 1.0 / $total_time) * 100;
1404                         print $l;
1405                         $s1 = "";
1406                         $s2 = " " x length($l);
1407                         $r = $dumpers_held[$d];
1408                         foreach $key (sort valuesort keys %$r) {
1409                                 next
1410                                   unless $dumpers_held[$d]{$key} >= 1;
1411                                 printf "%s%20s: %8s  (%6.2f%%)\n",
1412                                         $s1,
1413                                         $key,
1414                                         &busytime($dumpers_held[$d]{$key}),
1415                                         ($dumpers_held[$d]{$key} * 1.0 / $dumpers_active[$d]) * 100;
1416                                 $s1 = $s2;
1417                         }
1418                         if ($s1 eq "") {
1419                                 print "\n";
1420                         }
1421                 }
1422         }
1423 }
1424
1425 exit $exit_status;
1426
1427 sub make_hostpart() {
1428         local($host,$partition,$datestamp) = @_;
1429
1430         if(! defined($hosts{$host})) {
1431                 push @hosts, $host;
1432                 $hosts{$host}=1;
1433         }
1434         my($new_part) = 1;
1435         foreach $pp (sort @$host) {
1436                 $new_part = 0 if ($pp eq $partition);
1437         }
1438         push @$host, $partition if $new_part==1;
1439
1440         my($hostpart) = "$host$partition$datestamp";
1441         if(!defined $datestamp{$datestamp}) {
1442                 $datestamp{$datestamp} = 1;
1443                 push @datestamp, $datestamp;
1444         }
1445
1446         return $hostpart;
1447 }
1448
1449 sub byprocess() {
1450         my(@tmp_a) = split(/(\d*)$/, $a, 2);
1451         my(@tmp_b) = split(/(\d*)$/, $b, 2);
1452         return ($tmp_a[0] cmp $tmp_b[0]) || ($tmp_a[1] <=> $tmp_b[1]);
1453 }                               
1454  
1455 sub valuesort() {
1456         $r->{$b} <=> $r->{$a};
1457 }
1458
1459 sub dump_size() {
1460         local($filename) = @_;
1461         local($size);
1462         local($dsize) = 0;
1463         local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
1464                    $atime,$mtime,$ctime,$blksize,$blocks);
1465         while ($filename ne "") {
1466                 $filename = "$filename.tmp" if (!(-e "$filename"));
1467                 $filename = "/dev/null" if (!(-e "$filename"));
1468                 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
1469                                 $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
1470                 $size=$size-32768 if $size > 32768;
1471                 $dsize += $size;
1472                 open(DUMP,$filename);
1473                 $filename = "";
1474                 while(<DUMP>) {
1475                         if(/^CONT_FILENAME=(.*)$/) { $filename = $1; last }
1476                         last if /^To restore, position tape at start of file and run/;
1477                 }
1478                 close(DUMP);
1479         }
1480         return $dsize;
1481 }
1482
1483 sub unctime() {
1484         my (@MoY);
1485         my (@tl);
1486         my ($a);
1487         my ($m);
1488         my ($month);
1489         my ($time);
1490
1491         @MoY = ('Jan','Feb','Mar','Apr','May','Jun',
1492                 'Jul','Aug','Sep','Oct','Nov','Dec');
1493
1494         # Preset an array of values in case some parts are not passed as
1495         # arguments.  This lets the date, etc, be omitted and default to
1496         # today.
1497
1498         @tl = localtime;
1499
1500         foreach $a (@_) {
1501                 next
1502                   if ($a eq '');
1503
1504                 # See if this argument looks like a month name.
1505
1506                 $month = 0;
1507                 foreach $m (@MoY) {
1508                         last
1509                           if ($m eq $a);
1510                         $month = $month + 1;
1511                 }
1512                 if ($month < 12) {
1513                         $tl[4] = $month;
1514                         next;
1515                 }
1516
1517                 # See if this is a day of the month.
1518
1519                 if ($a =~ /^\d+$/ && $a >= 1 && $a <= 32) {
1520                         $tl[3] = $a;
1521                         next;
1522                 }
1523
1524                 # See if the next argument looks like a time.
1525
1526                 if ($a =~ /^(\d+):(\d+)/) {
1527                         $tl[2] = $1;
1528                         $tl[1] = $2;
1529                         if ($a =~ /^(\d+):(\d+):(\d+)/) {
1530                                 $tl[0] = $3;
1531                         }
1532                         next;
1533                 }
1534
1535                 # See if this is a year.
1536
1537                 if ($a =~ /^\d\d\d\d$/ && $a >= 1900) {
1538                         $tl[5] = $a;
1539                         next;
1540                 }
1541         }
1542
1543         $time = &timelocal (@tl);
1544
1545         return $time;
1546 }
1547
1548 sub set_starttime() {
1549         my (@tl);
1550         my ($time);
1551         my ($date);
1552
1553         # Preset an array of values in case some parts are not passed as
1554         # arguments.  This lets the date, etc, be omitted and default to
1555         # today.
1556
1557         ($date)=@_;
1558         @tl = localtime;
1559
1560         $tl[5] = substr($date,  0, 4)   if(length($date) >= 4);
1561         $tl[4] = substr($date,  4, 2)-1 if(length($date) >= 6);
1562         $tl[3] = substr($date,  6, 2)   if(length($date) >= 8);
1563         $tl[2] = substr($date,  8, 2)   if(length($date) >= 10);
1564         $tl[1] = substr($date, 10, 2)   if(length($date) >= 12);
1565         $tl[0] = substr($date, 12, 2)   if(length($date) >= 14);
1566
1567         $time = &timelocal (@tl);
1568
1569         return $time;
1570 }
1571
1572
1573 sub showtime() {
1574         my($delta)=shift;
1575         my($oneday)=24*60*60;
1576
1577         @now=localtime($starttime+$delta);
1578         if($delta > $oneday) {
1579                 $result=sprintf("%d+",$delta/$oneday);
1580         } else {
1581                 $result="";
1582         }
1583         $result.=sprintf("%d:%02d:%02d",$now[2],$now[1],$now[0]);
1584         return $result;
1585 }
1586
1587 sub busytime() {
1588         my($busy)=shift;
1589         my($oneday)=24*60*60;
1590
1591         if($busy > $oneday) {
1592                 $days=int($busy/$oneday);
1593                 $result=sprintf("%d+",$busy/$oneday);
1594                 $busy-=$days*$oneday;
1595         } else {
1596                 $result="";
1597         }
1598         $hours=int($busy/60/60);
1599         $busy-=$hours*60*60;
1600         $minutes=int($busy/60);
1601         $busy-=$minutes*60;
1602         $seconds=$busy;
1603         $result.=sprintf("%d:%02d:%02d",$hours,$minutes,$seconds);
1604         return $result;
1605 }
1606