#!/usr/bin/env perl ## Copyright © 2010 by Daniel Friesel ## License: WTFPL ## 0. You just DO WHAT THE FUCK YOU WANT TO. use strict; use warnings; use 5.010; use autodie; use Filesys::Df; use GD; use Getopt::Std; use Term::ANSIColor; my @mounts; my %opts; sub format_size { my ($bytes) = @_; my @postfix = (' ', 'k', 'M', 'G', 'T'); while ($bytes > 1000) { $bytes /= 1000; shift @postfix; } return sprintf('%3.1f%s', $bytes, $postfix[0]); } sub bar_console { my ($percent, $width) = @_; my $vlen = sprintf("%d", $width * $percent / 100); return sprintf( '[%s%s]', '=' x ($vlen), ' ' x ($width - $vlen), ); } sub bar_png { my ($percent, $w, $h) = @_; my $bar = GD::Image->new($w, $h); my $black = $bar->colorAllocate( 0, 0, 0); my $gray = $bar->colorAllocate(127, 127, 127); my $lgray = $bar->colorAllocate(191, 191, 191); my $white = $bar->colorAllocate(255, 255, 255); my $vwidth = sprintf("%d", ($w- 2) * $percent / 100); $bar->rectangle(0, 0, $w - 1, $h - 1, $gray); $bar->filledRectangle(1, 1, $w - 2, $h - 2, $white); $bar->filledRectangle(1, 1, $vwidth, $h - 2, $lgray); return $bar; } sub show_df_console { my $mp_width = 0; foreach my $mount (@mounts) { my $this_width = length($mount->[1]); if ($this_width > $mp_width) { $mp_width = $this_width; } } my $h_format = "%-${mp_width}s %6s %6s %6s %4s%% %20s %s\n"; my $l_format = "%-${mp_width}s %6s %6s %6s %2.1f%% %20s %s\n"; print color('yellow'); printf( $h_format, qw{Mountpoint Size Used Avail Use}, q{}, q{Filesystem}, ); print color('reset'); foreach my $mount (@mounts) { # $mount->[4]->{'per'} (provided by Filesys::Df) is inaccurate my $percent = $mount->[4]->{'used'} * 100 / $mount->[4]->{'blocks'}; printf( $l_format, $mount->[1], format_size($mount->[4]->{'blocks'}), format_size($mount->[4]->{'used'}), format_size($mount->[4]->{'bavail'}), $percent, bar_console($percent, 18), $mount->[0], ); } return; } sub show_df_png { my $spacing = 40; my $h = @mounts * $spacing; my $w = 220; my $im = GD::Image->new($w, $h); my $black = $im->colorAllocate( 0, 0, 0); my $gray = $im->colorAllocate(127, 127, 127); my $lgray = $im->colorAllocate(191, 191, 191); my $white = $im->colorAllocate(255, 255, 255); $im->rectangle(0, 0, $w - 1, $h - 1, $gray); $im->filledRectangle(1, 1, $w - 2, $h - 2, $white); for my $i (0 .. $#mounts) { my $mount = $mounts[$i]; my $percent = $mount->[4]->{'used'} * 100 / $mount->[4]->{'blocks'}; $im->string(gdSmallFont, 10, $spacing * $i + 7, $mount->[1], $black); $im->string(gdSmallFont, $w - 46, $spacing * $i + 7, sprintf("%6s", format_size($mount->[4]->{'bavail'})), $black); $im->copy(bar_png($percent, $w - 20, 10), 10, $spacing * $i + 20, 0, 0, $w - 20, 10); } open(my $out_fh, '>', '/tmp/vdf.png'); binmode $out_fh; print $out_fh $im->png(); close($out_fh); return; } getopts('acg', \%opts); open(my $mounts_fh, '<', '/proc/mounts'); while (my $line = <$mounts_fh>) { push(@mounts, [split(qr{ }, $line)]); } close($mounts_fh); foreach my $mount (@mounts) { my ($device, $mountpoint, $type, $flags) = @{$mount}; my $df_ref = df($mountpoint, 1); if (not defined $df_ref) { next; } $mount->[4] = $df_ref; } if (not $opts{'a'}) { @mounts = grep { $_->[0] !~ qr{ ^ ( (root|tmp)fs | none ) $ }x } @mounts; } if ($opts{'c'}) { show_df_console(); } elsif ($opts{'g'}) { show_df_png(); } __END__ =head1 NAME =head1 SYNOPSIS =head1 DESCRIPTION =head1 OPTIONS =head1 EXIT STATUS =head1 CONFIGURATION =head1 DEPENDENCIES =head1 BUGS AND LIMITATIONS =head1 AUTHOR Copyright (C) 2010 by Daniel Friesel Ederf@finalrewind.orgE =head1 LICENSE 0. You just DO WHAT THE FUCK YOU WANT TO.