#!/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; no if $] >= 5.018, warnings => "experimental::smartmatch"; use autodie; use Derf::Visual 'GD_bar'; use Filesys::Df; use GD; use Getopt::Std; use Term::ANSIColor; my @mounts; my %opts; my $alpha; 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 show_df_console { my $mp_width = 10; 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 %04.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 = 32; my $h = @mounts * $spacing; my $w = 200; my $offset_left = 5; my $offset_top = 3; my $offset_right = 5; my $offset_free = $w - $offset_right - (6 * 6); my $bar_width = $w - $offset_left - $offset_right; my $bar_height = 10; my $bar_top = $offset_top + 13; my $im = GD::Image->new($w, $h); my $black = $im->colorAllocateAlpha( 0, 0, 0, $alpha); my $gray = $im->colorAllocateAlpha(127, 127, 127, $alpha); my $lgray = $im->colorAllocateAlpha(191, 191, 191, $alpha); my $white = $im->colorAllocateAlpha(255, 255, 255, $alpha); $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, $offset_left, $spacing * $i + $offset_top, $mount->[1], $black); $im->string(gdSmallFont, $offset_free, $spacing * $i + $offset_top, sprintf("%6s", format_size($mount->[4]->{'bavail'})), $black); $im->copy(GD_bar( width => $bar_width, height => $bar_height, alpha => $alpha, percent_filled => $percent, lined => 6, ), $offset_left, $spacing * $i + $bar_top, 0, 0, $bar_width, $bar_height); } open(my $out_fh, '>', '/tmp/vdf.png'); binmode $out_fh; print $out_fh $im->png(); close($out_fh); return; } getopts('Aa:cfgi:', \%opts); $alpha = $opts{'a'} // 0; open(my $mounts_fh, '<', '/proc/mounts'); while (my $line = <$mounts_fh>) { my ($device, $mountpoint, $type, $flags) = split(qr{ }, $line); my $df_ref = df($mountpoint, 1); if (not defined $df_ref) { next; } push(@mounts, [ $device, $mountpoint, $type, $flags, $df_ref ]); } close($mounts_fh); if (not $opts{'A'}) { @mounts = grep { $_->[0] !~ qr{ ^ ( (root|tmp)fs | none ) $ }x } @mounts; } if ($opts{'i'}) { my @ignored = split(qr{,}, $opts{'i'}); @mounts = grep { not ($_->[1] ~~ [@ignored]) } @mounts; } if ($opts{'c'}) { show_df_console(); } elsif ($opts{'g'}) { show_df_png(); } if ($opts{'f'}) { exec('feh', '/tmp/vdf.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.