#!/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.5p1';
}

$result = &NGetOpt (	"summary",
			"stats|statistics",
			"dumping|d",
			"waitdumping|wdumping",
			"waittaper|wtaper",
			"dumpingtape|dtape",
			"writingtape|wtape",
			"finished",
			"failed|error",
			"estimate",
			"gestimate|gettingestimate",
			"date",
			"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 "amstatus$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;
}

$unit=`$sbindir/amgetconf$suf displayunit`;
chomp($unit);
$unitdivisor=1;
if($unit eq 'K') {
  $unitdivisor = 1;
  $unit='k';
}
elsif($unit eq 'M') {
  $unitdivisor = 1024;
  $unit='m';
}
elsif($unit eq 'G') {
  $unitdivisor = 1024*1024;
  $unit='g';
}
elsif($unit eq 'T') {
  $unitdivisor = 1024*1024*1024;
  $unit='t';
}


if( defined $opt_file) {
	if( $opt_file =~ m,^/, ) {
		$errfile = $opt_file;
	} else {
		$errfile = "$pwd/$opt_file";
		$errfile = "$logdir/$opt_file" if ( ! (-f $errfile ));
	}
}
else {
	$errfile="$logdir/amflush" if(! (-f $errfile));
	if (! -f $errfile) {
		if (-f "$logdir/amflush.1" && -f "$logdir/amdump.1" &&
		    -M "$logdir/amflush.1"  < -M "$logdir/amdump.1") {
			$errfile="$logdir/amflush.1";
		} else {
			$errfile="$logdir/amdump.1";
		}
	}
}

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 = ();
$nb_tape = 0;
$ntpartition{$nb_tape} = 0;
$ntsize{$nb_tape} = 0;
$ntesize{$nb_tape} = 0;
$tape_size = 0;

