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