[comp.lang.perl] 'Profil' script -- Comments?

shein@ferdowsi.berkeley.edu (Soren Hein) (05/29/91)

The below script, 'profil', is intended to print some statistics on
user accounts. It recursively goes through the directory tree from
the invocation point, and records file sizes along with last access
date. It is heavily based on an example from the Scriptures.

'Profil' is my first perl script, and is therefore written for its
educational value rather than its usefulness. I post it for two
reasons:

1. To hopefully get some hints on how to think Perl.
2. To ask what statistics on accounts would really be useful to know.
   (I'm a mere mortal, not a sysadmin. Hence also the warn's rather
   than die's.)

/Soren

------
Sample output:
Days    files        %files            M          avg.K        %compr.
  1       504         11.88        1.196           2.37          0.00
  2         3          0.07        0.217          72.29          0.00
  3         2          0.05        0.015           7.46          0.00
  7       369          8.69        1.938           5.25         18.26
 14       313          7.38        3.898          12.45         12.89
 21       178          4.19        1.000           5.62         31.92
 30       490         11.55        1.687           3.44         60.87
 60       350          8.25        2.608           7.45         16.88
 90      1821         42.91        7.299           4.01         23.08
120        25          0.59        0.120           4.78        100.00
150        35          0.82        0.177           5.05        100.00
180         1          0.02        0.004           3.65        100.00
270       141          3.32        0.483           3.42        100.00
360        12          0.28        0.259          21.59        100.00
----------------------------------------------------------------------
         4244        100.00       20.900           4.92         25.69

---------

#!/usr/local/bin/perl

# Soren Hein, shein@robotics.berkeley.edu, 05/28/91.
# Rudimentary account statistics program. Recursive part adapted from
# the Book, p. 56f. Works with 4.003 at least.

require "pwd.pl";

# Initialize.
@daylimits = (1, 2, 3, 7,14,21,30,60,90,120,150,180,270,360,100000);
@numfiles  = (0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,     0);
@sizes     = (0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,     0);
@compr     = (0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,     0);
&initpwd;

# Start at the top.
&dodir('.');

# Add up some totals.
$totf = $totsiz = $totcom = 0;
for ($i = 0; $i <= $#numfiles; ++$i)
{
  $totf   += $numfiles[$i];
  $totsiz += $sizes[$i];
  $totcom += $compr[$i];
}

# Print out summary.
print "Days    files        %files            M",
      "          avg.K        %compr.\n";
for ($i = 0; $i <= $#numfiles; ++$i) 
{
  printf "%3d     %5d    %10.2f     %8.3f     %10.2f    %10.2f\n",
    $daylimits[$i], $numfiles[$i], 100 * $numfiles[$i] / $totf,
    $sizes[$i] / ( 1000 * 1000 ) , $sizes[$i]/( 1000 * $numfiles[$i] ), 
    100 * $compr[$i] / $sizes[$i]
  unless (($numfiles[$i] == 0) || $sizes[$i] == 0 || $totf == 0);
}
print "---------------------------------------",
      "-------------------------------\n";
printf "        %5d    %10.2f     %8.3f     %10.2f    %10.2f\n",
  $totf, 100.00, $totsiz / (1000*1000), $totsiz / (1000 * $totf),
  100 * $totcom / $totsiz;

sub dodir
{
  # Get arguments.
  local($dir, $nlink) = @_;

  # Declare local variables.
  local($dev, $ino, $mode, $subcount);

  # At the top level, we need to find nlink ourselves.
  ($dev, $ino, $mode, $nlink) = stat('.') unless $nlink;

  # Get the list of files in the current directory.
  if ( !(opendir(DIR, '.')) )
  {
    warn "Can't open $dir.";
  }
  else
  {
    local(@filenames) = readdir(DIR);
    closedir(DIR);

    if ($nlink == 2) 
    {  # This directory has no subdirectories.
      for (@filenames) 
      {
        next if $_ eq '.';
        next if $_ eq '..';
        $name = $_;
	# Count everything but symbolic links.
        if (!(-l $name)) { &register($name); }
      }
    }
    else 
    {  # This directory has subdirectories.
      $subcount = $nlink - 2;
      for (@filenames) 
      {
        next if $_ eq '.';
        next if $_ eq '..';
        $name = "$_";
	# Count everything but symbolic links.
        if (!(-l $name)) { &register($name); }
    
        next if $subcount == 0; # Seen all the subdirectories?

        # Get link count and check for directoriness.
        ($dev, $ino, $mode, $nlink) = lstat($_);
        next unless -d _;

        # It really is a directory, so do it recursively.
        if ( !(&chdir($_)) )
	{
	  warn "Can't cd to $name";
	}
	else
	{
          &dodir($name, $nlink);
          &chdir('..');
        }
        --$subcount;
      }
    }
  }
}
    
sub register 
{
  local($name) = @_;
  local($acctime) = -A $name;
  local($i) = 0;

  # Find time slot.
  while ($acctime > $daylimits[$i]) 
  {
    ++$i;
  }

  ++$numfiles[$i];
  $size = -s $name;
  $sizes[$i] += $size;

  # Is the file compressed?
  if ($name =~ m/(\w+)*\.Z$/) { $compr[$i] += $size; }
}