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