#!/usr/bin/perl # # Report on filesystem space usage ... sort of an improved 'df' use strict; use warnings; use Number::Bytes::Human qw(format_bytes); use Filesys::DfPortable; use Text::Truncate; our $debug = 0; # Enable debugging messages our $width = `tput cols`; # Width of output; we hope to have something useful out of 'tput cols' # which seems to work for me. our $siunits = 0; # Whether to use SI units for Number::Bytes::Human our $blocksize = 1024; # Get a consistent block size our @mountpoints = getmounts("/etc/mtab"); push @mountpoints, getmounts("/etc/mnttab"); # And get the mountpoints. First is Linux and second is Solaris our @headings = ("Filesystem", "Size", "%Used", "%fslots", "Avail", "Rsrved", "Used"); our @widths = (-35, 7, 7, 8, 7, 7, 7); # Headings for each column together with their nominal width. Note that # negative widths means left justfied and not right justified. our %tput = ( "smso" => `tput smso`, "rmso" => `tput rmso` ); if (($width + 0) < 1) { $width = 80; # Just a sensible default in case things aren't working. The addition of # zero makes sure the test works. } else { $width = $width + 0; # Make numeric; gets rid of an extraneous \n } print "Number of mountpoints: $#mountpoints\n" if $debug; print "Width = $width\n" if $debug; outheadings($width); foreach my $mount (@mountpoints) { my $df = dfportable($mount, $blocksize); if ((defined($df)) && ($df->{blocks} > 0)) { # Not interested in fake filesystems ... yet outfs($mount, $df, $width); } else { print "No information for $mount\n" if $debug; } } # getmounts # # Go through /etc/mnttab and extract mount points sub getmounts { my $mnttab = pop(@_); my $in; my @mountpoints; open $in, "<$mnttab" or return (); # This deliberately doesn't die because we might want to try different # files. while (<$in>) { my @words = split; push @mountpoints, $words[1]; } return @mountpoints; } # outraw # # Output a series of strings according to their percentage share of # the width of the screen. # #sub outraw { # my $w = pop(@_); # my $strper; # while (@_) { # my $str = pop(@_); # my $width = int(pop(@_) * $w / 100); # #print "str=$str, width=$width\n" if $debug; # $str = truncstr($str, abs($width), "+"); # printf "%${width}s", $str; # } # print "\n"; #} # outraw # # Output a series of strings according to their minimum size; once the width # is consumed, and remaining columns are silently discarded; the intention is # that less useful columns are left until the end. sub outraw { my $w = pop(@_); print "Initial width=$w\n" if $debug; while (@_) { my $str = pop(@_); my $width = pop(@_); if ($width < $w) { $str = truncstr($str, abs($width), "+"); printf "%${width}s", $str; } $w = $w - abs($width); } print "\n"; print "Remaining width=$w\n" if $debug; } # outfs # # Display the filesystem output in a neatly formatted manner sub outfs { my $width = pop(@_); my $df = pop(@_); my $mount = pop(@_); my @words; # Remember: Last column first! push @words, ($widths[5], format_bytes($df->{bused} * $blocksize, si => $siunits)); push @words, ($widths[4], format_bytes(($df->{bfree} - $df->{bavail}) * $blocksize, si => $siunits)); push @words, ($widths[4], format_bytes($df->{bavail} * $blocksize, si => $siunits)); if (defined($df->{fper})) { push @words, ($widths[3], "$df->{fper}%"); } else { push @words, ($widths[3], "n/a"); } push @words, ($widths[2], "$df->{per}%"); push @words, ($widths[1], format_bytes($df->{blocks} * $blocksize, si => $siunits)); push @words, ($widths[0], $mount); outraw(@words, $width); } # outheadings # # Display the headings for each column using outraw in much the same way as outfs. sub outheadings { my $width = pop(@_); my @words; for (my $i = $#widths; $i > -1; $i--) { push @words, ($widths[$i], $headings[$i]); } print $tput{smso}; outraw(@words, $width); print $tput{rmso}; }