#!/usr/bin/perl -w
#

# Run perl.
eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
	 & eval 'exec /usr/bin/perl -S $0 $argv:q'
		if 0;

require "newgetopt.pl";
use Time::Local;

$confdir="/etc/amanda";
$prefix='/usr/local';
$prefix=$prefix;		# avoid warnings about possible typo
$exec_prefix="${prefix}";
$exec_prefix=$exec_prefix;	# ditto
$sbindir="${exec_prefix}/sbin";

$USE_VERSION_SUFFIXES='no';
$suf = '';
if ( $USE_VERSION_SUFFIXES =~ /^yes$/i ) {
        $suf='-2.4.2p2';
}

$result = &NGetOpt (	"summary",
			"stats|statistics",
			"dumping|d",
			"waitdumping|wdumping",
			"waittaper|wtaper",
			"dumpingtape|dtape",
			"writingtape|wtape",
			"finished",
			"failed|error",
			"estimate",
			"gestimate|gettingestimate",
			"config|c:s",
			"file:s",
			);
if($result !=1 ) {
	&usage();
}

if( defined $opt_config ) {
	$conf = $opt_config;
}
else {
	if($#ARGV == 0 ) {
		$conf=$ARGV[0];
	}
	else {
		&usage();
	}
}

if ( ! -d "$confdir/$conf" ) {
    die "amdump$suf: could not find directory $confdir/$conf";
}

$pwd = `pwd`;
chomp $pwd;
chdir "$confdir/$conf";

$logdir=`$sbindir/amgetconf$suf logdir`;
exit 1 if $? != 0;
chomp $logdir;
$errfile="$logdir/amdump";

$nb_options = defined( $opt_summary ) +
				  defined( $opt_stats ) +
				  defined( $opt_dumping ) +
				  defined( $opt_waitdumping ) +
				  defined( $opt_waittaper ) +
				  defined( $opt_dumpingtape ) +
				  defined( $opt_writingtape ) +
				  defined( $opt_finished ) +
				  defined( $opt_estimate ) +
				  defined( $opt_gestimate ) +
				  defined( $opt_failed );

if($nb_options == 0 ) {
	$opt_summary     = 1;
	$opt_stats       = 1; 
	$opt_dumping     = 1;
	$opt_waitdumping = 1;
	$opt_waittaper   = 1;
	$opt_dumpingtape = 1;
	$opt_writingtape = 1;
	$opt_finished    = 1;
	$opt_failed      = 1;
	$opt_gestimate   = 1;
	$opt_estimate    = 1;
}

if( defined $opt_file) {
	if( $opt_file =~ m,^/, ) {
		$errfile = $opt_file;
	} else {
		$errfile = "$pwd/$opt_file";
		$errfile = "$logdir/$opt_file" if ( ! (-f $errfile ));
	}
}

open(AMDUMP,"<$errfile") || die("$errfile: $!");
print "Using $errfile";

$start_degraded_mode = 0;

$label = "";					# -w fodder
$origsize = 0;					# -w fodder
$idle_dumpers = 0;
$status_driver = "";
$status_taper = 0;
$estimate_done = 0;
$holding_space = 0;
$start_time = 0;
@dumpers_active = ();

