sysmon
#!/usr/bin/perl -w
#
# sysmon -- low tech monitoring of multiple systems,
# plus mailbox/news checking
#
use strict;
use File::stat;
use Term::ReadKey;
use Term::ANSIScreen qw/:color :constants :cursor :screen/;
#
# signal handlers
#
$SIG{INT} = \&sighndl;
$SIG{TERM} = \&sighndl;
$SIG{CHLD} = 'IGNORE';
my ( $logid, $home ) = ( getpwuid($<) )[ 0, 7 ];
my $key; # key pressed
my $n; # priority queue size
my $sigtermed; # signal terminated
my $i; # loop index
my ( $j, $k ); # priority queue indices
my @hostlist; # systems to monitor
my @pq; # priority queue (array of hashes)
my %row; # screen coordinates for each host
my %col;
my $t; # temp array element
open( LL, "<$home/.sysmonlist" );
chomp( @hostlist = <LL> );
close(LL);
$| = 1;
screeninit();
#
# set up priority queue, initially with everything equal priority (ASAP)
# number of elements in pq = 1 + number of hosts; elements are pq[1..n]
#
$n = 1 + scalar(@hostlist);
$pq[1] = { sched => 0, cmd => "checkmail" };
for ( $i = 0 ; $i <= $#hostlist ; $i++ ) {
$pq[ $i + 2 ] = { sched => 0, cmd => $hostlist[$i] };
}
#
# also set up screen position for each host
#
my $nrows = int( ( 1 + scalar(@hostlist) ) / 2 ); # assume 2 columns
for ( $i = 0 ; $i <= $#hostlist ; $i++ ) {
$row{ $hostlist[$i] } = 5 + ( $i % $nrows );
$col{ $hostlist[$i] } = 1 + 40 * int( $i / $nrows );
}
ReadMode 4; # raw
while ( !$sigtermed ) {
locate( 1, 55 );
print BOLD scalar localtime;
if ( time() >= $pq[1]{sched} ) {
$t = $pq[1];
if ( $t->{cmd} eq "checkmail" ) {
checkmail( $logid, $home );
$t->{sched} = time() + 60;
}
else {
checkhost( $pq[1]{cmd} );
$t->{sched} = time() + 240 + rand(120);
}
#
# requeue command with new scheduling
#
$k = 1;
while ( $k <= int( $n / 2 ) ) {
$j = $k + $k;
if ( $j < $n && $pq[$j]{sched} > $pq[ $j + 1 ]{sched} ) {
$j++;
}
last if ( $t->{sched} <= $pq[$j]{sched} );
$pq[$k] = $pq[$j];
$k = $j;
}
$pq[$k] = $t;
}
if ( defined( $key = ReadKey(1) ) ) { # keypress!
last if ( $key eq "Q" || $key eq "q" );
screeninit();
}
sleep 1;
}
locate( 1, 1 );
cls;
ReadMode 0;
exit(0);
sub sighndl {
my ($sig) = @_;
$sigtermed = $sig;
}
sub screeninit {
$Term::ANSIScreen::AUTORESET = 1;
cls;
locate( 1, 1 );
print BOLD "CIS Unix System Monitor";
locate( 4, 9 );
print BOLD UNDERLINE "Users Up(d) Load Resp(s)";
locate( 4, 49 );
print BOLD UNDERLINE "Users Up(d) Load Resp(s)";
}
sub checkmail {
my ( $logid, $home ) = @_;
my @infiles;
my $infile;
my $col;
my $sb;
my $isnews;
locate( 2, 1 );
clline; # clear two lines
locate( 3, 1 );
clline; # clear two lines
$col = 1;
if ( -s "$home/.mailspool/$logid" ) {
locate( 2, $col );
print RED "[MAIL]";
$col += 6;
}
$sb = stat("$home/.jnewsrc");
if ( time() - $sb->mtime > 4 * 3600 ) {
locate( 2, $col );
print MAGENTA "[NEWS]";
$col += 6;
}
opendir( M, "$home/Mail" ) || die "Can't open $home/Mail: $!\n";
@infiles = grep { /^IN\./ } readdir(M);
closedir(M);
foreach $infile (@infiles) {
$infile =~ s/^IN\.//;
if ( -s "$home/Mail/IN.$infile" ) {
locate( 2, $col );
print YELLOW "[$infile]";
$col += ( length($infile) + 2 );
}
}
$sb = stat("$home/Mail/Postmaster");
if ( $sb->size > 0 && time() - $sb->atime > 7200 ) {
locate( 2, $col );
print GREEN "[Postmaster]";
$col += 12;
}
$sb = stat("$home/Mail/Spam");
if ( $sb->size > 0 && time() - $sb->atime > 14400 ) {
locate( 2, $col );
print GREEN "[Spam]";
$col += 6;
}
}
#
# check host, display results
#
sub checkhost {
my ($host) = @_; # host to check
my @psout; # output from ps
my $up; # calculated uptime
my ( $t1, $t2 ); # time before and after uptime query
my $rt; # elapsed time for query
my ( $r, $c ); #row and column
$r = $row{$host};
$c = $col{$host};
locate( $r, $c );
print BOLD $host;
locate( $r, $c + 8 );
print ' ' x 32;
eval {
local $SIG{ALRM} = sub { die "alarm\n" };
alarm(60);
$t1 = time();
open( F, "ssh $host uptime 2>&1|" );
my $users = "-";
my $load = "----";
my $uptime = "----";
while (<F>) {
next unless / up /;
/ (\d+) user/ && ( $users = $1 );
/average: (\d+\.\d+), (\d+\.\d+), (\d+\.\d+)/
&& ( $load = $3 );
$up = 0;
/(\d+) days?/ && ( $up += $1 );
/(\d+) hrs?/ && ( $up += $1 / 24 );
/(\d+) mins?/ && ( $up += $1 / 1440 );
/(\d+) secs?/ && ( $up += $1 / 86400 );
/(\d+):(\d+),/ && ( $up += ( $1 / 24 + $2 / 1440 ) );
$uptime = sprintf( "%8.2f", $up );
}
close(F);
$t2 = time();
$rt = $t2 - $t1;
if ( $users eq "-" ) {
locate( $r, $c + 12 );
print BLACK ON_RED "NO RESPONSE";
}
else {
locate( $r, $c + 8 );
printf( "%4s", $users );
locate( $r, $c + 12 );
printf( "%8s", $uptime );
locate( $r, $c + 20 );
if ( $load >= 2.0 ) {
print RED sprintf( "%6s", $load );
}
elsif ( $load >= 1.0 ) {
print YELLOW sprintf( "%6s", $load );
}
else {
print GREEN sprintf( "%6s", $load );
}
locate( $r, $c + 29 );
if ( $rt > 30 ) {
print RED sprintf( "%5d", $rt );
}
elsif ( $rt > 15 ) {
print YELLOW sprintf( "%5d", $rt );
}
else {
print GREEN sprintf( "%5d", $rt );
}
}
alarm(0);
};
if ($@) {
die "Something went wrong!\n" unless $@ eq "alarm\n";
locate( $r, $c + 9 );
print BLACK ON_RED "NO RESPONSE";
open( PS, "/bin/ps T|" );
while (<PS>) {
if (/ssh/) {
@psout = split;
kill 1, $psout[0];
}
}
close(PS);
close(F);
}
}