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