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