Article Figure 1 Listing 1 nov2006.tar

Listing 1 program output

    =1=    #!/usr/bin/perl
    =2=    use strict;
    =3=    use warnings;
    =4=    
    =5=    use constant ONEOVERLOG2 => 1/log(2);
    =6=    
    =7=    use File::Find;
    =8=    use Template;
    =9=    
    =10=    my %sums;
    =11=    ## $sums{$uid}[$log_2_blocks]{blocks} += $blocks;
    =12=    ## $sums{$uid}[$log_2_blocks]{count} ++;
    =13=    
    =14=    @ARGV = qw(.) unless @ARGV;
    =15=    
    =16=    my %seen;
    =17=    
    =18=    find sub {
    =19=      return if -l;
    =20=      return unless -f _ or -d _;
    =21=      my @stat = stat(_) or return;
    =22=      my ($dev, $ino, $uid, $blocks) = @stat[0, 1, 4, 12];
    =23=      return if $seen{"$dev $ino"}++;
    =24=    
    =25=      my $slot = $blocks ? log($blocks) * ONEOVERLOG2 : 0;
    =26=      $sums{$uid}[$slot]{blocks} += $blocks;
    =27=      $sums{$uid}[$slot]{count}++;
    =28=    }, @ARGV;
    =29=    
    =30=    my %usernames = map { $_ => scalar getpwuid $_ } keys %sums;
    =31=    my @labels;
    =32=    for (values %sums) {
    =33=      while (@labels < @$_) {
    =34=        push @labels, 2**@labels;
    =35=      }
    =36=    }
    =37=    
    =38=    my %VARS = 
    =39=      (sums => \%sums,
    =40=       usernames => \%usernames,
    =41=       labels => \@labels);
    =42=    
    =43=    Template->new({ POST_CHOMP => 1 })
    =44=      ->process(\<<'END_OF_TEMPLATE', \%VARS) or die Template->error;
    =45=    [% BLOCKSIZE = 1024 %]
    =46=    <style type="text/css">
    =47=    th, td {
    =48=      margin: 0; border: 1px dotted black; padding: 0.2em; text-align: center;
    =49=    }
    =50=    </style>
    =51=    [% MACRO nice(n) BLOCK;
    =52=      IF n >= 1073741824 * 9.995;
    =53=        n / 1073741824 | format('%dG');
    =54=      ELSIF n >= 1073741824;
    =55=        n / 1073741824 | format('%.2gG');
    =56=      ELSIF n >= 1048576 * 9.995;
    =57=        n / 1048576 | format('%dM');
    =58=      ELSIF n >= 1048576;
    =59=        n / 1048576 | format('%.2gM');
    =60=      ELSIF n >= 1024 * 9.995;
    =61=        n / 1024 | format('%dK');
    =62=      ELSIF n >= 1024;
    =63=        n / 1024 | format('%.2gK');
    =64=      ELSE;
    =65=        n;
    =66=      END;
    =67=    END %]
    =68=    [% MACRO bc(b,c) BLOCK %]
    =69=    <td>[% bytes = b * BLOCKSIZE; nice(bytes) %]<br/>[% nice(c) %]</td>
    =70=    [% END %]
    =71=    [% FOR uid = sums.keys.nsort %]
    =72=    [%   IF loop.first %]
    =73=    <table>
    =74=    [%     FOR label = labels %]
    =75=    [%       IF loop.first %]
    =76=    <tr><th>User</th>
    =77=    [%       END %]
    =78=    <th>[% label_bytes = label * BLOCKSIZE; nice(label_bytes) %]</th>
    =79=    [%       IF loop.last %]
    =80=    <th>Total</th>
    =81=    </tr>
    =82=    [%       END %]
    =83=    [%     END %]
    =84=    [%   END %]
    =85=    [%   labels_max = labels.max %]
    =86=    [%   FOR column = [0..labels_max] %]
    =87=    [%     cell = sums.$uid.$column %]
    =88=    [%     IF loop.first %]
    =89=    [%       total_blocks = 0; total_count = 0 %]
    =90=    <tr><th>[% usernames.$uid || "?"; " ("; uid; ")" %]</th>
    =91=    [%     END %]
    =92=    [%     IF cell %]
    =93=    [%       total_blocks = total_blocks + cell.blocks %]
    =94=    [%       total_count = total_count + cell.count %]
    =95=    [%       bc(cell.blocks, cell.count) %]
    =96=    [%     ELSE %]
    =97=    <td> </td>
    =98=    [%     END %]
    =99=    [%     IF loop.last %]
    =100=    [%       bc(total_blocks, total_count) %]
    =101=    </tr>
    =102=    [%     END %]
    =103=    [%   END %]
    =104=    [%   IF loop.last %]
    =105=    </table>
    =106=    [%   END %]
    =107=    [% END %]
    =108=    END_OF_TEMPLATE