while(<AMDUMP>) {
	chomp;
	if(/amdump: start at (.*)/) {
		print " from $1";
		$starttime=&unctime(split(/[ 	]+/,$1));
	}
	elsif(/setup_estimate: (\S+):(\S+): command .*, options:/) {
		$host=$1;
		$partition=$2;
		if(! defined($hosts{$host})) {
			push @hosts, $host;
			$hosts{$host}=1;
		}
		push @$host, $partition;
		$hostpart="$host$partition";
		$estimate{$hostpart}=0;
		$level{$hostpart}=0;
		$esize{$hostpart}=0;
		$dump_started{$hostpart}=0;
		$dump_finished{$hostpart}=0;
		$taper_started{$hostpart}=0;
		$taper_finished{$hostpart}=0;
		$error{$hostpart}="";
	}
	elsif(/got result for host (\S+) disk (\S+): (\d+) -> (\d+)K,/) {
		$host=$1;
		$partition=$2;
		$hostpart="$host$partition";
		$estimate{$hostpart}=1;
		$level{$hostpart}=$3;
		$esize{$hostpart}=$4;
	}
	elsif(/getting estimates took/) {
		$estimate_done=1;
	}
	elsif(/GENERATING SCHEDULE:/) {
		$generating_schedule=1;
	}
	elsif(/^(\S+) (\S+) (\d+) (\d+) \d+:\d+:\d+:\d+:\d+:\d+ (\d+) \d+/) {
		if($generating_schedule == 1 ) {
			$host=$1;
			$partition=$2;
			$hostpart="$host$partition";
			$level{"$hostpart"}=$4;
			$size=$5;
			$size=32 if $size<32;
			$esize{$hostpart}=$size;
			$size{$hostpart}=$size;
			$degr_level{$hostpart}=-1;
		}
	}
	elsif(/^(\S+) (\S+) (\d+) (\d+) \d+:\d+:\d+:\d+:\d+:\d+ (\d+) \d+ (\d+) \d+:\d+:\d+:\d+:\d+:\d+ ([-]*\d+) \d+/) {
		if($generating_schedule == 1 ) {
			$host=$1;
			$partition=$2;
			$hostpart="$host$partition";
			$level{$hostpart}=$4;
			$size=$5;
			$size=32 if $size<32;
			$esize{$hostpart}=$size;
			$size{$hostpart}=$size;
			$degr_level{$hostpart}=$6;
			$degr_size{$hostpart}=$7;
			$degr_size{$hostpart}=32 if ($7 < 32);
		}
	}
	elsif(/^driver: start time (\S+)/) {
		$start_time=$1;
		$current_time=$1;
		$dumpers_active[0]=0;
		$dumpers_held[0]={};
		$dumpers_active=0;
	}
	elsif(/^driver: adding holding disk \d+ dir \S+ size (\d+)/) {
		$holding_space += $1;
	}
	elsif(/driver: send-cmd time (\S+) to (dumper\d*): (FILE-DUMP|PORT-DUMP) (\d+-\d+) (\S+) (\S+) (\S+) (\d+)/) {
		$current_time=$1;
		$host=$6;
		$partition=$7;
		$hostpart="$host$partition";
		$serial=$4;
		$dump_started{$hostpart}=1;
		$dump_time{$hostpart}=$1;
		$dump_finished{$hostpart}=0;
		$holding_file{$hostpart}=$5;
		if(     $level{$hostpart} != $8 &&
		   $degr_level{$hostpart} == $8) {
			$level{$hostpart}=$degr_level{$hostpart};
			$size{$hostpart} =$degr_size{$hostpart};
			$esize{$hostpart}=$degr_size{$hostpart};
		}
		$serial{"$serial"}=$hostpart;
		if(! defined($busy_time{$2})) {
			$busy_time{$2}=0;
		}
		$running_dumper{$2} = $hostpart;
		$error{$hostpart}="";
		$dumpers_active++;
		if(! defined($dumpers_active[$dumpers_active])) {
			$dumpers_active[$dumpers_active]=0;
		}
		if(! defined($dumpers_held[$dumpers_active])) {
			$dumpers_held[$dumpers_active]={};
		}
	}
	elsif(/driver: result time (\S+) from (dumper\d+): FAILED (\d+-\d+) (.*)/) {
		$current_time=$1;
		$serial=$3;
		$error=$4;
		$hostpart=$serial{$serial};
		$dump_finished{$hostpart}=-1;
		$busy_time{$2}+=($1-$dump_time{$hostpart});
		$running_dumper{$2} = "0";
		$dump_time{$hostpart}=$1;
		$error{$hostpart}=$error;
		$dumpers_active--;
	}
	elsif(/driver: result time (\S+) from (dumper\d+): TRY-AGAIN (\d+-\d+) (.*)/) {
		$current_time=$1;
		$serial=$3;
		$error=$4;
		$hostpart=$serial{$serial};
		$dump_started{$hostpart}=0;
		$dump_finished{$hostpart}=0;
		$busy_time{$2}+=($1-$dump_time{$hostpart});
		$running_dumper{$2} = "0";
		$dump_time{$hostpart}=$1;
		$error{$hostpart}="(aborted:$error)";
		$dumpers_active--;
	}
	elsif(/driver: result time (\S+) from (dumper\d+): DONE (\d+-\d+) (\d+) (\d+) (\d+) \[.*\]/) {
		$current_time=$1;
		$serial=$3;
		$origsize=$4;
		$outputsize=$5;
		$hostpart=$serial{$serial};
		$size{$hostpart}=$outputsize;
		$dump_finished{$hostpart}=1;
		$busy_time{$2}+=($1-$dump_time{$hostpart});
		$running_dumper{$2} = "0";
		$dump_time{$hostpart}=$1;
		$error{$hostpart}="";
		$dumpers_active--;
	}
	elsif(/driver: result time (\S+) from (dumper\d+): ABORT-FINISHED (\d+-\d+)/) {
		$current_time=$1;
		$serial=$3;
		$hostpart=$serial{$serial};
		$dump_started{$hostpart}=0;
		$dump_finished{$hostpart}=0;
		$busy_time{$2}+=($1-$dump_time{$hostpart});
		$running_dumper{$2} = "0";
		$dump_time{$hostpart}=$1;
		$error{$hostpart}="(aborted)";
		$dumpers_active--;
	}
	elsif(/driver: finished-cmd time (\S+) dumper\d+ dumped (\S+):(\S+)/){
		$current_time=$1;
	}
	elsif(/driver: send-cmd time (\S+) to taper: FILE-WRITE (\d+-\d+) (\S+) (\S+) (\S+) \d*/){
		$current_time=$1;
		$serial=$2;
		$host=$4;
		$partition=$5;
		$hostpart="$host$partition";
		$serial{$serial}=$hostpart;
		$taper_started{$hostpart}=1;
		$taper_finished{$hostpart}=0;
		$taper_time{$hostpart}=$1;
	}
	elsif(/driver: send-cmd time (\S+) to taper: PORT-WRITE (\d+-\d+) (\S+) (\S+) \d*( \d*|)/){
		$current_time=$1;
		$serial=$2;
		$host=$3;
		$partition=$4;
		$hostpart="$host$partition";
		$serial{$serial}=$hostpart;
		$taper_started{$hostpart}=1;
		$taper_finished{$hostpart}=0;
		$taper_time{$hostpart}=$1;
	}
	elsif(/driver: result time (\S+) from taper: DONE (\d+-\d+) (\S+)/) {
		$current_time=$1;
		$serial=$2;
		$label=$3;
		$hostpart=$serial{$serial};
		$taper_finished{$hostpart}=1;
		$busy_time{"taper"}+=($1-$taper_time{$hostpart});
		$taper_time{$hostpart}=$1;
	}
	elsif(/driver: result time (\S+) from taper: (TRY-AGAIN|TAPE-ERROR) (\d+-\d+) (.+)/) {
		$current_time=$1;
		$serial=$3;
		$error=$4;
		$hostpart=$serial{$serial};
		$taper_finished{$hostpart}= $2 eq 'TAPE-ERROR' ? -2 : -1;
		$busy_time{"taper"}+=($1-$taper_time{$hostpart});
		$taper_time{$hostpart}=$1;
		$error{$hostpart}=$error;
	}
	elsif(/planner: FAILED (\S+) (\S+) (\d+) (.*)/) {
		$host=$1;
		$partition=$2;
		$hostpart="$host$partition";
		$dump_started{$hostpart}=-1;
		$level{$hostpart}=$3;
		$error{$hostpart}=$4;
	}
	elsif(/dump of driver schedule after start degraded mode:/) {
		$start_degraded_mode=1;
	}
	elsif(/driver: state time (\S+) free (.*) taper: (\S+) idle-dumpers: (\d+) qlen (.*) driver-idle: (\S+)/) {
		$current_time=$1;
		$status_taper=$3;
		$idle_dumpers=$4;

		%free = split (/ +/, $2);
		%qlen = split (/ +/, $5);

		if($status_driver ne "") {
			$dumpers_active[$dumpers_active_prev]
				+=$current_time-$state_time_prev;
			$dumpers_held[$dumpers_active_prev]{$status_driver}
				+=$current_time-$state_time_prev;
		}
		$state_time_prev=$current_time;
		$dumpers_active_prev=$dumpers_active;
		$status_driver=$6;
		if(! defined($dumpers_held[$dumpers_active]{$status_driver})) {
			$dumpers_held[$dumpers_active]{$status_driver}=0;
		}
	}
}

