#!/usr/local/bin/perl5
#
# -------------------------------------------------------------------- 
#
# Program Name    volstat.pl
# Source location http://www.lnf.infn.it/~angius/volstat/
# Description     Some statistic for AFS cell volumes
# Author          Sandro Angius (LNF/INFN)
# Email           Sandro.Angius@lnf.infn.it
# Creation Date   5/08/2000 (V. 0.90)
# Revision Date   5/31/2001 (V. 0.91)
#                                                                       
#  This Perl script is free software; you can redistribute it and/or        
#  modify it under the terms of the GNU General Public License as 
#  published by the Free Software Foundation;
#
#  This script is distributed in the hope that it will be useful,      
#  but WITHOUT ANY WARRANTY; without even the implied warranty of       
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    
#  Library General Public License for more details.                     
#                                                       
# -------------------------------------------------------------------- 

$VOSCMD = '/usr/afsws/etc/vos';

# Definizionde della cella di riferimento
# $MYCELL = 'lnf.infn.it';
$MYCELL = 'infn.it';

# Toglie dominio da sserver se $NODOM = 1
# Attenzione potrebbe provocare errori di calcolo su celle "sparse"
# su dominii diversi se l'hostname privato del dominio coincide
$NODOM  = 1;

$w_vname   = 20;
$w_vid     = 10;
$w_vtype   = 2;
$w_vstatus = 3;
$w_vserver = ($NODOM ? 10 : 25);
$w_vroid   = 10;
$w_vquota  = 10;
$w_p100    = 5;
$w_access  = 8;
$w_backup  = $w_vquota + 2*$w_p100 + 8;

$VOSMATCH='^(\S+)\s+(\d+) (..)\s+(\d+) K\s+(\S+)\s*\n\s+(\S+)\s+\/vicep(\w+)\s*\n\s+RWrite\s+\d+ ROnly\s+(\d+) Backup\s+(\d+)\s*\n\s+MaxQuota\s+(\d+) K\s*\n\s+Creation\s+([^\n]+)\n\s+Last Update\s+([^\n]+)\n\s+(\d+) accesses in the past day.+\n\s*\n\s*((\S+)([^\n]*\n)+)';

@mname{'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 
   'Sep', 'Oct', 'Nov', 'Dec'} = 
    ('01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12');

$summary = 0;
$backup  = 0;
$ronly   = 0;
$header  = 1;
$regexp  = '.*';

while (@ARGV[0] =~ /^-.+/) {

    $arg = shift(@ARGV);

    if ($arg eq '-help') {
	print "Usage: $0 [-help] [-summary] [-backup] [-readonly] [-noheader] [-file <filename>|-regexp <regexp>|-pipe|-all|-server <server> [partition]|volume_name ...]\n";
	exit -1;
    } 
    elsif ($arg eq '-file') {
	$fname = shift(@ARGV);
	die "$0: Missing file!\n" if ($fname eq '');
	die "$0: '$fname' is a directory !\n" if -d $fname;
	die "$0: File '$fname' doesn't exist or cannot be read!\n" unless -r $fname;
	$VSTREAM=VSTREAM;
	open($VSTREAM, "<$fname");
	last;
    } 
    elsif ($arg eq '-pipe') {
	$VSTREAM=\*STDIN;
	last;
    } 
    elsif ($arg eq '-all') {
	$VSTREAM=VSTREAM;
	open($VSTREAM, "$VOSCMD listvldb -cell $MYCELL -quiet | grep '^[^ ]'|");
	last;
    } 
    elsif ($arg eq '-regexp') {
	$regexp = shift(@ARGV);
	die "$0: Missing Regular Expression!\n" if ($regexp eq '');
	$VSTREAM=VSTREAM;
	open($VSTREAM, "$VOSCMD listvldb -cell $MYCELL -quiet | grep '^[^ ]'|");
	last;
    } 
    elsif ($arg eq '-server') {
	$hserver = shift(@ARGV);
	die "$0: Missing AFS server hostname!\n" if ($hserver eq '');
        $hvicep  = shift(@ARGV);
	if ($hvicep ne '') {
	    $hserver = "-server $hserver -partition $hvicep";
	}
	else {
	    $hserver = "-server $hserver";
	}
	$VSTREAM=VSTREAM;
	open($VSTREAM, "$VOSCMD listvol $hserver -cell $MYCELL -quiet | grep ' RW ' | cut -f1 -d' '|");
	last;
    } 
    elsif ($arg eq '-summary') {
	$summary = 1;
    } 
    elsif ($arg eq '-noheader') {
	$header = 0;
    } 
    elsif ($arg eq '-backup') {
	$backup = 1;
    } 
    elsif ($arg eq '-readonly') {
	$ronly  = 1;
    } 
    else {
	die "$0: Invalid Option '$arg', -help";
	last;
    } 
    
}

