#!/usr/bin/perl -w ############################################################################# # durep - Disk Usage Report Generator # # # # Copyright (C) 2004 Damian Kramer (psiren@hibernaculum.net) # # # # You may distribute this program under the terms of the Artistic License. # # # # This program is distributed in the hope that it will be useful, but # # WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # Artistic License for more details. # ############################################################################# use MLDBM qw(DB_File Storable); use POSIX; use strict; ## Set these variables as appropriate. ## -------------------------------------------------- our $datadir = "/var/lib/durep"; # Filesystem path to the data files. our $css_file = "/server-manager/durep/style.css"; # URL to CSS file our $bar_image = "/server-manager/durep/bar.png"; # URL to image used in bar graph our $show_mtime = 1; # Show file modifcation time our $show_opts = 0; # Show options used ## -------------------------------------------------- ### NO USER-SERVICEABLE PARTS BEYOND THIS POINT ### our ($me, $data, @ancestors, @records, %input, $temp, $version, $top_node, $collated); our ($TYPE_FILE, $TYPE_DIR, $TYPE_EMPTY, $TYPE_COALESCED, $TYPE_COLLAPSED); $me = $ENV{SCRIPT_NAME}; $TYPE_FILE = 0; $TYPE_DIR = 1; $TYPE_EMPTY = 2; $TYPE_COALESCED = 4; $TYPE_COLLAPSED = 8; $version = "0.9"; $ENV{PATH} = "/bin:/usr/bin"; $top_node = {}; $collated = loadCollateFile($datadir); getInput(); if(%input) { fetchData(); displayData(); } else { displayList(); } # Return to system exit 0; sub getInput { if($ENV{REQUEST_METHOD} eq 'POST') { chomp($_ = ); } elsif($ENV{REQUEST_METHOD} eq 'GET') { $_ = $ENV{QUERY_STRING}; } else { return; } for $temp (split("&", $_)) { my ($var, $val) = split ('=', $temp); $val =~ s/\+/ /g; $val =~ s/%(..)/pack("H2", $1)/eg; if(defined $input{$var}) { $input{$var} .= "\0$val"; } else { $input{$var} = $val; } } } sub displayInput { print "Content-type: text/html\n\n"; my ($key, $val); print "SMESERVER Disk Usage Report"; print "

"; print ""; while(($key, $val) = each %input) { my $length = length $val; print "\n"; } print "
$key
[$length]
[$val]
"; print ""; } sub fetchData { my $root_node = {}; my $node; tie %{$root_node}, 'MLDBM', "$datadir/$collated->{$input{fid}}->{FILENAME}", O_RDONLY, 0640 or errorPage(); %{$data} = (%{$root_node->{DATA}}); %{$top_node} = (%{$root_node->{$input{nid}}}); $node = $top_node; while($node->{PARENT}) { my $tmp = {}; %{$tmp} = (%{$root_node->{$node->{PARENT}}}); unshift @ancestors, $tmp; $node = $tmp; } foreach $node (@{$top_node->{CHILDREN}}) { my $tmp = {}; %{$tmp} = (%{$root_node->{$node}}); push @records, $tmp; } @records = reverse sort sortBySize @records; untie %{$root_node}; } sub displayList { print "Content-type: text/html\n\n"; my $hash = sortCollateFile($collated); my ($key, $val); print qq{ Disk Usage Report

Disk Usage Report

}; foreach my $host (keys %{$hash}) { print "\n"; my $flip = 0; foreach my $e (reverse sort sortByDate @{$hash->{$host}}) { if($flip) { print ""; } else { print ""; } $flip = !$flip; print ""; print ""; printf "", $e->{DESC} || "-"; printf "", prettyFileSize($e->{SIZE}); printf "", prettyNum($e->{DIR_COUNT}); printf "", prettyNum($e->{FILE_COUNT}); printf "", prettyDate($e->{LAST_UPDATE}); print "\n"; } } # table to show df of all disk on main page print qq{
 PathDescriptionSizeDirsFilesDate