close(AMDUMP);

if(defined $current_time) {
	for ($d = 0; $d < $#dumpers_active; $d++) {
		$the_dumper = "dumper$d";
		if(defined($running_dumper{$the_dumper}) &&
		   $running_dumper{$the_dumper} ne "0") {
			$busy_time{$the_dumper}+=($current_time-$dump_time{$running_dumper{$the_dumper}});
		}
	}
}

print "\n\n";

$nb_partition = 0;

$epartition = 0;
$estsize = 0;
$fpartition = 0;
$fsize = 0;
$wpartition = 0;
$wsize = 0;

$dtpartition = 0;
$dtesize = 0;
$dupartition = 0;
$dusize = 0;
$duesize = 0;
$dpartition = 0;
$dsize = 0;
$desize = 0;

$twpartition = 0;
$twsize = 0;
$twesize = 0;
$tapartition = 0;
$tasize = 0;
$taesize = 0;
$tfpartition = 0;
$tfsize = 0;
$tfesize = 0;
$tpartition = 0;
$tsize = 0;
$tesize = 0;

foreach $host (sort @hosts) {
	foreach $partition (sort @$host) {
		$nb_partition++;
		$hostpart = "$host$partition";
		if($estimate_done != 1) {
			if($estimate{$hostpart} != 1) {
				if( defined $opt_gestimate ) {
					printf "%-40s", "$host:$partition";
					print "            getting estimate\n";
				}
			}
			else {
				if( defined $opt_estimate ) {
					printf "%-40s", "$host:$partition";
					printf "%2d",  $level{$hostpart};
					printf "%8dk", $esize{$hostpart};
					print " estimate done\n";
				}
				$epartition++;
				$estsize += $esize{$hostpart};
			}
		}
		else {
			$epartition++;
			$estsize += $esize{$hostpart};
			if($estimate{$hostpart} != 1) {
				if( defined $opt_failed ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					print " no estimate\n";
				}
				$epartition--;
				$estsize -= $esize{$hostpart};
				$fpartition++;
			}
			elsif($dump_started{$hostpart} == -1) {
				if( defined $opt_failed ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf " " . $error{$hostpart} . "\n";
				}
				$fpartition++;
				$fsize+=$esize{$hostpart};
			}
			elsif($dump_started{$hostpart} != 1) {
				if( defined $opt_waitdumping ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $esize{$hostpart};
					print " wait for dumping $error{$hostpart}\n";
				}
				$wpartition++;
				$wsize += $esize{$hostpart};
			}
			elsif($dump_started{$hostpart} == 1 &&
					$dump_finished{$hostpart} == -1) {
				if( defined $opt_failed ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					print " ", $error{$hostpart};
					if( defined $starttime ) {
						print " (", &showtime($dump_time{$hostpart}), ")";
					}
					print "\n";
				}
				$fpartition++;
				$fsize+=$esize{$hostpart};
			}
			elsif($dump_started{$hostpart} == 1 &&
					$dump_finished{$hostpart} != 1 &&
					$taper_started{$hostpart} == 1) {
				if( defined $opt_dumpingtape ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $size{$hostpart};
					print " dumping to tape";
					if( defined $starttime ) {
						print " (", &showtime($taper_time{$hostpart}), ")";
					}
					print "\n";
				}
				$dtpartition++;
				$dtesize += $esize{$hostpart};
			}
			elsif($dump_started{$hostpart} == 1 &&
					$dump_finished{$hostpart} != 1) {
				$size = &dump_size($holding_file{$hostpart});
				if( defined $opt_dumping ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $esize{$hostpart};
					printf " dumping %8dk", $size/1024;
					if($size{$hostpart} != 0) {
						printf " (%6.2f%%)", 
								 (100.0*$size)/(1024.0*$esize{$hostpart});
					}
					if( defined $starttime ) {
						print " (", &showtime($dump_time{$hostpart}), ")";
					}
					print "\n";
				}
				$dupartition++;
				$dusize += $size/1024;
				$duesize += $esize{$hostpart};
			}
			elsif($dump_finished{$hostpart} == 1 &&
					$taper_started{$hostpart} != 1) {
				if( defined $opt_waittaper ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $size{$hostpart};
					print " dump done";
					if( defined $starttime ) {
						print " (", &showtime($dump_time{$hostpart}), ")";
					}
					print ", wait for writing to tape\n";
				}
				$dpartition++;
				$dsize += $size{$hostpart};
				$desize += $esize{$hostpart};
				$twpartition++;
				$twsize += $size{$hostpart};
				$twesize += $esize{$hostpart};
			}
			elsif($taper_started{$hostpart} == 1 &&
					$taper_finished{$hostpart} == 0) {
				if( defined $opt_writingtape ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $size{$hostpart};
					print " writing to tape";
					if( defined $starttime ) {
						print " (", &showtime($taper_time{$hostpart}), ")";
					}
					print "\n";
				}
				$dpartition++;
				$dsize += $size{$hostpart};
				$desize += $esize{$hostpart};
				$tapartition++;
				$tasize += $size{$hostpart};
				$taesize += $esize{$hostpart};
			}
			elsif($taper_started{$hostpart} == 1 &&
					$taper_finished{$hostpart} < 0) {
				if( defined $opt_failed ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $size{$hostpart};
					print " failed to tape";
					print " (will retry)" unless $taper_finished{$hostpart} < -1;
					if( defined $starttime ) {
						print " (", &showtime($taper_time{$hostpart}), ")";
					}
					print "\n";
				}
				$dpartition++;
				$dsize += $size{$hostpart};
				$desize += $esize{$hostpart};
				$tfpartition++;
				$tfsize += $size{$hostpart};
				$tfesize += $esize{$hostpart};
			}
			elsif($taper_finished{$hostpart} == 1) {
				if( defined $opt_finished ) {
					printf "%-40s%2d", "$host:$partition", $level{$hostpart};
					printf "%8dk", $size{$hostpart};
					print " finished";
					if( defined $starttime ) {
						print " (", &showtime($taper_time{$hostpart}), ")";
					}
					print "\n";
				}
				$dpartition++;
				$dsize += $size{$hostpart};
				$desize += $esize{$hostpart};
				$tpartition++;
				$tsize += $size{$hostpart};
				$tesize += $esize{$hostpart};
			}
			else {
				printf "%-40s%2d", "$host:$partition", $level{$hostpart};
				print " unknown state\n";
			}
		}
	}
}

