#!/usr/local/bin/perl5 -w
#
# Based on "afsmounts" script (Bradley White bww+@transarc.com)
#
# Sandro Angius (Sandro.Angius@lnf.infn.it, LNF/INFN, 05/05/2000)
# Last Update by Sandro Angius (19/12/2003)
#
# Notes          It tries to identifies loops, skips already visited subtrees
#                and avoid foreign mounts (if not requested).
#		 You need to have enough privileges on the tree under analysis.
#
# Usage          lsmountpoint.pl [-showquota] [-summary] [-foreign] <directory ...>
# Flags          -summary: show a summary of all mount points
#                -foreign: include foreign mount points
#                -showquota: show block used and quota of the volumes

use strict;

# Sometimes we need deep recursion, so no warnings about that...
$SIG{__WARN__} = sub {
	for ( $_[0] ) {
	    warn $_ unless /^Deep recursion on/;
	}
};

my($FS_LSM)='/usr/afsws/bin/fs lsmount ';
my($FS_EXA)='/usr/afsws/bin/fs examine ';

my($row)        = 0;
my($volwidth)   = 24;
my($qtawidth)   = 0;
my($qtahead)    = '';
my($notforeign) = 1;
my($summary)    = 0;
my($showquota)  = 0;

my($arg, $vol, $msg, %volmount, %volstk);

sub descend {
        my($dir) = @_;
        my(@names);

        return warn "Can't opendir $dir: $!\n" unless opendir(DIR, $dir);
        @names = readdir(DIR);
        closedir(DIR);
        for (@names) {
                &doname($dir . "/" . $_) unless $_ eq "." || $_ eq "..";
        }
        return $dir;
}

sub doname {
        my($name) = @_;
        my($dev, $ino, $vol, $qta, $ddir);

        return warn "$name: $!\n" unless ($dev, $ino) = lstat($name);
        return &descend($name) if $ino & 1;
        return $name if -l $name || ! -d _;
        $vol = `$FS_LSM $name 2>&1`;
        die "Can't get info on $name:\n$vol" unless $vol =~ s/.*mount point for volume '(.*)'\n$/$1/;

	if ($qtawidth) {
	    $qta = `$FS_EXA $name 2>&1`;
	    $qta="(can't get info)" unless $qta =~ s/Volume status for vid = \d+ named .+\nCurrent disk quota is (.+)\nCurrent blocks used are (\d+)\nThe partition has \d+ blocks available out of \d+\n\n/$2\/$1/;
	    $qta =~ s/unlimited/0/;
	}
	else {
	    $qta = '';
	}

	printf "%4d %-${volwidth}s %-${qtawidth}s%s", ++$row, $vol, $qta, $name;

	if (defined $volmount{$vol}) {
	    if (defined $volstk{$vol}) {
		printf " (Possible loop, skipping!)\n";
	    }
	    else {
		printf " (Already visited, skipping!)\n";
	    }
	    $volmount{$vol} .= "    $name\n";
	    return $name;
	}

	printf "\n";
	$volmount{$vol} .= "    $name\n";
        return $name if $vol =~ /.*\.backup$/;
	# avoid other afs cells
	return $name if ($vol =~ /^.+:.+$/) && $notforeign;

	$volstk{$vol} = 1;
	$ddir = &descend($name);
	undef($volstk{$vol});
        return $ddir;
}

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

    $arg = shift(@ARGV);

    if ($arg eq '-foreign') {
	$notforeign = 0;
    } 
    elsif ($arg eq '-showquota') {
	$qtawidth = 19;
	$qtahead  = 'Blocks Used/Quota';
    } 
    elsif ($arg eq '-summary') {
	$summary = 1;
    } 
    else {
	&usage();
    } 
}

if (@ARGV) {

    printf "#Row %-${volwidth}s %-${qtawidth}s%s\n", "Volume Name", $qtahead, "Mounted-on";

    foreach (@ARGV) {
	s#(.+)/+$#$1#;
	$msg = `$FS_EXA $_ 2>&1`;
	$msg =~ s/fs:\s*//, warn($msg), next unless $? == 0;
	&doname($_);
    }

    if ($summary) {
	printf "\n\nVolume Mount Point Summary:\n\n";
	foreach $vol (sort keys %volmount) {
	    printf "$vol\n$volmount{$vol}\n";
	}
    }
}
else {
    &usage();
}

sub usage()
{
    print "Usage: $0 [-summary] [-foreign] [-showquota] <directory ...>\n";
    exit -1;
}
