#!/usr/local/bin/perl

# na_qdiff - display quota diff
# Copyright (C) 1998  Daniel Quinlan
#
# This program 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; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

use Getopt::Std;

# Quota Fields, for major versions 4 and 5
sub QF4_Type ()		{0;}
sub QF4_ID ()		{1;}
sub QF4_KBytesUsed ()	{2;}
sub QF4_KBytesLimit ()	{3;}
sub QF4_FilesUsed ()	{4;}
sub QF4_FilesLimit ()	{5;}
sub QF4_QuotaSpec ()	{6;}
#
sub QF5_Type ()		{0;}
sub QF5_ID ()		{1;}
sub QF5_Volume ()	{2;}
sub QF5_Tree ()		{3;}
sub QF5_KBytesUsed ()	{4;}
sub QF5_KBytesLimit ()	{5;}
sub QF5_FilesUsed ()	{6;}
sub QF5_FilesLimit ()	{7;}
sub QF5_QuotaSpec ()	{8;}
#
sub QF_Type ()		{($QF == 4) ? &QF4_Type        : &QF5_Type; }
sub QF_ID ()		{($QF == 4) ? &QF4_ID          : &QF5_ID; }
sub QF_KBytesUsed ()	{($QF == 4) ? &QF4_KBytesUsed  : &QF5_KBytesUsed; }
sub QF_KBytesLimit ()	{($QF == 4) ? &QF4_KBytesLimit : &QF5_KBytesLimit; }
sub QF_FilesUsed ()	{($QF == 4) ? &QF4_FilesUsed   : &QF5_FilesUsed; }
sub QF_FilesLimit ()	{($QF == 4) ? &QF4_FilesLimit  : &QF5_FilesLimit; }
sub QF_QuotaSpec ()	{($QF == 4) ? &QF4_QuotaSpec   : &QF5_QuotaSpec; }

$prog = $0;
$prog =~ s@.*/@@;

getopts("hvVd:");

if ($opt_h) {
    &usage;
    exit 0;
}
if (($#ARGV < 1 && !$opt_d) || ($opt_d && $#ARGV < 0)) {
    &usage;
    exit 1;
}

sub usage {
    print <<EOF;
usage: $prog [-hvV] [report-A] [report-B|filer]
       $prog -d NUM filer

 -h       print this help
 -v       verbose (also print lines where "Files Used" changes)
 -V       more verbose (print every line)
 -d NUM   query filer, delay NUM seconds, then query again

The quota reports to be compared must be from a filer running
the same major version number (4 and 5 are currently supported).

If "report-B" does not exist and "filer" does, tries to
"rsh quota report" to a filer of the same name.
(Must be done as the root user from an adminhost).

Quotas listed in only one report are ignored.

Default verbosity is to only print lines where "KBytes Used" changes.
EOF
}

sub display_difference () {
    print $header_lines;

    for ($x = 0; $x <= $#before; $x++) {
	for ($y = 0; $y <= $#after; $y++) {
	    if ((($QF == 4) ||
		 ($QF == 5 &&
		  $before[$x][&QF5_Volume] eq $after[$y][&QF5_Volume] &&
		  $before[$x][&QF5_Tree] eq $after[$y][&QF5_Tree])) &&
		$before[$x][&QF_Type] eq $after[$y][&QF_Type] &&
		$before[$x][&QF_ID] eq $after[$y][&QF_ID] &&
		$before[$x][&QF_QuotaSpec] eq $after[$y][&QF_QuotaSpec])
	    {
		next unless (($opt_V) ||
			     ($before[$x][&QF_KBytesUsed] !=
			      $after[$y][&QF_KBytesUsed]) ||
			     ($opt_v &&
			      $before[$x][&QF_FilesUsed] !=
			      $after[$y][&QF_FilesUsed]));

		for ($i = 0; $i <= 8; $i++) {
		    if ($after[$y][$i] =~ /^-?[0-9]+$/ && $i != &QF_ID) {
			print ($after[$y][$i] - $before[$x][$i]);
		    }
		    else {
			print $after[$y][$i];
		    }
		    if ($i < 8) {
			print "\t";
		    }
		    else {
			print "\n";
		    }
		}
	    }
	}
    }
}

if ($opt_d) {
    # trying to directly query a filer
    die "$prog: unknown host $ARGV[0]\n" if !(gethostbyname($ARGV[0]));
    die "$prog: requires root privilege\n" if ($< != 0);
    die "$prog: bad timing interval\n" if ($opt_d <= 0);
    open (INPUT1,"rsh $ARGV[0] 'quota report'|") || die "Can't rsh $ARGV[0]\n";
    $ARGV[1] = $ARGV[0];
}
elsif (! -f $ARGV[1]) {
    # maybe trying to directly query a filer
    die "$prog: unknown file or host $ARGV[1]\n" if !(gethostbyname($ARGV[1]));
    die "$prog: requires root privilege\n" if ($< != 0);
    die "$prog: bad timing interval\n" if ($opt_d < 0);
    open (INPUT1, $ARGV[0]) || die "Can't open $ARGV[0]: $!\n";
    open (INPUT2,"rsh $ARGV[1] 'quota report'|") || die "Can't rsh $ARGV[1]\n";
}
else {
    # using two files
    open (INPUT1, $ARGV[0]) || die "Can't open $ARGV[0]: $!\n";
    open (INPUT2, $ARGV[1]) || die "Can't open $ARGV[1]: $!\n";
}

$QF = 4;
$header_done = 0;
$header_lines = '';
while (<INPUT1>) {
    if (! $header_done) {
	if (/Volume/) {
	    $QF = 5;
	}
	$header_lines .= $_;
	if (/^-/) {
	    $header_done = 1;
	}
	next;
    }
    @tmp = split;
    push @before, [ @tmp ];
}
close(INPUT1);
die "$prog: invalid data from $ARGV[0]\n" if (!$header_done);

if ($opt_d) {
    sleep $opt_d;
    open (INPUT2,"rsh $ARGV[0] 'quota report'|") || die "Can't rsh $ARGV[0]\n";
}

$QF_tmp = 4;
$header_done = 0;
while (<INPUT2>) {
    if (! $header_done) {
	if (/Volume/) {
	    $QF_tmp = 5;
	}
	if (/^-/) {
	    $header_done = 1;
	}
	next;
    }
    @tmp = split;
    push @after, [ @tmp ];
}
close(INPUT2);
die "$prog: invalid data from $ARGV[1]\n" if (!$header_done);

if ($QF != $QF_tmp) {
    die "$prog: quota report version mismatch\n";
}

&display_difference;