if (defined $opt_summary) {
	print "\n";
	print  "SUMMARY          part     real estimated\n";
	print  "                          size      size\n";
	printf "partition       : %3d\n", $nb_partition;
	printf "estimated       : %3d %18dk\n", $epartition , $estsize;
	printf "failed          : %3d %18dk           (%6.2f%%)\n",
		$fpartition , $fsize,
		$estsize ? ($fsize * 1.0 / $estsize) * 100 : 0.0;
	printf "wait for dumping: %3d %18dk           (%6.2f%%)\n",
		$wpartition , $wsize,
		$estsize ? ($wsize * 1.0 / $estsize) * 100 : 0.0;
	printf "dumping to tape : %3d %18dk           (%6.2f%%)\n",
		$dtpartition, $dtesize,
		$estsize ? ($dtesize * 1.0 / $estsize) * 100 : 0.0;
	printf "dumping         : %3d %8dk %8dk (%6.2f%%) (%6.2f%%)\n",
		$dupartition, $dusize, $duesize,
		$duesize ? ($dusize * 1.0 / $duesize) * 100 : 0.0,
		$estsize ? ($dusize * 1.0 / $estsize) * 100 : 0.0;
	printf "dumped          : %3d %8dk %8dk (%6.2f%%) (%6.2f%%)\n",
		$dpartition , $dsize , $desize,
		$desize ? ($dsize * 1.0 / $desize) * 100 : 0.0,
		$estsize ? ($dsize * 1.0 / $estsize) * 100 : 0.0;
	printf "wait for writing: %3d %8dk %8dk (%6.2f%%) (%6.2f%%)\n",
		$twpartition, $twsize, $twesize,
		$twesize ? ($twsize * 1.0 / $twesize) * 100 : 0.0,
		$estsize ? ($twsize * 1.0 / $estsize) * 100 : 0.0;
	printf "writing to tape : %3d %8dk %8dk (%6.2f%%) (%6.2f%%)\n",
		$tapartition, $tasize, $taesize,
		$taesize ? ($tasize * 1.0 / $taesize) * 100 : 0.0,
		$estsize ? ($tasize * 1.0 / $estsize) * 100 : 0.0;
	printf "failed to tape  : %3d %8dk %8dk (%6.2f%%) (%6.2f%%)\n",
		$tfpartition, $tfsize, $tfesize,
		$tfesize ? ($tfsize * 1.0 / $tfesize) * 100 : 0.0,
		$estsize ? ($tfsize * 1.0 / $estsize) * 100 : 0.0;
	printf "taped           : %3d %8dk %8dk (%6.2f%%) (%6.2f%%)\n",
		$tpartition , $tsize , $tesize,
		$tesize ? ($tsize * 1.0 / $tesize) * 100 : 0.0,
		$estsize ? ($tsize * 1.0 / $estsize) * 100 : 0.0;
	if($idle_dumpers ==0) {
		printf "all dumpers active\n";
	}
	else {
		$c1 = ($idle_dumpers == 1) ? "" : "s";
		$c2 = ($idle_dumpers == 1) ? " " : "";
		printf "%d dumper%s idle%s  : %s\n", $idle_dumpers, $c1, $c2, $status_driver;
	}
	if($status_taper eq "writing" && defined($qlen{"tapeq:"})) {
		printf "taper writing, tapeq: %d\n", $qlen{"tapeq:"};
	}
	else {
		printf "taper idle\n";
	}
	if (defined ($free{"kps:"})) {
		printf "network free kps: %8d\n", $free{"kps:"};
	}
	if (defined ($free{"space:"})) {
		if ($holding_space) {
			$hs = ($free{"space:"} * 1.0 / $holding_space) * 100;
		} else {
			$hs = 0.0;
		}
		printf "holding space   : %8dk (%6.2f%%)\n", $free{"space:"}, $hs;
	}
}

