Stellarcore.net

Stellarcore.net

This code sample is a Daemon Watcher first developed by Tim Baker when we worked at Cox Interactive Media. I liked it so much I made some improvements here and there, and now use it as standard tool for all system installs. This version came straight from a Solaris 8 machine.

Generally the cron looks like

#Daemon checker
15,30,45,59 * * * * /admin/global/bin/check_daemon.pl >> /var/adm/log/check_daemon.log

Don't forget to rotate the logs this generates.

#!/bin/perl

# ========================================================================
# File    : check_daemons.pl
# Purpose : Runs from cron.
# Author: Tim Baker & Mike Tremaine mgt-@@-stellarcore.net
# ========================================================================
# This is cron'd to run once every  15mins (0,15,30,45) 

use strict;

&init_global();

#Check Daemons everytime we run
foreach my $daemon( keys %{ $global::daemons } ) {
  &check_daemon( $daemon );
  }

exit;


# ------------------------------------------------------------------------
# init_global() - setup the Lumberjack stream
#
# in    : none
# out   : none
# glob	: Lots
# err   : none
# notes : none
# ------------------------------------------------------------------------

sub init_global {

#Logs
$global::log_file 		= "check_daemon.log";
$global::log_dir		= "/var/adm/log/check_daemon.log";
$global::run_dir		= "/var/run";

#Commands
$global::p_rm			= "/bin/rm";
$global::p_xargs		= "/bin/xargs";
$global::p_find			= "/bin/find";
$global::ps_cmd     	= '/bin/ps';
$global::ps_flags   	= '-f -p';
$global::grep_cmd   	= '/bin/grep';
$global::grep_flags 	= '';

#Daemon Config
# Info about the daemons to watch
$global::daemons = {
	prngd  => {
		greptest => 'prngd',
		pidfile  => "$global::run_dir/prngd.pid",
		command  => "/etc/init.d/prngd start"
			   },
	sshd  => {
		greptest => 'sshd',
		pidfile  => "$global::run_dir/sshd.pid",
		command  => "/etc/init.d/sshd start"
			   },
	sendmail  => {
		greptest => 'sendmail',
		pidfile  => "$global::run_dir/sendmail.pid",
		command  => "/etc/init.d/sendmail start"
			}
	};

#Time values for functions
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year = $year + 1900;
$mon = $mon + 1;

if ($min < 10) { $min = "0" . $min; };
if ($mon < 10) { $mon = "0" . $mon; };
if ($mday < 10) { $mday = "0" . $mday; };
if ($hour < 10) { $hour = "0" . $hour; };

$global::timestamp = "[" . $mon . "/" . $mday . "/" . $year . "  " . $hour . ":" . $min . " ]";

} # sub init_global

#######################################
#Check Daemons

sub check_daemon {

  my $daemon    = shift;

  my $grep_test = $global::daemons->{$daemon}->{greptest};
  my $pid_file  = $global::daemons->{$daemon}->{pidfile};

  # if there's a PID file , see if that process is running
  if( open( PID, "< $pid_file" ) ) {
    chomp( my $pid =  );
    close PID;

    my $call = "$global::ps_cmd $global::ps_flags $pid | " .
               "$global::grep_cmd '$grep_test' | $global::grep_cmd -v 'tail -f '";

    my @daemons = grep { index( $_, 'grep' ) == -1 } `$call`;

    # if it is running
    if( (scalar @daemons) ) {
	  print "$global::timestamp daemon $daemon is running\n";
      return;
    }
    else {
    #make sure the daemon is not running under another PID
	my $call = "$global::ps_cmd -ef | $global::grep_cmd '$grep_test' | " .
	"$global::grep_cmd -v grep | $global::grep_cmd -v 'tail -f '";
			  
	 my @daemons = `$call`;
				  
	 if( (scalar @daemons) ) {
	  print "$global::timestamp daemon $daemon is running but PID file is wrong\n";
	  my $pid_restore = "$global::ps_cmd -ef | $global::grep_cmd '$grep_test' ".
	  "| $global::grep_cmd -v grep | $global::grep_cmd -v 'tail -f ' | awk '{ print \$2 }'";
	  `$pid_restore > $pid_file`;
	  print "$global::timestamp daemon '$daemon' $pid_file file created\n";
	  return; 
	 } else {
	  print "$global::timestamp daemon '$daemon' is not running," .
	  "but it left a PID file behind\n";
	 
	  # ...and restart the daemon
	  start_daemon( $daemon );
	 }

    }
  }
  else {
    # is there a daemon running without a pid file?
    my $call = "$global::ps_cmd -ef | $global::grep_cmd '$grep_test' | " .
      "$global::grep_cmd -v grep | $global::grep_cmd -v 'tail -f '";

    my @daemons = `$call`;

    # daemon is already running
    if( (scalar @daemons) ) {
      print "$global::timestamp daemon '$daemon' is running with no PID file\n";
	  #print @daemons;
	  #Be nice to make one -mgt
	  my $pid_restore = "$global::ps_cmd -ef | $global::grep_cmd '$grep_test'" .
	  "| $global::grep_cmd -v grep | $global::grep_cmd -v 'tail -f ' | awk '{ print \$2 }'";
	  `$pid_restore > $pid_file`;
      return;
    }
    else {
      print "$global::timestamp daemon '$daemon' is not running\n";
      start_daemon( $daemon );
    }
  }

} # sub check_daemon

# ------------------------------------------------------------------------
# start_daemon() - start up a daemon
#
# in    : the key of the daemon in the global daemons hash
# out   : none
# mod   : none
# glob  : $global::daemons
# err   : none
# notes : none
# ------------------------------------------------------------------------

sub start_daemon {

  my $daemon = shift;

  my $cmd    = $global::daemons->{$daemon}->{command};

  print "$global::timestamp restarting daemon '$daemon'\n";
  system ( $cmd ) == 0 || do {
    print "$global::timestamp Unable to spawn $cmd: $!\n";
    return;
  };
  print "$global::timestamp daemon '$daemon' restarted\n";

} # sub start_daemon