while(<AMDUMP>) {
	chomp;
	if(/(amdump|amflush): start at (.*)/) {
		print " from $2\n";
		$starttime=&unctime(split(/[ 	]+/,$2));
	}
	elsif(/amdump: datestamp (\S+)/) {
		$gdatestamp = $1;
		if(!defined $datestamp{$gdatestamp}) {
			$datestamp{$gdatestamp} = 1;
			push @datestamp, $gdatestamp;
		}
	}
	elsif(/setup_estimate: (\S+):(\S+): command .*, options: *(\S+) *last_level -?\d+ next_level0 -?\d+ level_days \d+ *getting estimates (-?\d) \(-2\) (-?\d) \(-2\) (-?\d) \(-2\)/) {
		$host=$1;
		$partition=$2;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		$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;
		$partialestimate{$hostpart}=0;
		$error{$hostpart}="";
		if($4 != -1) { $getest{$hostpart} .= ":$4:" };
		if($5 != -1) { $getest{$hostpart} .= ":$5:" };
		if($6 != -1) { $getest{$hostpart} .= ":$6:" };
	}
	elsif(/setup_estimate: (\S+):(\S+): command .*, options:/) {
		$host=$1;
		$partition=$2;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		$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;
		$partialestimate{$hostpart}=0;
		$error{$hostpart}="";
		$_ = <AMDUMP>;
		while (! /getting estimates/) { $_ = <AMDUMP>; }
		chomp;
		if(/getting estimates (-?\d) \(-2\) (-?\d) \(-2\) (-?\d) \(-2\)/) {
			if($1 != -1) { $getest{$hostpart} .= ":$1:" };
			if($2 != -1) { $getest{$hostpart} .= ":$2:" };
			if($3 != -1) { $getest{$hostpart} .= ":$3:" };
		}
		else {
			die("ERROR $_");
		}
	}
	elsif(/got result for host (\S+) disk (\S+): (\d+) -> (\d+)K,/) {
		$host=$1;
		$partition=$2;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		$estimate{$hostpart}=1;
		$level{$hostpart}=$3;
		$esize{$hostpart}=$4 / $unitdivisor;
		$partialestimate{$hostpart}=0;
		$getest{$hostpart} = "";
	}
	elsif(/got partial result for host (\S+) disk (\S+): (-?\d+) -> (-?\d+)K, (-?\d+) -> (-?\d+)K, (-?\d+) -> (-?\d+)K/) {
		$host=$1;
		$partition=$2;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		if($4 > 0 || $6 > 0 || $8 > 0) {
			$estimate{$hostpart}=1;
			$level{$hostpart}=$3;
			$esize{$hostpart}=$4 / $unitdivisor;
			$partialestimate{$hostpart}=1;
			if($4 > 0) { $getest{$hostpart} =~ s/:$3://; }
			if($6 > 0) { $getest{$hostpart} =~ s/:$5://; }
			if($8 > 0) { $getest{$hostpart} =~ s/:$7://; }

			if($getest{$hostpart} eq "") { $partialestimate{$hostpart}=0; }
		}
	}
	elsif(/getting estimates took/) {
		$estimate_done=1;
	}
	elsif(/amflush/) {
		$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=&make_hostpart($host,$partition,$gdatestamp);
			$level{"$hostpart"}=$4;
			$esize=$5;
			$esize=32 if $esize<32;
			$esize{$hostpart}=$esize / $unitdivisor;
			$degr_level{$hostpart}=-1;
		}
	}
	elsif(/^DUMP (\S+) (\S+) (\S+) (\d+) (\d+) \d+:\d+:\d+:\d+:\d+:\d+ (\d+) \d+/) {
		if($generating_schedule == 1 ) {
			$host=$1;
			$partition=$2;
			$datestamp=$3;
			$hostpart=&make_hostpart($host,$partition,$datestamp);
			$level{"$hostpart"}=$5;
			$esize=$6;
			$esize=32 if $esize<32;
			$esize{$hostpart}=$esize / $unitdivisor;
			$degr_level{$hostpart}=-1;
		}
	}
	elsif(/^DUMP (\S+) (\S+) (\S+) (\S+) (\d+) (\d+) \d+:\d+:\d+:\d+:\d+:\d+ (\d+) \d+/) {
		if($generating_schedule == 1 ) {
			$host=$1;
			$features=$2;
			$features=$features;
			$partition=$3;
			$datestamp=$4;
			$hostpart=&make_hostpart($host,$partition,$datestamp);
			$level{"$hostpart"}=$6;
			$esize=$7;
			$esize=32 if $esize<32;
			$esize{$hostpart}=$esize / $unitdivisor;
			$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=&make_hostpart($host,$partition,$gdatestamp);
			$level{$hostpart}=$4;
			$esize=$5;
			$esize=32 if $esize<32;
			$esize{$hostpart}=$esize / $unitdivisor;
			$degr_level{$hostpart}=$6;
			$degr_size{$hostpart}=$7 / $unitdivisor;
			$degr_size{$hostpart}=32 if ($7 < 32);
		}
	}
	elsif(/^DUMP (\S+) (\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;
			$datestamp=$3;
			$hostpart=&make_hostpart($host,$partition,$datestamp);
			$level{$hostpart}=$5;
			$esize=$6;
			$esize=32 if $esize<32;
			$esize{$hostpart}=$esize / $unitdivisor;
			$degr_level{$hostpart}=$7;
			$degr_size{$hostpart}=$8 / $unitdivisor;
			$degr_size{$hostpart}=32 if ($8 < 32);
		}
	}
	elsif(/^FLUSH (\S+) (\S+) (\S+) (\d+) (\S+)/) {
		$host=$1;
		$partition=$2;
		$datestamp="$3";
		$level=$4;
		$holding_file=$5;
		$hostpart=&make_hostpart($host,$partition,$datestamp);
		$flush{$hostpart}=0;
		$holding_file{$hostpart}=$holding_file;
		$level{$hostpart}=$level;
	}
	elsif(/^driver: start time (\S+)/) {
		$start_time=$1;
		$current_time=$1;
		$dumpers_active[0]=0;
		$dumpers_held[0]={};
		$dumpers_active=0;
	}
	elsif(/^driver: tape size (\d+)/) {
		$tape_size = $1 / $unitdivisor;
	}
	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=&make_hostpart($host,$partition,$gdatestamp);
		$serial=$4;
		$serial{$serial}=$hostpart;
		$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};
			$esize{$hostpart}=$degr_size{$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: send-cmd time (\S+) to (dumper\d*): (FILE-DUMP|PORT-DUMP) (\d+-\d+) (\S+) (\S+) (\S+) (\S+) (\d+)/) {
		$current_time=$1;
		$host=$6;
		$partition=$7;
		$device=$8;
		$device=$device;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		$serial=$4;
		$serial{$serial}=$hostpart;
		$dump_started{$hostpart}=1;
		$dump_time{$hostpart}=$1;
		$dump_finished{$hostpart}=0;
		$holding_file{$hostpart}=$5 if $3 eq "FILE-DUMP";
		if(     $level{$hostpart} != $9 &&
		   $degr_level{$hostpart} == $9) {
			$level{$hostpart}=$degr_level{$hostpart};
			$esize{$hostpart}=$degr_size{$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: send-cmd time (\S+) to (dumper\d*): (FILE-DUMP|PORT-DUMP) (\d+-\d+) (\S+) (\S+) (\S+) (\S+) (\S+) (\d+)/) {
		$current_time=$1;
		$host=$6;
		$features=$7;
		$features=$features;
		$partition=$8;
		$device=$9;
		$device=$device;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		$serial=$4;
		$serial{$serial}=$hostpart;
		$dump_started{$hostpart}=1;
		$dump_time{$hostpart}=$1;
		$dump_finished{$hostpart}=0;
		$holding_file{$hostpart}=$5 if $3 eq "FILE-DUMP";
		if(     $level{$hostpart} != $10 &&
		   $degr_level{$hostpart} == $10) {
			$level{$hostpart}=$degr_level{$hostpart};
			$esize{$hostpart}=$degr_size{$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: send-cmd time (\S+) to (dumper\d*): CONTINUE (\d+-\d+) (\S+) (\d+) (\d+)/) {
		$current_time=$1;
		$serial=$3;
		$hostpart=$serial{$serial};
		if($hostpart ne "") {
			$dump_roomq{$hostpart}=undef;
			$error{$hostpart}="";
		}
	}
	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}="driver: $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}="driver: (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 / $unitdivisor;
		$outputsize=$5 / $unitdivisor;
		$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}="driver: (aborted)";
		$dumpers_active--;
	}
	elsif(/driver: result time (\S+) from (dumper\d+): RQ-MORE-DISK (\d+-\d+)/) {
		$current_time=$1;
		$serial=$3;
		$hostpart=$serial{$serial};
		$dump_roomq{$hostpart}=1;
		$error{$hostpart}="(waiting for holding disk space)";
	}
	elsif(/driver: finished-cmd time (\S+) dumper\d+ dumped (\S+):(\S+)/){
		$current_time=$1;
	}
	elsif(/driver: send-cmd time (\S+) to taper: START-TAPER (\S+)/) {
		if(!defined $gdatestamp) {
			$gdatestamp=$2;
			if(!defined $datestamp{$gdatestamp}) {
				$datestamp{$gdatestamp} = 1;
				push @datestamp, $gdatestamp;
			}
		}
	}
	elsif(/driver: send-cmd time (\S+) to taper: FILE-WRITE (\d+-\d+) (\S+) (\S+) (\S+) (\d*) (\S+)/){
		$current_time=$1;
		$serial=$2;
		$host=$4;
		$partition=$5;
		$level=$6;
		$ldatestamp=$7;
		if(!defined $datestamp{$ldatestamp}) {
			$datestamp{$ldatestamp} = 1;
			push @datestamp, $ldatestamp;
		}
		$hostpart=&make_hostpart($host,$partition,$ldatestamp);
		$serial{$serial}=$hostpart;
		if(!defined $level{$hostpart}) {
			$level{$hostpart} = $level;
		}
		$serial{$serial}=$hostpart;
		$taper_started{$hostpart}=1;
		$taper_finished{$hostpart}=0;
		$taper_time{$hostpart}=$1;
	}
	#features (maybe missing features)
	elsif(/driver: send-cmd time (\S+) to taper: FILE-WRITE (\d+-\d+) (\S+) (\S+) (\S*) (\S+) (\d*) (\S+)/){
		$current_time=$1;
		$serial=$2;
		$host=$4;
		$features=$5;
		$features=$features;
		$partition=$6;
		$level=$7;
		$ldatestamp=$8;
		if(!defined $datestamp{$ldatestamp}) {
			$datestamp{$ldatestamp} = 1;
			push @datestamp, $ldatestamp;
		}
		$hostpart=&make_hostpart($host,$partition,$ldatestamp);
		$serial{$serial}=$hostpart;
		if(!defined $level{$hostpart}) {
			$level{$hostpart} = $level;
		}
		$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=&make_hostpart($host,$partition,$gdatestamp);
		$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+) (\S+) \d+ \d+/){
		$current_time=$1;
		$serial=$2;
		$host=$3;
		$features=$4;
		$partition=$5;
		$hostpart=&make_hostpart($host,$partition,$gdatestamp);
		$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+) (\d+) \[sec (\S+) kb (\d+) kps/) {
		$current_time=$1;
		$serial=$2;
		$label=$3;
		$size=$6 / $unitdivisor;
		$hostpart=$serial{$serial};
		$taper_finished{$hostpart}=1;
		$busy_time{"taper"}+=($1-$taper_time{$hostpart});
		$taper_time{$hostpart}=$1;
		if(!defined $size{$hostpart}) {
			$size{$hostpart}=$size;
		}
		$ntpartition{$nb_tape}++;
		$ntsize{$nb_tape} += $size{$hostpart};
		if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
			$ntesize{$nb_tape} += $esize{$hostpart};
		}
		else {
			$ntesize{$nb_tape} += $size{$hostpart};
		}
	}
	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}="driver: $error";
	}
	elsif(/driver: dump failed (\S+) (\S+) (\S+), too many dumper retry/) {
		$serial=$1;
		$hostpart=$serial{$serial};
		$dump_started{$hostpart}=-1;
		$dump_finished{$hostpart}=-2;
		$error{$hostpart} .= "(too many dumper retry)";
	}
	elsif(/driver: tape failed (\S+) (\S+) (\S+), too many taper retry/) {
		$serial=$1;
		$hostpart=$serial{$serial};
		$taper_started{$hostpart}=-1;
		$taper_finished{$hostpart}=-2;
		$error{$hostpart} .= "(too many taper retry)";
	}
	elsif(/planner: FAILED (\S+) (\S+) (\S+) (-?\d+) (.*)/) {
		$host=$1;
		$partition=$2;
		$datestamp=$3;
		$hostpart=&make_hostpart($host,$partition,$datestamp);
		$dump_started{$hostpart}=-1;
		$level{$hostpart}=$4;
		$error{$hostpart}="planner: $5";
	}
	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;
		}
	}
	elsif(/taper: wrote label `(\S*)'/) {
		$nb_tape++;
		$ntlabel{$nb_tape} = $1;
		$ntpartition{$nb_tape} = 0;
		$ntsize{$nb_tape} = 0;
		$ntesize{$nb_tape} = 0;
	}
	else {
		#print "Ignoring: $_\n";
	}
}

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";

$nb_partition = 0;

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

$flpartition = 0;
$flsize = 0;
$wfpartition = 0;
$wfsize = 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;

$maxnamelength = 10;
foreach $host (sort @hosts) {
	foreach $partition (sort @$host) {
		foreach $datestamp (sort @datestamp) {
			$hostpart=&make_hostpart($host,$partition,$datestamp);
			next if(!defined $estimate{$hostpart} && !defined $flush{$hostpart});
			if(length("$host:$partition") > $maxnamelength) {
				$maxnamelength = length("$host:$partition");
			}
		}
	}
}

foreach $host (sort @hosts) {
	foreach $partition (sort @$host) {
	   foreach $datestamp (sort @datestamp) {
			$hostpart=&make_hostpart($host,$partition,$datestamp);
			next if(!defined $estimate{$hostpart} && !defined $flush{$hostpart});
			$nb_partition++;
			if( !defined $size{$hostpart} && defined $holding_file{$hostpart}) {
				$size{$hostpart} = &dump_size($holding_file{$hostpart}) / (1024 * $unitdivisor);
			}
			$in_flush=0;
			if($estimate_done != 1 && !defined $flush{$hostpart}) {
				if(defined $estimate{$hostpart}) {
					if($estimate{$hostpart} != 1) {
						if( defined $opt_gestimate) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s", "$host:$partition";
							print "             getting estimate\n";
						}
					}
					else {
						if(defined $opt_estimate ||
							(defined $opt_gestimate && $partialestimate{$hostpart} == 1)) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s", "$host:$partition";
							printf "%2d",  $level{$hostpart};
							printf "%9d$unit", $esize{$hostpart};
							if($partialestimate{$hostpart} == 1) {
								print " partial";
							}
							print " estimate done\n";
						}
						$epartition++;
						$estsize += $esize{$hostpart};
					}
				}
			}
			else {
				if(defined $estimate{$hostpart}) {
					if($estimate{$hostpart} == 1) {
						$epartition++;
						$estsize += $esize{$hostpart};
					}
					elsif (!defined $dump_started{$hostpart} || $dump_started{$hostpart} == 0) {
						if( defined $opt_failed) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "           no estimate\n";
						}
						$fpartition++;
					}
				}
				else {
					$flpartition++;
					$flsize += $size{$hostpart};
					$in_flush=1;
				}
				if(defined $taper_started{$hostpart} &&
						$taper_started{$hostpart}==1) {
					if(defined $dump_started{$hostpart}) {
						$dpartition++;
						if(defined($size{$hostpart})) {
							$dsize += $size{$hostpart};
						}
						else {
							$dsize += $esize{$hostpart};
						}
						$desize += $esize{$hostpart};
					}
					if(defined $dump_started{$hostpart} &&
					   	$dump_started{$hostpart} == 1 &&
							$dump_finished{$hostpart} == 0 &&
							$taper_started{$hostpart} == 1) {
						if( defined $opt_dumpingtape ) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "%9d$unit", $esize{$hostpart};
							print " dumping to tape";
							if( defined $starttime ) {
								print " (", &showtime($taper_time{$hostpart}), ")";
							}
							print "\n";
						}
						$dtpartition++;
						$dtesize += $esize{$hostpart};
					}
					elsif($taper_finished{$hostpart} == 0) {
						if( defined $opt_writingtape ) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "%9d$unit", $size{$hostpart};
							if($in_flush == 0) {
								print " writing to tape";
							}
							else {
								print " flushing to tape";
							}
							if( defined $starttime ) {
								print " (", &showtime($taper_time{$hostpart}), ")";
							}
							print "\n";
						}
						$tapartition++;
						$tasize += $size{$hostpart};
						if(defined $esize{$hostpart}) {
							$taesize += $esize{$hostpart};
						}
						else {
							$taesize += $size{$hostpart};
						}
					}
					elsif($taper_finished{$hostpart} < 0) {

						if(defined $size{$hostpart}) {
							$xsize = $size{$hostpart};
						}
						elsif(defined $esize{$hostpart}) {
							$xsize = $esize{$hostpart};
						}
						else {
							$xsize = 0;
						}

						if(defined $esize{$hostpart}) {
							$exsize += $esize{$hostpart};
						}
						else {
							$exsize += $xsize;
						}

						if( defined $opt_failed  ||
							 (defined $opt_waittaper && ($taper_finished{$hostpart} == -1))) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "%9d$unit", $xsize;
							if($in_flush == 0) {
								print " failed to tape";
							}
							else {
								print " failed to flush";
							}
							print " (will retry)" unless $taper_finished{$hostpart} < -1;
							if( defined $starttime ) {
								print " (", &showtime($taper_time{$hostpart}), ")";
							}
							print "\n";
						}

						$tfpartition++;
						$tfsize += $xsize;
						$tfesize += $exsize;

						if($in_flush == 0) {
							$twpartition++;
							$twsize += $xsize;
							$twesize += $exsize;
						}
						else {
							$wfpartition++;
							$wfsize += $xsize;
						}
					}
					elsif($taper_finished{$hostpart} == 1) {
						if( defined $opt_finished ) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "%9d$unit", $size{$hostpart};
							if($in_flush == 0) {
								print " finished";
							}
							else {
								print " flushed";
							}
							if( defined $starttime ) {
								print " (", &showtime($taper_time{$hostpart}), ")";
							}
							print "\n";
						}
						$tpartition++;
						$tsize += $size{$hostpart};
						if(defined $esize{$hostpart} && $esize{$hostpart} > 1) {
							$tesize += $esize{$hostpart};
						}
						else {
							$tesize += $size{$hostpart};
						}
					}
					else {
						printf "%8s ", $datestamp if defined $opt_date;
						printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
						print " unknown state TAPER\n";
					}
				}
				elsif(defined $dump_started{$hostpart}) {
					if($dump_started{$hostpart} == -1) {
						if( defined $opt_failed ) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf " " . $error{$hostpart} . "\n";
						}
						$fpartition++;
						$fsize+=$esize{$hostpart};
					}
					elsif($dump_started{$hostpart} == 0) {
						if($estimate{$hostpart} == 1) {
							if( defined $opt_waitdumping ) {
								printf "%8s ", $datestamp if defined $opt_date;
								printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
								printf "%9d$unit", $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 "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%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) {
						if( defined $opt_dumping ) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "%9d$unit", $esize{$hostpart};
							printf " dumping %8d$unit", $size{$hostpart};
							if($size{$hostpart} != 0) {
								printf " (%6.2f%%)", (100.0*$size{$hostpart})/$esize{$hostpart};
							}
							if( defined $starttime ) {
								print " (", &showtime($dump_time{$hostpart}), ")";
							}
							if(defined $dump_roomq{$hostpart}) {
								print " " . $error{$hostpart};
							}
							print "\n";
						}
						$dupartition++;
						$dusize += $size{$hostpart};
						$duesize += $esize{$hostpart};
					}
					elsif($dump_finished{$hostpart} == 1 &&
							$taper_started{$hostpart} != 1) {
						if( defined $opt_waittaper ) {
							printf "%8s ", $datestamp if defined $opt_date;
							printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
							printf "%9d$unit", $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};
					}
					else {
						printf "%8s ", $datestamp if defined $opt_date;
						printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
						print " unknown state DUMPER\n";
					}
				}
				elsif(defined $flush{$hostpart}) {
					if( defined $opt_waittaper ) {
						printf "%8s ", $datestamp if defined $opt_date;
						printf "%-${maxnamelength}s%2d", "$host:$partition", $level{$hostpart};
						printf "%9d$unit", $size{$hostpart};
						print " waiting to flush\n";
					}
					$wfpartition++;
					$wfsize += $size{$hostpart};
				}
				elsif(defined $level{$hostpart}) {
					printf "%8s ", $datestamp if defined $opt_date;
					printf "%-${maxnamelength}s%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 %20d$unit\n", $epartition , $estsize;
	printf "flush           : %3d %9d$unit\n", $flpartition, $flsize;
	printf "failed          : %3d %20d$unit           (%6.2f%%)\n",
		$fpartition , $fsize,
		$estsize ? ($fsize * 1.0 / $estsize) * 100 : 0.0;
	printf "wait for dumping: %3d %20d$unit           (%6.2f%%)\n",
		$wpartition , $wsize,
		$estsize ? ($wsize * 1.0 / $estsize) * 100 : 0.0;
	printf "dumping to tape : %3d %20d$unit           (%6.2f%%)\n",
		$dtpartition, $dtesize,
		$estsize ? ($dtesize * 1.0 / $estsize) * 100 : 0.0;
	printf "dumping         : %3d %9d$unit %9d$unit (%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 %9d$unit %9d$unit (%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 %9d$unit %9d$unit (%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 "wait to flush   : %3d %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
		$wfpartition, $wfsize, $wfsize, 100, 0;
	printf "writing to tape : %3d %9d$unit %9d$unit (%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 %9d$unit %9d$unit (%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 %9d$unit %9d$unit (%6.2f%%) (%6.2f%%)\n",
		$tpartition , $tsize , $tesize,
		$tesize ? ($tsize * 1.0 / $tesize) * 100 : 0.0,
		($estsize+$flsize) ? ($tsize * 1.0 / ($estsize + $flsize)) * 100 : 0.0;
	if($nb_tape > 1 || $tape_size != 0) {
		for($i=1; $i <= $nb_tape; $i++) {
			if($tape_size != 0) {
				printf "  tape %-3d      : %3d %9d$unit %9d$unit (%6.2f%%) %s\n",
					$i, $ntpartition{$i}, $ntsize{$i}, $ntesize{$i}, 100*$ntsize{$i}/$tape_size, $ntlabel{$i};
			}
			else {
				printf "  tape %-3d      : %3d %9d$unit %9d$unit %s\n",
					$i, $ntpartition{$i}, $ntsize{$i}, $ntesize{$i}, $ntlabel{$i};
			}
		}
	}
	if($idle_dumpers ==0) {
		printf "all dumpers active\n";
	}
	else {
		$c1 = ($idle_dumpers == 1) ? "" : "s";
		$c2 = ($idle_dumpers < 10) ? " " : "";
		$c3 = ($idle_dumpers == 1) ? " " : "";
		printf "%d dumper%s idle%s %s: %s\n", $idle_dumpers, $c1, $c2, $c3, $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: %9d\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   : %9d$unit (%6.2f%%)\n", ($free{"space:"}/$unitdivisor), $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 make_hostpart() {
	local($host,$partition,$datestamp) = @_;

	if(! defined($hosts{$host})) {
		push @hosts, $host;
		$hosts{$host}=1;
	}
	my($new_part) = 1;
	foreach $pp (sort @$host) {
		$new_part = 0 if ($pp eq $partition);
	}
	push @$host, $partition if $new_part==1;

	my($hostpart) = "$host$partition$datestamp";
	if(!defined $datestamp{$datestamp}) {
		$datestamp{$datestamp} = 1;
		push @datestamp, $datestamp;
	}
	return $hostpart;
}

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] [--date]\n";
	exit 0;
}