if(defined $opt_stats) {
	if(defined($current_time) && $current_time != $start_time) {
		$total_time=$current_time-$start_time;
		foreach $key (sort byprocess keys %busy_time) {
			printf "%8s busy   : %8s  (%6.2f%%)\n",
				$key, &busytime($busy_time{$key}),
				($busy_time{$key} * 1.0 / $total_time) * 100;
		}
		for ($d = 0; $d <= $#dumpers_active; $d++) {
			$l = sprintf "%2d dumper%s busy%s : %8s  (%6.2f%%)",
				$d, ($d == 1) ? "" : "s", ($d == 1) ? " " : "",
				&busytime($dumpers_active[$d]),
				($dumpers_active[$d] * 1.0 / $total_time) * 100;
			print $l;
			$s1 = "";
			$s2 = " " x length($l);
			$r = $dumpers_held[$d];
			foreach $key (sort valuesort keys %$r) {
				next
				  unless $dumpers_held[$d]{$key} >= 1;
				printf "%s%20s: %8s  (%6.2f%%)\n",
					$s1,
					$key,
					&busytime($dumpers_held[$d]{$key}),
					($dumpers_held[$d]{$key} * 1.0 / $dumpers_active[$d]) * 100;
				$s1 = $s2;
			}
			if ($s1 eq "") {
				print "\n";
			}
		}
	}
}

