SUMMARY: Listing disc space per user without running quota

From: Paul Key <paul_at_hsrc.org.uk>
Date: Wed, 9 Apr 1997 10:03:49 GMT

Here is a PERL script to do the job.

The author is Kjetil Torgrim Homme <kjetilho_at_ifi.uio.no>.

Thanks to everybody who replied.

Paul

The script:

#!/local/bin/perl

use Getopt::Std;

&init;

&dodir($dir);
&report;

&cleanup;

sub dodir {
    my (_at_dirs, $file, _at_stats);

    chdir ($_[0]) || return warn "can't chdir $_[0]: $!\n";
    opendir (DIR, ".") || return warn "can't open $_[0]: $!\n";
    _at_dirs = ();
    while ($file = readdir DIR) {
        next if $file eq "." || $file eq "..";

        _at_stats = lstat $file;
        next if $#stats == -1; # usually file removed under our feet
        
        # dev 0, ino 1, mode 2, nlink 3, uid 4, gid 5, rdev 6, size 7,
        # atime 8, mtime 9, ctime 10, blksize 11, blocks 12

        $uid = $stats[4];

        next if $uid == 65534 || $uid == 60001;

        $kb = $stats[12] / 2;

        ##
        ## To avoid miscalculating multiply linked files, we divide by
        ## the number of links. We don't do this for directories, since
        ## the other hardlinks are "." and ".." which we always skip.
        ##

        $kb /= $stats[3] if ! -d _;
        $du_byuid[$uid] += $kb;

        if ($opt_v) {
            $du1m_byuid[$uid] += $kb if ($stats[8] < $ago1months);
            $du2m_byuid[$uid] += $kb if ($stats[8] < $ago2months);
            $du3m_byuid[$uid] += $kb if ($stats[8] < $ago3months);
        }

        next if $opt_x && $stats[0] != $device;

        ##
        ## Remember to check this later, unless it's a .snapshot directory
        ## on a NetApp.
        ##

        push (_at_dirs, $file) if (-d _ && ($uid || $file ne ".snapshot"));
    }
    closedir (DIR);

    for (_at_dirs) {
        &dodir ($_);
    }
    chdir ("..") || die "can't chdir .. from $_[0]: $!\n";
}

sub report {
    my ($i, %used, _at_report, $uid);

    ##
    ## Build an array of users with non-zero usage
    ##

    for ($i = 0; $i <= $#du_byuid; $i++) {
        next unless defined $du_byuid[$i] && $du_byuid[$i] > 0;
        $used{$user_byuid[$i]} = $du_byuid[$i];
    }

    ##
    ## Sort it into descending order
    ##

    _at_report = sort { $used{$b} <=> $used{$a} } keys %used;

    for (_at_report) {
        if ($opt_v) {
            $uid = $uid_byuser{$_};
            printf("%7d\t%-8s\t%7d %7d %7d\n", $used{$_}, $_,
                   $du1m_byuid[$uid], $du2m_byuid[$uid], $du3m_byuid[$uid]);
        } else {
            printf("%7d %s\n", $used{$_}, $_);
        }
    }
}

sub usage {
    my ($me);
    $me = $0; $me =~ s,.*/,,;
    print STDERR
"Usage: $me [options] [directory]
Options are:
  -v display three columns containing the number of blocks not
             accessed in the last 30, 60, and 90 days.
  -n NETAPP connect to NETAPP and create a snapshot before starting.
  -x stay in one filesystem.\n";
    exit (64);
}

##
## init sets the following globals:
## $dir Directory to investigate
## _at_du_byuid Total disk usage
## _at_user_byuid Lookup username by numeric uid
## %uid_byuser Lookup numeric uid by username
##
## $opt_n Name of NetApp
## $snap Name of snapshot
## $opt_v Boolean
## $ago{1,2,3}months Times for comparing file age
## _at_du{1,2,3}m_byuid Accumulators for several file ages
## $opt_x Boolean
## $device Device number to investigate
##

sub init {
    &usage unless getopts ('vxn:');

    $SIG{'INT'} = $SIG{'TERM'} = $SIG{'HUP'} = 'cleanup';

    $dir = $#ARGV == 0 ? $ARGV[0] : ".";
    print "$dir:\n";

    if ($opt_v) {
        $ago1months = time - (1 * 30 * 86400);
        $ago2months = time - (2 * 30 * 86400);
        $ago3months = time - (3 * 30 * 86400);
    }

    ##
    ## Create a snapshot.
    ##

    if ($opt_n) {
        $snap = "quot.$dir.$$"; $snap =~ s/[^\w\d]+/./g;
        system ("rsh -n $opt_n snap create $snap >&2 &");
        $dir .= "/.snapshot/$snap";
    }
    
    ##
    ## Prime the arrays to avoid undefined values.
    ##

    setpwent;
    while (_at_u = getpwent) {
        next if $u[2] == 65534 || $u[2] == 60001;
        $user_byuid[$u[2]] = $u[0];
        $uid_byuser{$u[0]} = $u[2];
            
    }
    endpwent;

    ##
    ## Fill in unknown values
    ##

    local ($i);
    for ($i = 0; $i <= $#user_byuid; $i++) {
        $du_byuid[$i] = 0;
        $du1m_byuid[$i] = $du2m_byuid[$i] = $du3m_byuid[$i] = 0 if $opt_v;

        next if defined $user_byuid[$i];

        $user_byuid[$i] = "#$i";
        $uid_byuser{"#$i"} = $i;
    }

    ##
    ## Wait until the snapshot has been developed.
    ##

    if ($opt_n) {
        while (! -d $dir) {
            sleep (1);
        }
    }

    if ($opt_x) {
        $device = (lstat ($dir))[0];
    }

}

sub cleanup {
    if ($opt_n && defined $snap) {
        # system ("rsh $opt_n snap delete $snap >&2");
        system ("rsh $opt_n snap delete $snap > /dev/null");
    }
    exit (0);
}

_____________________________________________________________________

    |R| A Message from Paul Key: Reginet Systems Developer
    |E| at
    |G| The Institute of Public & Environmental Health,
    |I| The University of Birmingham,
    |N| http://www.hsrc.org.uk
    |E| E-mail : Paul_at_hsrc.org.uk
    |T| Telephone : 0 (+44) 121 456 5600 Ext. 59875
    | | Fax / Messages : 0 (+44) 121 454 6876
______________________________________________________________________
Received on Wed Apr 09 1997 - 12:16:36 NZST

This archive was generated by hypermail 2.4.0 : Wed Nov 08 2023 - 11:53:36 NZDT