#!/usr/local/bin/perl -w # # Watch processlist and notify differences to an admin. # # Usage: Just fire-off. # If there's no basefile, it'll generate it. After that, it runs quietly. # Only change the adminmail and/or the syslog-value if needed. # # If you have some processes which are constantly changing, you can have them ingnored # by changing the baselist. Just change the counter to -1 and it will be ignored the # next run. So, "grep 2" will become "grep -1". # This feature might come in handy when checking i.e. a webserver. Your amount of # httpd processes will never be constant. # Off course you can add entries yourself at the end of the basefile. But don't add an # EOL to the file! # # Let it initialize by cron, as you're shell probably will not be there all the time. # # $Id: pcds,v 2.7 2003/12/26 10:28:04 bart Exp $ # $Revision: 2.7 $ # # Bart Somers # William H. Nugent 10-Sep-2003 Modified PCDS to allow a range of the number # of processes to be checked. # # This software is released under the GPL. The full licence # can be found at: # http://www.gnu.org/licenses/licenses.html#GPL # # use strict; use vars; use Sys::Syslog qw(:DEFAULT setlogsock); umask 077; my $baselist = "/var/tmp/baselist.txt"; my $currlist = "/var/tmp/currlist.txt"; my $logfile = "/var/tmp/pcds.log"; # WARNING! # When setting an email-addres, be sure to escape the "@" sign, by putting a # backslash in front if it: me\@some.where. Multiple addresses are allowed, seperate them by # spaces. my $adminmail = "root\@localhost"; my $syslog = 1; my $maillog = 0; # Debugging. If set to non-zero, we don't cleanup the logfile and current # process-list as defined above. my $debug = 0; # Choose your syslog-output facility and level. Default is set to local5 and err (error). # WARNING: devide the facility and level by a "|" sign: local5|err my $loglevel = "local5|err"; # No configurable options below this line. ################################################################## sub getprocs { my $oldword; my $count; my $process; open (CURRLIST, "> $currlist") || die("Can't open $currlist : $!"); if ( $main::osystem eq "FreeBSD" ) { $process = `ps -axco command | grep -v COMMAND | sort`; chomp $process; } else { $process = `ps -eo comm | grep -v COMMAND | sort`; chomp $process; } my @proclist = split "\n", $process; foreach $b (@proclist) { if ( ! defined $oldword ) { $oldword = $b; } if ($b eq $oldword) { $count++; } else { print (CURRLIST $oldword, " ", $count, " " ); $oldword = $b; $count = 1; } } close CURRLIST; } sub difflist { open (BASELIST, " $baselist") || die("Can't open $baselist : $!"); open (CURRLIST, " $currlist") || die("Can't open $currlist : $!"); my $base = ; my $curr = ; close BASELIST; close CURRLIST; open (LOGFILE, "> $logfile") || die("Can't open $logfile : $!"); my @baselist = split " ", $base; my @currlist = split " ", $curr; my $basecount = 0; my $currcount = 0; my $intcountcurr = 0; my $intcountbase = 0; my $match = 0; for ( $currcount = 0; $currcount <= $#currlist; $currcount+=2 ) { for ( $basecount = 0; $basecount <= $#baselist; $basecount+=2) { if ( $baselist[$basecount] eq $currlist[$currcount] ) { $match = 1; $intcountbase = $basecount + 1; $intcountcurr = $currcount + 1; my @range = split /-/, $baselist[$intcountbase]; if ( $baselist[$intcountbase] eq "-1" ) { #process is on the ignore-list } elsif ( @range == 2 ) { if ( $range[0] ne '' && $range[1] ne '' && $range[0] <= $currlist[$intcountcurr] && $currlist[$intcountcurr] <= $range[1] ) { #process is in the right range } else { my $intcountcurr = $currcount + 1; print (LOGFILE "Oops, ", $currlist[$intcountcurr], " ", $baselist[$basecount], " processes running, instead of the range ", $range[0], " to ", $range[1], "\n"); if ( $syslog == 1 ){ syslog ($loglevel, "$currlist[$intcountcurr] $baselist[$basecount] processes running, instead of the range $range[0] to $range[1]"); } } } elsif ( $baselist[$intcountbase] != $currlist[$intcountcurr] ) { my $intcountcurr = $currcount + 1; print (LOGFILE "Oops, ", $currlist[$intcountcurr], " ", $baselist[$basecount], " processes running, instead of ", $baselist[$intcountbase], "\n"); if ( $syslog == 1 ){ syslog ($loglevel, "$currlist[$intcountcurr] $baselist[$basecount] processes running, instead of $baselist[$intcountbase]"); } } } } #print "match: ", $match, "\n"; if ( $match == 0 ) { print (LOGFILE $currlist[$intcountcurr], " ",$currlist[$currcount], " process running. Not seen before. \n"); if ( $syslog == 1 ){ syslog ($loglevel, "$currlist[$intcountcurr] $currlist[$currcount] process running. Not seen before."); } } $match = 0; } close LOGFILE; } sub mailreport { my $hostname = `hostname`; my $osystem = `uname -s`; chop $osystem; if ( -s $logfile && $osystem ne "SunOS" ) { system ("cat $logfile | mail -s \"PCDS logging from $hostname \" $adminmail"); } elsif ( -s $logfile ) { system ("cat $logfile | mailx -s \"PCDS logging from $hostname \" $adminmail"); } } # End of subroutines. Start executing something. our $osystem = `uname -s`; chomp $osystem; if ( ! -e $baselist ) { open (LOGFILE, "> $logfile") || die("Can't open $logfile : $!"); &getprocs( $currlist ); rename $currlist, $baselist; print (LOGFILE "Initialization complete. \n"); if ( $syslog == 1 ){ if ( $osystem eq "Linux" ) { setlogsock('unix'); } openlog ('pcds', 'nowait', 'user'); syslog ($loglevel, "Initialization complete."); closelog (); } close LOGFILE; if ( $maillog == 1 ){ &mailreport( $logfile, $adminmail ); } if ( $debug == 0 ) { unlink $logfile; } exit (0); } # Check to see if we have really somthing to log to. if ( $maillog == 0 && $syslog == 0 ){ print (STDERR "Error: nothing to log to. Both mail and syslog disabled. Check configuration. \n"); exit (1); } # Check the way we want to log and start checking. if ( $syslog == 1 ){ if ( $osystem eq "Linux" || $osystem eq "FreeBSD" ){ setlogsock('unix'); } openlog ('pcds', 'nowait', 'user'); } getprocs(); difflist(); # Send an emailreport if requested. if ( $maillog == 1 ){ mailreport (); } # Do some clean-up.... if ( $syslog == 1 ){ closelog (); } if ( $debug == 0 ) { unlink $currlist; unlink $logfile; } exit (0);