sub byprocess() {
	my(@tmp_a) = split(/(\d*)$/, $a, 2);
	my(@tmp_b) = split(/(\d*)$/, $b, 2);
	return ($tmp_a[0] cmp $tmp_b[0]) || ($tmp_a[1] <=> $tmp_b[1]);
}                               
 
sub valuesort() {
	$r->{$b} <=> $r->{$a};
}

sub dump_size() {
	local($filename) = @_;
	local($size);
	local($dsize) = 0;
	local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
		   $atime,$mtime,$ctime,$blksize,$blocks);
	while ($filename ne "") {
		$filename = "$filename.tmp" if (!(-e "$filename"));
		$filename = "/dev/null" if (!(-e "$filename"));
		($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
				$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
		$size=$size-32768 if $size > 32768;
		$dsize += $size;
		open(DUMP,$filename);
		$filename = "";
		while(<DUMP>) {
			if(/^CONT_FILENAME=(.*)$/) { $filename = $1; last }
			last if /^To restore, position tape at start of file and run/;
		}
		close(DUMP);
	}
	return $dsize;
}

sub unctime() {
	my (@MoY);
	my (@tl);
	my ($a);
	my ($m);
	my ($month);
	my ($time);

	@MoY = ('Jan','Feb','Mar','Apr','May','Jun',
		'Jul','Aug','Sep','Oct','Nov','Dec');

	# Preset an array of values in case some parts are not passed as
	# arguments.  This lets the date, etc, be omitted and default to
	# today.

	@tl = localtime;

	foreach $a (@_) {
		next
		  if ($a eq '');

		# See if this argument looks like a month name.

		$month = 0;
		foreach $m (@MoY) {
			last
			  if ($m eq $a);
			$month = $month + 1;
		}
		if ($month < 12) {
			$tl[4] = $month;
			next;
		}

		# See if this is a day of the month.

		if ($a =~ /^\d+$/ && $a >= 1 && $a <= 32) {
			$tl[3] = $a;
			next;
		}

		# See if the next argument looks like a time.

		if ($a =~ /^(\d+):(\d+)/) {
			$tl[2] = $1;
			$tl[1] = $2;
			if ($a =~ /^(\d+):(\d+):(\d+)/) {
				$tl[0] = $3;
			}
			next;
		}

		# See if this is a year.

		if ($a =~ /^\d\d\d\d$/ && $a >= 1900) {
			$tl[5] = $a;
			next;
		}
	}

	$time = &timelocal (@tl);

	return $time;
}

sub showtime() {
	my($delta)=shift;
	my($oneday)=24*60*60;

	@now=localtime($starttime+$delta);
	if($delta > $oneday) {
		$result=sprintf("%d+",$delta/$oneday);
	} else {
		$result="";
	}
	$result.=sprintf("%d:%02d:%02d",$now[2],$now[1],$now[0]);
	return $result;
}

sub busytime() {
	my($busy)=shift;
	my($oneday)=24*60*60;

	if($busy > $oneday) {
		$days=int($busy/$oneday);
		$result=sprintf("%d+",$busy/$oneday);
		$busy-=$days*$oneday;
	} else {
		$result="";
	}
	$hours=int($busy/60/60);
	$busy-=$hours*60*60;
	$minutes=int($busy/60);
	$busy-=$minutes*60;
	$seconds=$busy;
	$result.=sprintf("%d:%02d:%02d",$hours,$minutes,$seconds);
	return $result;
}

sub usage() {
	print "amstatus [--config] config [--file amdump_file]\n";
	print "         [--summary] [--dumping] [--waitdumping] [--waittaper]\n";
	print "         [--dumpingtape] [--writingtape] [--finished] [--failed]\n";
	print "         [--estimate] [--gestimate] [--stats]\n";
	exit 0;
}