$from = $#ARGV >= 0 ;

printf "%-${w_vname}s %-${w_vid}s %-${w_vserver}s %s %${w_vquota}s %${w_p100}s %${w_p100}s %2s %2s %-8s %-8s %-3s %${w_access}s\n\n", "Volume", "ID", "Server/Part", "TY", "QUOTA(Kb)", "%Q.",  "Qx.", "RO", "BK", "CDate", "UDate", "St.", "Accesses" if $header;

while ( ($from ? $invol = shift(@ARGV) : chomp($invol=<$VSTREAM>)), $invol ne '') {

    $invol =~ s/ +$//g;
    next if ($invol !~ /$regexp/);

    ($v_name, $v_id, $v_type, $v_space, $v_status, $v_server, $v_part, $v_roid, 
     $v_bkid, $v_quota, $v_cdate, $v_rdate, $v_access, $other) =  &getvdata($invol);

    next if ($v_name == -1);

    ($v_sserver, $v_status, $v_cdate, $v_rdate) = 
	&convdata($v_server, $v_status, $v_cdate, $v_rdate);

    ($pinfo_f{$v_sserver}, $pinfo_t{$v_sserver}, $pinfo_n{$v_sserver}) = 
	&getpartinfo($v_server, $v_part) if (! defined $pinfo_f{$v_sserver});
	
    if ($v_quota) {
	$quotax100  = int(100*($v_space/$v_quota));
	$pquotax100 = int($pinfo_f{$v_sserver}/$v_quota);
	$pquotax100 = '>>' if ($pquotax100 > 99);
	$pinfo_q{$v_sserver} += $v_quota;
    }
    else {
	$quotax100  = '(' . int(100*($v_space/$pinfo_t{$v_sserver})) . ')';
	$pquotax100 = int($pinfo_f{$v_sserver}/$v_space);
	$pquotax100 = '>>' if ($pquotax100 > 99);
	$pquotax100 = '(' . $pquotax100 . ')';
	$pinfo_n{$v_sserver} = '*';
	$pinfo_q{$v_sserver} += 0;
    }

    $pinfo_u{$v_sserver} += $v_space;

    printf "%-${w_vname}s %-${w_vid}s %-${w_vserver}s  %s %${w_vquota}d %${w_p100}s %${w_p100}s %2s %2s %-8s %-8s %-3s %${w_access}d\n", $v_name, $v_id, $v_sserver, $v_type, $v_quota, $quotax100, $pquotax100, ($v_roid ? 'Y':'N'), ($v_bkid ? 'Y':'N'), $v_cdate, $v_rdate, $v_status, $v_access;

    if ($ronly) {

	$rwlocation = $v_sserver;

	($v_name, $v_id, $v_type, $v_space, $v_status, $v_server, $v_part, $v_roid, $v_bkid, $v_quota, $v_cdate, $v_rdate, $v_access, $other) =  &getvdata("${invol}.readonly");

	while ($v_name != -1) {
	    ($v_sserver, $v_status, $v_cdate, $v_rdate) = 
		&convdata($v_server, $v_status, $v_cdate, $v_rdate);

	    if ($rwlocation ne $v_sserver) {

		($pinfo_f{$v_sserver}, $pinfo_t{$v_sserver}, $pinfo_n{$v_sserver}) = 
		    &getpartinfo($v_server, $v_part) if (! defined $pinfo_f{$v_sserver});
		
		if ($v_quota) {
		    $quotax100  = int(100*($v_space/$v_quota));
		    $pquotax100 = int($pinfo_f{$v_sserver}/$v_quota);
		    $pquotax100 = '>>' if ($pquotax100 > 99);
		    $pinfo_q{$v_sserver} += $v_quota;
		}
		else {
		    $quotax100  = '(' . int(100*($v_space/$pinfo_t{$v_sserver})) . ')';
		    $pquotax100 = int($pinfo_f{$v_sserver}/$v_space);
		    $pquotax100 = '>>' if ($pquotax100 > 99);
		    $pquotax100 = '(' . $pquotax100 . ')';
		    $pinfo_n{$v_sserver} = '*';
		    $pinfo_q{$v_sserver} += 0;
		}

		$pinfo_u{$v_sserver} += $v_space;
	    }
	    else {
		$pquotax100 = '';
	    }

	    printf "%-${w_vname}s %-${w_vid}s %-${w_vserver}s  %s %${w_vquota}s %${w_p100}s %${w_p100}s %2s %2s %-8s %-8s %-3s %${w_access}d\n", ' ', $v_id, $v_sserver, $v_type, ' ', ' ', $pquotax100, ' ', ' ', ' ', $v_rdate, $v_status, $v_access;
	
	    ($v_name, $v_id, $v_type, $v_space, $v_status, $v_server, $v_part, $v_roid, $v_bkid, $v_quota, $v_cdate, $v_rdate, $v_access, $other) =  &getodata($other);
		
	}
	
    }

    if ($backup) {

	($v_name, $v_id, $v_type, $v_space, $v_status, $v_server, $v_part, $v_roid, $v_bkid, $v_quota, $v_cdate, $v_rdate, $v_access) =  &getvdata("${invol}.backup");

	if ($v_name != -1) {

	    ($v_sserver, $v_status, $v_cdate, $v_rdate) = 
		&convdata($v_server, $v_status, $v_cdate, $v_rdate);

	    printf "%-${w_vname}s %-${w_vid}s %-${w_vserver}s  %s %${w_backup}s %-8s %-8s %-3s %${w_access}d\n", ' ', $v_id, $v_sserver, $v_type, ' ', ' ', $v_rdate, $v_status, $v_access;
	
	}
    }
}

