#!/opt/bin/perl -w # # ping_monitor [options] hosts... # # Display a table of hosts and indicate if the hosts are pingable. If run # as root a proper icmp `ping' is used, otherwise the program is forced to # do send `udp' echo packets which not all hosts respond to. # # This program is used for a special X window display which permantly # displays the status and loads of multiple machines under our control. # I also like using it under Linux as a monitor of the PPP connection # to the outside world. # # Options: # -c num Number of columns for hosts # -t title Add a title inside the window (if no WM titlebar provided) # Plus standard X window options (see Tk::CmdLine Manpage) # # Copyright (c) 1998 Anthony Thyssen. All rights reserved. This program # is free software; you can redistribute it and/or modify it under the # same terms as Perl itself. # # Please mail any suggestions or ideas to anthony@cit.gu.edu.au # the latest version of the software is available from # http://www.cit.gu.edu.au/~anthony/software/ # use Tk; use Net::Ping; $prog=$0; $prog=~s/^.*\/([^\/]+)$/$1/; # Colors to use for host state $host_up = 'green'; $host_fail = 'yellow'; $host_down = 'red'; # time betwwen checks and for host down $cycle_time = 60; # test once a minute $down_time = 300; # down after 5 minutes $columns = 1; # Default number of columns # Initialize and Create the Main Window. # This also reads and extracts X11 Options from @ARGV before we look for our # program specific options. And reads in the applications resources. $mw = MainWindow->new; $mw->title("Ping Monitor"); sub Usage { print STDERR @_; print STDERR "Usage: $prog [-c {num_columns}] hosts...\n"; exit(10); } # The `and' below is to prevent a undefined variable warning # It is also lower precidence so parentheses are not needed. while( $_ = $ARGV[0] and ($_, $arg) = /^-(.)(.*)/ ) { $arg = '' unless defined $arg; # Ensure arg is defined shift; /-/ && do { last; }; # End of options /t/ && do { $title = $arg || shift; next; }; /g/ && do { $mw->geometry($arg || shift); next; }; /c/ && do { $columns = $arg || shift; Usage( "Bad Column Value -c $columns\n" ) unless $columns =~ /^\d+$/; next }; &Usage( "Bad Option `-", $_, $arg, "'\n" ); } undef($arg); @hosts = @ARGV; Usage("No hosts given!") unless @hosts; # ---------------- Window Setup -------------------------- $ping = $> ? Net::Ping->new('udp', 2) : Net::Ping->new('icmp', 2) ; if ( defined $title ) { $mw->Label( -text => $title, -borderwidth => 0, -highlightthickness => 0, )-> pack; } # inital check color until host is pinged $background = $mw->cget('-background'); $rows= int( $#hosts / $columns ) + 1; $column = 0; $row=0; # NOTE: the initial value of a check button is "undef" NOT "0", at the time # of writing. This is not documented so things could change. To ensure # things are correct, the onValue is set to the same as the offValue (0) and # a call to the checkbutton->select method is made, to set the internal # variable. @cb_common = ( -onvalue => 0, # Default ON = Default OFF -activebackground => $background, # don't indicate mouse -highlightthickness => 0, # or highlight button ); # grid frame my $g = $mw->Frame->pack( -fill => 'both', -expand => 1, ); foreach $host ( @hosts ) { $host_up{$host} = 0; # Assume host has never been up! # Pack host in a frame to align all indicators on the left # and provide a nice border between the hosts. my $f = $g->Frame( -borderwidth => 1, -relief => 'sunken', )->grid( -column => $column, -row => $row, -sticky => 'nsew', ); $host_cb{$host} = $f->Checkbutton( -text => $host, -selectcolor => $background, # No indication yet @cb_common, )->pack( -side => 'left' ); $host_cb{$host}->select; # set the internal veriable to the onValue if ( ++$row >= $rows ) { $column++; $row=0; } } # make all grid elements expand with window for( $column=0; $column<$columns; $column++ ) { $g->gridColumnconfigure( $column, -weight => 1 ); } for( $row=0; $row<$rows; $row++ ) { $g->gridRowconfigure( $row, -weight => 1 ); } # ------------------ Main Tasks ------------------ sub ping_host { my($host) = @_; if ( $ping->ping( $host ) ) { $host_up{$host} = time; # last time host was up $host_cb{$host}->configure( -selectcolor => $host_up ); } else { my $time = time - $host_up{$host}; # time host has been down $host_cb{$host}->configure( -selectcolor => $time > $down_time ? $host_down : $host_fail ); } } sub ping_hosts { foreach $host ( @hosts ) { ping_host( $host ); } $mw->after($cycle_time*1000, \&ping_hosts); } $mw->after(0, \&ping_hosts); MainLoop;