$host
 $e->{PATH}%s%s%s%s%s
}; my $dflist = `df -hP|grep -v 'Use%'|sed 's#^##g'`; $dflist =~ s/[ ]+/<\/td>
FilesystemSizedUsedAvailableUse %Mounted on
#g'|sed 's#\$#
/g; print $dflist; print qq{
}; } sub displayData { print "Content-type: text/html\n\n"; my ($key, $val); print qq{ Disk Usage Report ($data->{HOSTNAME})

Disk Usage Report ($data->{HOSTNAME})

"; printf "", prettyFileSize($top_node->{SIZE}); print "
[Home] }; foreach my $tmp (@ancestors) { printf "$tmp->{NAME}%s", $tmp->{ID}, (($tmp->{NAME} =~ m|\/$|) ? "" : "/"); } print "$top_node->{NAME}%s
"; print "\n"; print ""; print ""; print "" if $show_mtime; print ""; my $flip = 0; foreach my $node (@records) { my $percent = $top_node->{SIZE} ? ($node->{SIZE}/$top_node->{SIZE}*100) : 0; if($flip) { print ""; } else { print ""; } $flip = !$flip; print "", $percent); if($node->{TYPE} & $TYPE_DIR) { if($node->{TYPE} & $TYPE_EMPTY) { print ""; printf("", shortDate($node->{MTIME})) if $show_mtime; print ""; } else { printf("", $node->{DCOUNT}); printf("", $node->{FCOUNT}); printf("", shortDate($node->{MTIME})) if $show_mtime; print ""; } } elsif($node->{TYPE} & $TYPE_COALESCED) { printf "", $node->{FCOUNT}; printf("", shortDate($node->{MTIME})) if $show_mtime; print ""; } else { print ""; printf("", shortDate($node->{MTIME})) if $show_mtime; print ""; } print "\n"; } print "
SizePercentageDirsFilesModifiedFile
"; print prettyFileSize($node->{SIZE}); print ""; print barChart($percent); printf("%4.2f%%00%s$node->{NAME}/%d%d%s$node->{NAME}/ %d%s$node->{NAME}  %s$node->{NAME}
\n"; print "
"; printf "", scalar localtime($data->{LAST_UPDATE}); print ""; print "
%sGenerated by durep v. $version
\n"; if($show_opts && $data->{OPTIONS}) { print "
"; } print ""; } ### All this does is create an HTML table bar graph type thingy. sub barChart { my $percent = int($_[0]*2+0.5); my $rv = "
"; if($percent) { $rv .= ""; } else { $rv .= " "; } $rv .= "
"; return $rv; } # Generates a human readable file size string sub prettyFileSize { my $val = $_[0]; my $dtype = "b"; if($val >= 1024) { $val /= 1024; $dtype = "K"; } if($val >= 1024) { $val /= 1024; $dtype = "M"; } if($val >= 1024) { $val /= 1024; $dtype = "G"; } if($dtype eq "b") { return sprintf("%d%s", $val, $dtype); } else { return sprintf("%.1f%s", $val, $dtype); } } sub prettyDate { return POSIX::strftime("%T %a %b %e %Y", localtime $_[0]); } sub shortDate { if($_[0] < (time - 31536000)) { return POSIX::strftime("%b %e %Y", localtime $_[0]); } return POSIX::strftime("%b %e %H:%M", localtime $_[0]); } sub prettyNum { my $r = reverse shift; $r =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; return scalar reverse $r; } sub sortBySize { return $a->{SIZE} <=> $b->{SIZE}; } sub sortByDate { return $a->{LAST_UPDATE} <=> $b->{LAST_UPDATE}; } sub sortByPath { return $a->{PATH} cmp $b->{PATH}; } sub loadCollateFile { my $dir = shift; my %db; my $r; tie %db, 'MLDBM', "$dir/durep.cds", O_RDONLY, 0640 or errorPage(); foreach my $key (keys %db) { $r->{$key} = \%{$db{$key}}; } untie %db; return $r; } sub sortCollateFile { my $hash = shift; my $r; foreach my $key (keys %{$hash}) { my $hostname = $hash->{$key}->{HOSTNAME}; push @{$r->{$hostname}}, \%{$hash->{$key}}; } return $r; } sub errorPage { print "Content-type: text/html\n\n"; print qq{ Disk Usage Report

Durep encountered an error!

Please check that you have collated the files and that the permissions on them are correct.

}; exit 0; }