if ($summary) {

    print "\n\n";
    printf "%-${w_vserver}s %${w_vquota}s %${w_vquota}s %${w_vquota}s %${w_vquota}s %${w_p100}s %${w_p100}s %${w_p100}s\n\n", "Srv/Part", "RUsed(Kb)", "LUsed(Kb)", "Quota(Kb)", "Blocks(Kb)", "RU%", "LU%",  "Q%" if $header;

    foreach $vice (sort keys %pinfo_f) {

	$afs_u += $pinfo_u{$vice};
	$afs_q += $pinfo_q{$vice};
	$afs_t += $pinfo_t{$vice};
	$cur_a  = $pinfo_t{$vice} - $pinfo_f{$vice};
	$afs_a += $cur_a;

	printf "%-${w_vserver}s %${w_vquota}d %${w_vquota}d %${w_vquota}d %${w_vquota}d %${w_p100}d %${w_p100}d %${w_p100}d %s\n", $vice, $cur_a, $pinfo_u{$vice}, $pinfo_q{$vice}, $pinfo_t{$vice}, int(100*($cur_a/$pinfo_t{$vice})), int(100*($pinfo_u{$vice}/$pinfo_t{$vice})), int(100*($pinfo_q{$vice}/$pinfo_t{$vice})), $pinfo_n{$vice};
    }

    print "\n", "-" x (75 + ($NODOM == 0 ? 15 : 0)), "\n" if $header;

    printf "%-${w_vserver}s %${w_vquota}s %${w_vquota}s %${w_vquota}s %${w_vquota}s %${w_p100}s %${w_p100}s %${w_p100}s %s\n", "Total:", $afs_a, $afs_u, $afs_q, $afs_t, int(100*($afs_a/$afs_t)), int(100*($afs_u/$afs_t)), int(100*($afs_q/$afs_t));


}
exit 0;

sub getvdata {

    my($volinfo,$tail);
    my($volname) = @_;

    $volinfo = `$VOSCMD examine $volname -cell $MYCELL 2>&1`;

    return (-1) if ($volinfo eq '' | $volinfo =~ /does not exist/);
    return (-1) if ($volinfo eq '' | $volinfo =~ /VLDB: no such entry/);
    return (-1) if ($volinfo eq '' | $volinfo =~ /Could not attach volume/);

    $_ = $volinfo;

    /$VOSMATCH/;

    return($1, $2, $3, $4, $5, $6, $7, $8, 
	   $9, $10, $11, $12, $13, ($15 eq 'RWrite:' ? '' : $14));
}

sub getodata {

    my($tail);
    my($volinfo) = @_;

    return (-1) if ($volinfo eq '');

    $_ = $volinfo;

    /$VOSMATCH/;

    return($1, $2, $3, $4, $5, $6, $7, $8, 
	   $9, $10, $11, $12, $13, ($15 eq 'RWrite:' ? '' : $14));
}

sub convdata {

    my($sserver, $status, $cdate, $rdate) = @_;

    # toglie dominio da sserver se $NODOM = 1;
    $sserver  =~ s#^([^\.]+)\..+$#\1# if $NODOM; 
    $sserver .=  "/$v_part";
    $status   =~ s#-.+$##;
    $cdate    =~ s#... (...)\s+(\d+) \d\d:\d\d:\d\d (\d+)$#\3#;
    $cdate   .=  $mname{$1} . sprintf("%02d", $2);
    $rdate    =~ s#... (...)\s+(\d+) \d\d:\d\d:\d\d (\d+)$#\3#;
    $rdate   .=  $mname{$1} . sprintf("%02d", $2);

    return($sserver, $status, $cdate, $rdate);
}

sub getpartinfo {

    my($free, $tot);
    my($server, $partition) = @_;

    ($free = `$VOSCMD partinfo $server $partition -cell $MYCELL`) =~ s#^.+: (\d+) .+total (\d+)\n$#\1#;
    $tot = $2;

    return($free, $tot, '');
}
	
#
# EOF
#
