[comp.lang.perl] Useful "du"

clements@bbn.com (Bob Clements) (03/29/90)

In article <7514@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>On the other hand, you can just mutate the following into what you want.
> [...]
>Larry
>
>sub dodir {
> ...
>}


Thanks, Larry.  I mutated it into the attached "useful du" which I called
"used".  It looks down a directory tree and prints out (almost) what "du"
prints, but filters it into useful info.  You tell it a depth and a size.
It prints out all directories to the given depth and then anything below
that level if it is as big as the given size.

Basically it tells me "Where the heck has all the space gone on u0?".
Usage: used /nfs/whizbang/u0 1 2000
gives you the top level of directories in u0 (even if they're not
big) and all the directories lower than that that are eating more
than 2 megabytes.

It's my first perl program - be gentle :-)
It doesn't deal with hard links, they'll be multiple-counted.

Bob Clements, K1BC, clements@bbn.com
----------------------------------------------slash/chop here
#!/usr/bin/perl

( $#ARGV != 2 ) && die "Usage: $0 <srcdir> <printdepth> <size_threshold>\n" ;

$srcdir = shift ;
$printdepth = shift ;
$thresh = shift ;
$curdepth = 0;

chdir($srcdir) || die "Can't chdir to $srcdir" ;
$topn = &dodir($srcdir);

print "Total space allocated at and below $srcdir is $topn K.\n";

sub dodir {
    local($intn,$belown) = 0;
    local($dir) = @_;
    local($name,$dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size);
    local($atime,$mtime,$ctime,$blksize,$blocks);

    if (opendir(DIR,'.')) {
        local(@filenames) = sort readdir(DIR);
        closedir(DIR);
    
        for (@filenames) {
            next if $_ eq '.';
            next if $_ eq '..';
	    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
	     $atime,$mtime,$ctime,$blksize,$blocks) = lstat($_);
            next if ($mode & 0170000) eq 0120000;   # don't follow symlinks

            $name = "$dir/$_";
            $intn += $blocks/2;     # report 1K blocks, not 512 byte blocks

            if (($mode & 0170000) == 0040000) {
                if (chdir $_) {
    		    $curdepth++;
                    $belown = &dodir($name);
                    $intn += $belown;
                    if (($curdepth <= $printdepth) || ($belown >= $thresh)) {
                        print "$belown\t$name\n";
                    }
    		    $curdepth--;
                    chdir '..';
    	        } else {
    	            print "*** Can't cd to $name\n";
    	        }
	    }
        }
    } else {
        print "*** Can't open $dir\n";
    }
    $intn;
}
----------------------------------------------slash/chop here

bengtl@thep.lu.se (Bengt Larsson) (03/30/90)

In article <54235@bbn.COM> clements@BBN.COM writes:

[the "used" perl script here]

I'm a beginner with Perl, so forgive me!

I tried the "used" script and it doesn't work for me. The error seems
to be in these two lines:

>	    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
>	     $atime,$mtime,$ctime,$blksize,$blocks) = lstat($_);

When I run this through the debugger (perl -d) all the variables get
defined, except "$blksize" and "$blocks", which appear to be empty
(nothing shows in the "p" command). Of course, the sum of blocks reported
will then be 0 (zero) for all directories. Not very useful.

This was with Perl patchlevel 15 on a 3B2 running System V 3.2. Standard
cc used for compile (no shared libraries).

Is this a bug maybe? 

Regards,
-- 
Bengt Larsson - Theor. Psysics, Lund University, Sweden - bengtl@thep.lu.se

bengtl@thep.lu.se (Bengt Larsson) (03/30/90)

In message <9003300249.AA14755@thep.lu.se> I wrote:

>This was with Perl patchlevel 15 on a 3B2 running System V 3.2. Standard
>cc used for compile (no shared libraries).

It was Unix version 3.0, sorry. 

Anyway - I get the same result now with Perl patchlevel 18. 
-- 
Bengt Larsson - Theor. Psysics, Lund University, Sweden - bengtl@thep.lu.se