#!/usr/bin/perl use strict; use warnings; ############################################################################## # Copyright (C) 2003 Rohan Romanus Almeida # email: arcofdescent@gmail.com # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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 # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## # $Id: ibmonitor,v 1.25 2004/12/17 19:02:54 arc_of_ascent Exp $ use Time::HiRes qw/usleep gettimeofday tv_interval/; use Getopt::Long; use Term::ANSIColor; use Data::Dumper; $| = 1; # variables my $debug = 0; my $debug_file = 'ibmonitor-debug.log'; my $version = '1.3'; my $useReadKey = 0; my $firstpass = 1; my $avgpass; my @proc_data = (); my @tmp = (); my $clearstr = `clear`; my $interface = {}; my $interfaces_all = {}; my @interface_names = (); my @interface_names_copy = (); my %cmd_options = (); my ($inter, $direction); my $inputkey; my $key_mess = ''; my $maxbytes_cnt = (2**32) - 1; my $start_time; my %colors = (); my %movers = (); my $elapsed_time; my $ostr; my $ihelp = 0; my $ihelp_flg = 0; my ($i, @index); my ($t0, $t1, $t0_t1); # functions sub print_usage(); sub print_help(); sub create_interface($); sub get_proc_data(); sub trim($); sub alignstr($$$); sub init_interfaces_all(); sub reset_all(); sub debug_it($); sub show_help(); sub quit_it(); sub adjust_unit($); sub get_run_time($); sub process_userkey($); sub order_interfaces(); # Check for installation of Term-ReadKey module eval q/use Term::ReadKey;/; if (!$@) { $useReadKey = 1; } if ($debug) { open FH, ">$debug_file" or die "Can't write $debug_file in current directory: $!"; close FH; } %colors = ( 'max' => 'Red', 'avg' => 'Green', 'data' => 'Magenta', ); %cmd_options = ( 'bits' => 0, 'bytes' => 0, 'avg' => 0, 'max' => 0, 'interval' => 2, 'colors' => 1, 'data' => 0, 'help' => 0, 'version' => 0, 'dev' => '', 'file' => '/proc/net/dev', ); %movers = ( 'init' => 0, 'num' => 0, 'dir' => 0, ); # Parse command line options my $result = GetOptions ( 'bits' => \$cmd_options{'bits'}, 'bytes' => \$cmd_options{'bytes'}, 'avg' => \$cmd_options{'avg'}, 'max' => \$cmd_options{'max'}, 'interval=i' => \$cmd_options{'interval'}, 'colors!' => \$cmd_options{'colors'}, 'data' => \$cmd_options{'data'}, 'help' => \$cmd_options{'help'}, 'version' => \$cmd_options{'version'}, 'dev=s' => \$cmd_options{'dev'}, 'file=s' => \$cmd_options{'file'}, ); if (not $result) { print_usage(); exit 1; } if ($cmd_options{'interval'} == 0) { print STDERR "0 not allowed as interval.\n"; print_usage(); exit 1; } if (not -e $cmd_options{'file'}) { print STDERR 'file '.$cmd_options{'file'}.' does not exist.'."\n"; print STDERR "ibmonitor requires the /proc/net/dev file.\n"; print STDERR "See the README file provided with ibmonitor.\n"; exit 1; } if (`file $cmd_options{file}` !~ /empty/) { print STDERR "$cmd_options{file} does not appear to be a valid filetype\n"; exit 1; } if ($cmd_options{'help'}) { print_help(); exit 1; } if ($cmd_options{'version'}) { print STDERR "ibmonitor version $version\n"; exit 1; } if ($cmd_options{'bits'} == 0 && $cmd_options{'bytes'} == 0) { $cmd_options{'bits'} = 1; } init_interfaces_all(); $start_time = time(); # Change to raw mode. # ie. Disable control keys, and enables us to read a single keystroke if ($useReadKey) { eval q/ReadMode 'raw';/; } # Start the never-ending story! while (1) { $ostr = sprintf $clearstr; # print header $ostr .= sprintf alignstr('Interface', 10, 'r'); if ($cmd_options{'bits'} == 1 && $cmd_options{'bytes'} == 1) { $ostr .= sprintf alignstr('Received ', 22, 'r'); $ostr .= sprintf alignstr('Sent ', 22, 'r'); $ostr .= sprintf alignstr('Total ', 22, 'r'); $ostr .= sprintf "\n"; $ostr .= sprintf alignstr(' ', 10, 'r'); for (1 .. 3) { $ostr .= sprintf alignstr('Kbps', 12, 'r'); $ostr .= sprintf alignstr('KBps', 10, 'r'); } } elsif ($cmd_options{'bits'} == 1) { $ostr .= sprintf alignstr('Received', 12, 'r'); $ostr .= sprintf alignstr('Sent', 12, 'r'); $ostr .= sprintf alignstr('Total', 12, 'r'); $ostr .= sprintf "\n"; $ostr .= sprintf alignstr(' ', 10, 'r'); for (1 .. 3) { $ostr .= sprintf alignstr('Kbps', 12, 'r'); } } elsif ($cmd_options{'bytes'} == 1) { $ostr .= sprintf alignstr('Received', 10, 'r'); $ostr .= sprintf alignstr('Sent', 10, 'r'); $ostr .= sprintf alignstr('Total', 10, 'r'); $ostr .= sprintf "\n"; $ostr .= sprintf alignstr(' ', 10, 'r'); for (1 .. 3) { $ostr .= sprintf alignstr('KBps', 10, 'r'); } } $ostr .= sprintf "\n\n"; # Get data from /proc and populate interfaces hash @proc_data = get_proc_data(); $t0 = [gettimeofday]; for (@proc_data) { ($tmp[0], $tmp[1]) = map trim($_), split /:/; # Check if user wants to see some particular interface only (ie. --dev) if ($tmp[0] =~ /($cmd_options{'dev'})/) { create_interface($tmp[0]) if (not exists $interface->{$tmp[0]}); push @interface_names, $tmp[0] if (not grep /^$tmp[0]$/, @interface_names); $interface->{$tmp[0]}{'Received'}{'New'} = (split /\s+/, $tmp[1])[0]; $interface->{$tmp[0]}{'Sent'}{'New'} = (split /\s+/, $tmp[1])[8]; } } foreach $inter (keys %{$interface}) { delete $interface->{$inter} if (not grep /^$inter$/, @interface_names); } foreach $inter (@interface_names) { if (not grep /^$inter$/, @interface_names_copy) { push @interface_names_copy, $inter; } } # Arrange interface_names array according to user sort @index = (); for ($i=0;$i{$_}{'Received'}{'Old'} = $interface->{$_}{'Received'}{'New'}; $interface->{$_}{'Sent'}{'Old'} = $interface->{$_}{'Sent'}{'New'}; } $firstpass = 0; $avgpass = 1; @interface_names = sort @interface_names; if ($debug) { debug_it('Inside firstpass conditional:'); debug_it('Interval: '.$cmd_options{'interval'}); debug_it(Dumper($interface->{'ppp0'}{'Received'})); } } else { # reset interfaces_all hash foreach $direction (keys %{$interfaces_all}) { $interfaces_all->{$direction}{'Bandwidth'}{'Bps'} = 0; $interfaces_all->{$direction}{'Bandwidth'}{'KBps'} = 0; $interfaces_all->{$direction}{'Bandwidth'}{'Kbps'} = 0; } foreach $inter (@interface_names) { foreach $direction ('Received', 'Sent') { $interface->{$inter}{$direction}{'Bandwidth'}{'Bps'} = ($interface->{$inter}{$direction}{'New'} - $interface->{$inter}{$direction}{'Old'}) / $cmd_options{'interval'}; # Take care of negative values obtained, # due to the byte counter overflowing if ($interface->{$inter}{$direction}{'Bandwidth'}{'Bps'} < 0) { $interface->{$inter}{$direction}{'Bandwidth'}{'Bps'} = ($maxbytes_cnt - $interface->{$inter}{$direction}{'Old'} + $interface->{$inter}{$direction}{'New'}) / $cmd_options{'interval'}; } # Put new into old $interface->{$inter}{$direction}{'Old'} = $interface->{$inter}{$direction}{'New'}; } # Calulate total of received and sent $interface->{$inter}{'Total'}{'Bandwidth'}{'Bps'} = $interface->{$inter}{'Received'}{'Bandwidth'}{'Bps'} + $interface->{$inter}{'Sent'}{'Bandwidth'}{'Bps'}; foreach $direction (keys %{$interface->{$inter}}) { # Bandwidth in KBps $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'} = sprintf('%.2f', $interface->{$inter}{$direction}{'Bandwidth'}{'Bps'} / 1024); # Max Bandwidth in KBps $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'KBps'} = sprintf( '%.2f', ( $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'} > $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'KBps'}) ? $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'} : $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'KBps'} ); # Total data in KB $interface->{$inter}{$direction}{'Amount'}{'KB'} = sprintf('%.2f', $interface->{$inter}{$direction}{'Amount'}{'KB'} + $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'} * $cmd_options{'interval'}); # Average bandwidth in KBps $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'KBps'} = sprintf('%.2f', $interface->{$inter}{$direction}{'Amount'}{'KB'} / get_run_time('s')); # Values in Kbps $interface->{$inter}{$direction}{'Bandwidth'}{'Kbps'} = sprintf('%.2f', $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'} * 8); $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'Kbps'} = sprintf('%.2f', $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'KBps'} * 8); $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'Kbps'} = sprintf('%.2f', $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'KBps'} * 8); } # Sum of all interfaces foreach $direction (keys %{$interfaces_all}) { $interfaces_all->{$direction}{'Bandwidth'}{'KBps'} = sprintf('%.2f', $interfaces_all->{$direction}{'Bandwidth'}{'KBps'} + $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'}); $interfaces_all->{$direction}{'Bandwidth'}{'Kbps'} = sprintf('%.2f', $interfaces_all->{$direction}{'Bandwidth'}{'Kbps'} + $interface->{$inter}{$direction}{'Bandwidth'}{'Kbps'}); } # Display the interface stats $ostr .= sprintf alignstr(" $inter", 10, 'l'); foreach $direction (sort keys %{$interface->{$inter}}) { # Bandwidth $ostr .= sprintf alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Kbps'}, 12, 'r') if ($cmd_options{'bits'}); $ostr .= sprintf alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'KBps'}, 10, 'r') if ($cmd_options{'bytes'}); } $ostr .= sprintf "\n"; # Display the max stats if ($cmd_options{'max'}) { if ($cmd_options{'colors'}) { $ostr .= sprintf colored alignstr('|---- Max', 10, 'r'), $colors{'max'}; foreach $direction (sort keys %{$interface->{$inter}}) { $ostr .= sprintf colored alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'Kbps'}, 12, 'r'), $colors{'max'} if ($cmd_options{'bits'}); $ostr .= sprintf colored alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'KBps'}, 10, 'r'), $colors{'max'} if ($cmd_options{'bytes'}); } } else { $ostr .= sprintf alignstr('|---- Max', 10, 'r'); foreach $direction (sort keys %{$interface->{$inter}}) { $ostr .= sprintf alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'Kbps'}, 12, 'r') if ($cmd_options{'bits'}); $ostr .= sprintf alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Max'}{'KBps'}, 10, 'r') if ($cmd_options{'bytes'}); } } $ostr .= sprintf "\n"; } # Display the avg stats if ($cmd_options{'avg'}) { if ($cmd_options{'colors'}) { $ostr .= sprintf colored alignstr('|---- Avg', 10, 'r'), $colors{'avg'}; foreach $direction (sort keys %{$interface->{$inter}}) { $ostr .= sprintf colored alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'Kbps'}, 12, 'r'), $colors{'avg'} if ($cmd_options{'bits'}); $ostr .= sprintf colored alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'KBps'}, 10, 'r'), $colors{'avg'} if ($cmd_options{'bytes'}); } } else { $ostr .= sprintf alignstr('|---- Avg', 10, 'r'); foreach $direction (sort keys %{$interface->{$inter}}) { $ostr .= sprintf alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'Kbps'}, 12, 'r') if ($cmd_options{'bits'}); $ostr .= sprintf alignstr( $interface->{$inter}{$direction}{'Bandwidth'}{'Avg'}{'KBps'}, 10, 'r') if ($cmd_options{'bytes'}); } } $ostr .= sprintf "\n"; } # Display the interface data usage stats if ($cmd_options{'data'}) { if ($cmd_options{'colors'}) { $ostr .= sprintf colored alignstr('|- Amount', 10, 'r'), $colors{'data'}; foreach $direction (sort keys %{$interface->{$inter}}) { $ostr .= sprintf colored alignstr( adjust_unit($interface->{$inter}{$direction}{'Amount'}{'KB'}), 22, 'r'), $colors{'data'} if ($cmd_options{'bits'} && $cmd_options{'bytes'}); $ostr .= sprintf colored alignstr( adjust_unit($interface->{$inter}{$direction}{'Amount'}{'KB'}), 12, 'r'), $colors{'data'} if ($cmd_options{'bits'} && !$cmd_options{'bytes'}); $ostr .= sprintf colored alignstr( adjust_unit($interface->{$inter}{$direction}{'Amount'}{'KB'}), 10, 'r'), $colors{'data'} if ($cmd_options{'bytes'} && !$cmd_options{'bits'}); } } else { $ostr .= sprintf alignstr('|- Amount', 10, 'r'); foreach $direction (sort keys %{$interface->{$inter}}) { $ostr .= sprintf alignstr( adjust_unit($interface->{$inter}{$direction}{'Amount'}{'KB'}), 22, 'r') if ($cmd_options{'bits'} && $cmd_options{'bytes'}); $ostr .= sprintf alignstr( adjust_unit($interface->{$inter}{$direction}{'Amount'}{'KB'}), 12, 'r') if ($cmd_options{'bits'} && !$cmd_options{'bytes'}); $ostr .= sprintf alignstr( adjust_unit($interface->{$inter}{$direction}{'Amount'}{'KB'}), 10, 'r') if ($cmd_options{'bytes'} && !$cmd_options{'bits'}); } } $ostr .= sprintf "\n"; } $ostr .= sprintf "\n"; } # Stuff for all interfaces (interfaces_all hash) foreach $direction (keys %{$interfaces_all}) { # Total Data in KB for all interfaces $interfaces_all->{$direction}{'Amount'}{'KB'} = sprintf('%.2f', $interfaces_all->{$direction}{'Amount'}{'KB'} + $interfaces_all->{$direction}{'Bandwidth'}{'KBps'} * $cmd_options{'interval'}); # Average data in KBps $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'KBps'} = sprintf('%.2f', $interfaces_all->{$direction}{'Amount'}{'KB'} / get_run_time('s')); # Average data in Kbps $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'Kbps'} = sprintf('%.2f', $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'KBps'} * 8); # Max of all interfaces in KBps $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'KBps'} = sprintf('%.2f', ($interfaces_all->{$direction}{'Bandwidth'}{'KBps'} > $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'KBps'}) ? $interfaces_all->{$direction}{'Bandwidth'}{'KBps'} : $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'KBps'}); # Max of all interfaces in Kbps $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'Kbps'} = sprintf('%.2f', ($interfaces_all->{$direction}{'Bandwidth'}{'Kbps'} > $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'Kbps'}) ? $interfaces_all->{$direction}{'Bandwidth'}{'Kbps'} : $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'Kbps'}); } # Display All Interfaces stats $ostr .= sprintf alignstr(' All', 10, 'l'); foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf alignstr($interfaces_all->{$direction}{'Bandwidth'}{'Kbps'}, 12, 'r') if ($cmd_options{'bits'}); $ostr .= sprintf alignstr($interfaces_all->{$direction}{'Bandwidth'}{'KBps'}, 10, 'r') if ($cmd_options{'bytes'}); } $ostr .= sprintf "\n"; # Display the max of all interfaces if ($cmd_options{'max'}) { if ($cmd_options{'colors'}) { $ostr .= sprintf colored alignstr('|---- Max', 10, 'r'), $colors{'max'}; foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf colored alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'Kbps'}, 12, 'r'), $colors{'max'} if ($cmd_options{'bits'}); $ostr .= sprintf colored alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'KBps'}, 10, 'r'), $colors{'max'} if ($cmd_options{'bytes'}); } } else { $ostr .= sprintf alignstr('|---- Max', 10, 'r'); foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'Kbps'}, 12, 'r') if ($cmd_options{'bits'}); $ostr .= sprintf alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Max'}{'KBps'}, 10, 'r') if ($cmd_options{'bytes'}); } } $ostr .= sprintf "\n"; } # Display the avg of all interfaces if ($cmd_options{'avg'}) { if ($cmd_options{'colors'}) { $ostr .= sprintf colored alignstr('|---- Avg', 10, 'r'), $colors{'avg'}; foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf colored alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'Kbps'}, 12, 'r'), $colors{'avg'} if ($cmd_options{'bits'}); $ostr .= sprintf colored alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'KBps'}, 10, 'r'), $colors{'avg'} if ($cmd_options{'bytes'}); } } else { $ostr .= sprintf alignstr('|---- Avg', 10, 'r'); foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'Kbps'}, 12, 'r') if ($cmd_options{'bits'}); $ostr .= sprintf alignstr( $interfaces_all->{$direction}{'Bandwidth'}{'Avg'}{'KBps'}, 10, 'r') if ($cmd_options{'bytes'}); } } $ostr .= sprintf "\n"; } # Display the interfaces_all data usage stats if ($cmd_options{'data'}) { if ($cmd_options{'colors'}) { $ostr .= sprintf colored alignstr('|- Amount', 10, 'r'), $colors{'data'}; foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf colored alignstr( adjust_unit($interfaces_all->{$direction}{'Amount'}{'KB'}), 22, 'r'), $colors{'data'} if ($cmd_options{'bits'} && $cmd_options{'bytes'}); $ostr .= sprintf colored alignstr( adjust_unit($interfaces_all->{$direction}{'Amount'}{'KB'}), 12, 'r'), $colors{'data'} if ($cmd_options{'bits'} && !$cmd_options{'bytes'}); $ostr .= sprintf colored alignstr( adjust_unit($interfaces_all->{$direction}{'Amount'}{'KB'}), 10, 'r'), $colors{'data'} if (!$cmd_options{'bits'} && $cmd_options{'bytes'}); } } else { $ostr .= sprintf alignstr('|- Amount', 10, 'r'); foreach $direction (sort keys %{$interfaces_all}) { $ostr .= sprintf alignstr( adjust_unit($interfaces_all->{$direction}{'Amount'}{'KB'}), 22, 'r') if ($cmd_options{'bits'} && $cmd_options{'bytes'}); $ostr .= sprintf alignstr( adjust_unit($interfaces_all->{$direction}{'Amount'}{'KB'}), 12, 'r') if ($cmd_options{'bits'} && !$cmd_options{'bytes'}); $ostr .= sprintf alignstr( adjust_unit($interfaces_all->{$direction}{'Amount'}{'KB'}), 10, 'r') if (!$cmd_options{'bits'} && $cmd_options{'bytes'}); } } $ostr .= sprintf "\n"; } $elapsed_time = get_run_time(''); $ostr .= sprintf "\n"; if ($useReadKey) { $ostr .= sprintf ' Press \'q\' to quit...'; } else { $ostr .= sprintf ' Press ctrl+c to quit...'; } $ostr .= sprintf "\t\t".'Elapsed time: '.$elapsed_time; $ostr .= sprintf "\n"; if ($debug) { debug_it("avgpass: $avgpass"); debug_it('Interval: '.$cmd_options{'interval'}); debug_it("elapsed_time: $elapsed_time"); debug_it('%interface{\'ppp0\'}{\'Received\'} DUMP:'); debug_it(Dumper($interface->{'ppp0'}{'Received'})); } if ($key_mess ne '') { $ostr .= sprintf "\n $key_mess\n"; $key_mess = ''; } $avgpass++; if ($ihelp) { show_help(); } else { print $ostr; } if ($useReadKey) { eval q/$inputkey = ReadKey(0.000000001);/; if (defined($inputkey)) { # User has pressed some key. Better process it. process_userkey($inputkey); } } } # Clear interface names @interface_names_copy = @interface_names; @interface_names = (); # Sleep for interval seconds $t1 = [gettimeofday]; $t0_t1 = tv_interval $t0, $t1; if ($debug) { debug_it("\$t0_t1 = $t0_t1"); debug_it($cmd_options{'interval'} - $t0_t1); } usleep (($cmd_options{'interval'} - $t0_t1) * 1000000); } # End of never-ending story! :-) sub print_usage() { my $progname = `basename $0`; chop $progname; print STDERR "ibmonitor version $version\n"; print STDERR 'usage: '.$progname.' [--bits] [--bytes] [--max] [--avg] '."\n". "\t\t".'[--data] [--interval n] [--colors | --nocolors] '."\n". "\t\t".'[--dev regex] [--file proc] [--help] [--version]'."\n"; } sub create_interface($) { my $inter = shift; for my $direction ('Received', 'Sent', 'Total') { $interface->{$inter}{$direction}{'New'} = 0; $interface->{$inter}{$direction}{'Old'} = 0; $interface->{$inter}{$direction}{'Bandwidth'} = { 'Bps' => 0, 'KBps' => 0, 'Kbps' => 0, }; for my $type ('Max', 'Avg') { $interface->{$inter}{$direction}{'Bandwidth'}{$type} = { 'KBps' => 0, 'Kbps' => 0, }; } $interface->{$inter}{$direction}{'Amount'} = { 'KB' => 0, 'MB' => 0, 'GB' => 0, }; } } sub init_interfaces_all() { for my $dir ('Received', 'Sent', 'Total') { $interfaces_all->{$dir}{'Bandwidth'} = { 'Bps' => 0, 'KBps' => 0, 'Kbps' => 0, }; for my $type ('Max', 'Avg') { $interfaces_all->{$dir}{'Bandwidth'}{$type} = { 'KBps' => 0, 'Kbps' => 0, }; } $interfaces_all->{$dir}{'Amount'} = { 'KB' => 0, 'MB' => 0, 'GB' => 0, }; } } # get_proc_data # ------------- # Return array of lines from file /proc/net/dev # sub get_proc_data() { my @arr; #my $n_interfaces; open FH, "<$cmd_options{file}" or die "Couldn't open $cmd_options{file}!"; @arr = ; close FH; splice @arr, 0, 2; #$n_interfaces = scalar @arr; #if ($n_interfaces > $num_interfaces) { # An interface has been added/activated return @arr; } # trim # ---- # Remove leading/trailing whitespace from string # sub trim($) { my $str = $_[0]; $str =~ s/^\s+//; $str =~ s/\s+$//; return $str; } # alignstr # -------- # Align the string # arguments: # 1) the string to align # 2) field length # 3) l -> align left # m -> align center # r -> align right # sub alignstr($$$) { my ($str, $len, $pos) = @_; my $ret_str; my $num_spaces; my $left_spaces; my $right_spaces; $num_spaces = $len - length($str); if ($pos eq 'l') { # left align $ret_str = $str; $ret_str .= ' ' x $num_spaces; } elsif ($pos eq 'r') { # right align $ret_str = ' ' x $num_spaces; $ret_str .= $str; } elsif ($pos eq 'm') { # center align $left_spaces = int($num_spaces/2); $right_spaces = $num_spaces - $left_spaces; $ret_str = ' ' x $left_spaces; $ret_str .= $str; $ret_str .= ' ' x $right_spaces; } return $ret_str; } sub debug_it($) { my $content = $_[0]; open FH, ">>$debug_file"; print FH $content."\n"; close FH; } sub show_help() { # display list of interactive commands if ($useReadKey) { print $clearstr; my $tmpstr =< [q]uit 1-9 -> Set sleep time interval (in seconds) to the digit entered m -> Toggle display of [m]ax bandwidth a -> Toggle display of [a]verage bandwidth i -> Toggle display of values in KB[i]ts/sec (Kbps) y -> Toggle display of values in KB[y]tes/sec (KBps) d -> Toggle display of [d]ata transferred s -> Shift interface up/down. This should be followed by the interface number, and then the direction (u or d) r -> [r]eset all values ?/h -> This help screen Press Enter to resume monitoring... EOF print $tmpstr; } } sub quit_it() { # restore terminal mode to whatever it was if ($useReadKey) { eval q/ReadMode 'restore';/; print "\nQuitting...\n"; exit 0; } } sub reset_all() { foreach my $inter_r (keys %{$interface}) { foreach my $direction (keys %{$interface->{$inter_r}}) { foreach my $type ('Avg', 'Max') { foreach my $unit (keys %{$interface->{$inter_r}{$direction}{'Bandwidth'}{$type}}) { $interface->{$inter_r}{$direction}{'Bandwidth'}{$type}{$unit} = 0; } } foreach my $unit (keys %{$interface->{$inter_r}{$direction}{'Amount'}}) { $interface->{$inter_r}{$direction}{'Amount'}{$unit} = 0; } } } foreach my $direction (keys %{$interfaces_all}) { foreach my $type ('Avg', 'Max') { foreach my $unit (keys %{$interfaces_all->{$direction}{'Bandwidth'}{$type}}) { $interfaces_all->{$direction}{'Bandwidth'}{$type}{$unit} = 0; } } foreach my $unit (keys %{$interfaces_all->{$direction}{'Amount'}}) { $interfaces_all->{$direction}{'Amount'}{$unit} = 0; } } $avgpass = 1; $start_time = time(); } sub print_help() { my $output; print "\n"; print_usage(); # print full help with usage $output =< Show output values in KBits/sec. This is the default. --bytes -> Show output values in KBytes/sec --max -> Show maximum values per interface --avg -> Show average values per interface --interval n -> Set time interval as n seconds. The default is 2 seconds. --data -> Show data transferred in KB/MB/GB --colors -> Show some fancy coloring! (This is the default) --nocolors -> No fancy coloring please! --dev regex -> Show output from device which matches regex --file proc -> Specify which file to use in the proc filesystem for the interface byte counter --help -> Show help and exit --version -> Show version number and exit While the program is running, the following keys are recognized, which enables the user to change the output display format of the program. Note: ibmonitor responds directly to the single keystroke ie. the 'Enter' key need not be pressed q -> [q]uit 1-9 -> Set sleep time interval(in seconds) to the digit entered m -> Toggle display of [m]ax bandwidth a -> Toggle display of [a]verage bandwidth i -> Toggle display of values in KB[i]ts/sec (Kbps) y -> Toggle display of values in KB[y]tes/sec (KBps) d -> Toggle display of [d]ata transferred s -> Shift interface up/down. This should be followed by the interface number, and then the direction (u or d) r -> [r]eset all values ?/h -> help screen for interactive commands EOF print STDERR $output; } sub adjust_unit($) { my $amt = $_[0]; my $ret; if ($amt =~ /^\d{1,3}\b\.?/) { # return in KB $ret = $amt.' KB'; } elsif ($amt =~ /^\d{1,6}\b\.?/) { # return in MB $ret = sprintf('%.2f', ($amt / 1024)).' MB'; } elsif ($amt =~ /^\d{1,9}\b\.?/) { # return in GB $ret = sprintf('%.2f', ($amt / (1024*1024))).' GB'; } return $ret; } sub get_run_time($) { my $arg = shift; my $nowtime = time(); my $diff = $nowtime - $start_time; my ($sec, $min, $hour); my $ret; return $diff if ($arg eq 's'); $sec = $diff % 60; $min = ($diff / 60) % 60; $hour = ($diff / (60 * 60)) % 24; $ret = "$hour hrs, $min mins, $sec s"; return $ret; } sub process_userkey($) { my $ikey = $_[0]; if ($movers{'init'}) { $movers{'num'} = $ikey; $movers{'init'} = 0; if ($movers{'num'} !~ /\d/) { $key_mess = 'Need a number!'; $movers{'num'} = 0; } else { $key_mess = 'Interface to shift at position '.$ikey; } } elsif ($movers{'num'}) { $movers{'dir'} = $ikey; order_interfaces(); $movers{'num'} = 0; if ($movers{'dir'} eq 'u') { $key_mess = 'Shifting interface up'; } elsif ($movers{'dir'} eq 'd') { $key_mess = 'Shifting interface down'; } } elsif ($ihelp_flg) { if ($ikey eq "\n") { $ihelp = 0; $ihelp_flg = 0; } } elsif ($ikey eq '?' || $ikey eq 'h') { $ihelp = 1; $ihelp_flg = 1; } elsif ($ikey eq 'q') { quit_it(); } elsif ($ikey eq 'm') { $cmd_options{'max'} = abs($cmd_options{'max'}-1); if ($cmd_options{'max'}) { $key_mess = 'm => Displaying [m]ax Bandwidth'; } else { $key_mess = 'm => Not Displaying [m]ax Bandwidth'; } } elsif ($ikey eq 'a') { $cmd_options{'avg'} = abs($cmd_options{'avg'}-1); if ($cmd_options{'avg'}) { $key_mess = 'a => Displaying [a]verage Bandwidth'; } else { $key_mess = 'a => Not Displaying [a]verage Bandwidth'; } } elsif ($ikey eq 'i') { $cmd_options{'bits'} = abs($cmd_options{'bits'}-1); if ($cmd_options{'bits'}) { $key_mess = 'i => Displaying Values in Kb[i]ts/sec (Kbps)'; } else { $key_mess = 'i => Not Displaying Values in Kb[i]ts/sec (Kbps)'; } } elsif ($ikey eq 'y') { $cmd_options{'bytes'} = abs($cmd_options{'bytes'}-1); if ($cmd_options{'bytes'}) { $key_mess = 'y => Displaying Values in KB[y]tes/sec (KBps)'; } else { $key_mess = 'y => Not Displaying Values in KB[y]tes/sec (KBps)'; } } elsif ($ikey eq 'd') { $cmd_options{'data'} = abs($cmd_options{'data'}-1); if($cmd_options{'data'}) { $key_mess = 'd => Displaying [d]ata transferred'; } else { $key_mess = 'd => Not Displaying [d]ata transferred'; } } elsif ($ikey eq 'r') { # Reset all values reset_all(); $key_mess = 'r -> [r]esetting all values'; } elsif ($ikey =~ /^\d$/ && $ikey != 0) { # If ikey is a digit then it is an interval $cmd_options{'interval'} = $ikey; $key_mess = $ikey.' => Refresh interval is now ['.$ikey.'] seconds'; } elsif ($ikey eq 's') { # shift interface up/down $movers{'init'} = 1; $key_mess = $ikey.' => [s]hift interface up/down. Enter interface number '; } else { $key_mess = $ikey.' => Invalid keystroke'; } # something has to be shown! # resort to Kbits by default $cmd_options{'bits'} = 1 if ($cmd_options{'bits'} == 0 && $cmd_options{'bytes'} == 0); } sub order_interfaces() { if ($debug) { debug_it('order_interfaces():'); debug_it('Before:'); debug_it('%movers DUMP:'); debug_it(Dumper(%movers)); debug_it('@interface_names DUMP:'); debug_it(Dumper(@interface_names)); } # Check for boundary conditions if (($movers{'dir'} eq 'u') && ($movers{'num'} > 1) && ($movers{'num'} <= $#interface_names+1)) { ($interface_names[$movers{'num'}-2], $interface_names[$movers{'num'}-1]) = ($interface_names[$movers{'num'}-1], $interface_names[$movers{'num'}-2]); } elsif (($movers{'dir'} eq 'd') && ($movers{'num'} >= 1) && ($movers{'num'} <= $#interface_names)) { ($interface_names[$movers{'num'}], $interface_names[$movers{'num'}-1]) = ($interface_names[$movers{'num'}-1], $interface_names[$movers{'num'}]); } if ($debug) { debug_it('order_interfaces():'); debug_it('After:'); debug_it('%movers DUMP:'); debug_it(Dumper(%movers)); debug_it('@interface_names DUMP:'); debug_it(Dumper(@interface_names)); } } =head1 NAME ibmonitor - an interactive bandwidth monitor which runs on a linux console =head1 DESCRIPTION ibmonitor is an interactive linux console application which shows bandwidth consumed and total data transferred on all interfaces. Its main features are: - Shows received, transmitted and total bandwidth of each interface - Calculates and displays the combined value of all interfaces - Displays total data transferred per interface in KB/MB/GB - Bandwidth Values can be displayed in Kbits/sec(Kbps) and/or KBytes/sec(KBps) - Can show maximum bandwidth consumed on each interface since start of utility - Can show average bandwidth consumption on each interface since start of utility - The output with all features (max, avg and display in Kbps and KBps) easily fits on a 80x24 console or xterm - Can interactively change its output display format depending on key pressed by user. =head1 README ibmonitor is a command line program which will run on a linux console or xterm (rxvt, konsole, gnome-terminal, etc) usage: ibmonitor [--bits] [--bytes] [--max] [--avg] [--interval n] [--data] [--colors | --nocolors] [--dev regex] [--file proc] [--help] [--version] The following command line options (and their explanation) are available: --bits -> Show output values in KBits/sec. This is the default. --bytes -> Show output values in KBytes/sec --max -> Show maximum values per interface --avg -> Show average values per interface --interval n -> Set time interval as n seconds. The default is 2 seconds. --data -> Show data transferred in KB/MB/GB --colors -> Show some fancy coloring! This is the default --nocolors -> No fancy coloring please! --dev regex -> Show output from device matching regex --file proc -> Specify which file to use in the proc filesystem for the interface byte counter --help -> Show help and exit --version -> Show version number and exit While running, ibmonitor can also read the input key from the user and dynamically change the output display format depending on the key pressed. The following keys are supported. Note that ibmonitor responds directly to the single keystroke. ie. 'Enter' key need not be pressed. NOTE: This will only work if you have the Term::ReadKey Perl module installed and working, hence the requirement. q -> [q]uit 1 - 9 -> Set sleep time interval(in seconds) to the digit entered m -> Toggle display of [m]ax bandwidth a -> Toggle display of [a]verage bandwidth i -> Toggle display of values in KB[i]ts/sec (Kbps) y -> Toggle display of values in KB[y]tes/sec (KBps) d -> Toggle display of [d]ata transferred s -> Shift interface up/down. This should be followed by the interface number, and then the direction (u or d) r -> [R]eset all values ?/h -> Help Screen for interactive commands =head1 PREREQUISITES This script requires the following modules: C C C C =head1 COREQUISITES C =head1 AUTHOR Rohan Romanus Almeida =head1 SCRIPT CATEGORIES Networking Unix/System_administration =cut