#!/usr/bin/perl # See copyright, etc in below POD section. ###################################################################### use lib 'blib/lib'; # testing use Cwd; use FindBin qw($RealBin $RealScript $Script); use Getopt::Long; use IO::File; use Pod::Usage; use Proc::ProcessTable; use Sys::Syslog; use Schedule::Load; use Schedule::Load::Schedule; use strict; use vars qw ($Debug $Restart_Cmd); BEGIN { $ENV{PATH} = '/usr/ucb:/bin:/usr/bin' } # Secure path $SIG{PIPE} = 'IGNORE'; $Restart_Cmd = "/etc/init.d/slchoosed restart"; ###################################################################### my $opt_fork = 1; my $opt_period; my $opt_timeout = 120; autoflush STDOUT 1; autoflush STDERR 1; Getopt::Long::config ("no_auto_abbrev"); if (! GetOptions ( "help" => \&usage, "debug" => \&debug, "version" => \&version, "fork!" => \$opt_fork, # Debugging/Test script "period=i" => \$opt_period, "timeout=i" => \$opt_timeout, )) { die "%Error: Bad usage, try 'slchoosed_watchd --help'\n"; } $opt_period ||= ($Debug ? 5 : 600); # We're chdiring to /, so make sure program name has path if ($0 !~ m!^/!) { $0 = getcwd()."/".$0; } chdir "/"; # Change immediately to aid debugging of $0 change if (!$Debug) { if ($opt_fork) { exit if fork(); # Fork once to let parent die POSIX::setsid(); # Disassociate from controlling terminal exit if fork(); # Prevent possibility of acquiring a controling terminal chdir "/"; # Change working directory so can umount . } # Close open file descriptors my $openmax = POSIX::sysconf( &POSIX::_SC_OPEN_MAX ); $openmax = (!defined($openmax) || $openmax < 0) ? 64 : $openmax; foreach my $i (0 .. $openmax) { POSIX::close($i); } # Silence please (in case user didn't pipe when starting us) open(STDIN, "+>/dev/null"); open(STDOUT, "+>&STDIN"); open(STDERR, "+>&STDIN"); } # Loop in case something kills us while (1) { print "Starting server: $Script\n" if $Debug; if (!$Debug) { openlog($Script, 'cons,pid', 'daemon'); syslog('info', 'Started'); closelog(); } my $pid; if (0==($pid = fork())) { while (1) { sleep ($opt_period); # Sleep first, so there isn't a race at first startup ok_or_kill(timeout=>$opt_timeout); } exit(0); } die "%Error: Server aborted\n" if !$opt_fork; waitpid($pid,0); } #---------------------------------------------------------------------- sub usage { print "Version: $Schedule::Load::VERSION\n"; pod2usage(-verbose=>2, -exitval => 2); exit(1); } sub version { print "Version: $Schedule::Load::VERSION\n"; exit (1); } sub debug { $Debug = 1; $Schedule::Load::Chooser::Debug = 1; } ###################################################################### sub ok_or_kill { my %params = (#timeout=> @_); if (!slchoosed_up(%params)) { print "Chooser looks sick..\n" if $Debug; if (!$Debug) { openlog($Script, 'cons,pid', 'daemon'); syslog('warning', "slchoosed_watchd restarted slchoosed after $params{timeout} sec hang"); closelog(); } print "\t$Restart_Cmd\n" if $Debug; system($Restart_Cmd); } } sub slchoosed_up { my %params = (#timeout=> @_); my $ok; eval { print "Contacting slchoosed...\n" if $Debug; local $SIG{ALRM} = sub { die "Timeout\n"; }; alarm($params{timeout}); # Always run on the local machine, even if it is in standby to a different slchoosed. my $scheduler = Schedule::Load::Schedule->fetch(dhost=>'localhost'); # Make sure we fetch the host list. It may be empty though. $scheduler->hosts; print " slchoosed reached.\n" if $Debug; $ok = 1; alarm(0); }; alarm(0) if $@; return $ok; } ###################################################################### __END__ =pod =head1 NAME slchoosed_watchd - Make sure the slchoosed stays up =head1 SYNOPSIS B [ B<--help> ] =head1 DESCRIPTION slchoosed_watchd will periodically ask the slchoosed server for information, and if it does not respond, restart it. This is rarely needed, as slchoosed is fairly standard, but provides another level of assurance for critical applications. =head1 ARGUMENTS =over 4 =item --help Displays this message and program version and exits. =item --nofork For debugging, prevents the daemon from creating additional processes and from going into the background. This allows messages to appear on stdout, and ctrl-C to stop the daemon. =item --period I Specify the period in seconds between scheduler requests. The default is 10 minutes. =item --timeout I Specify the longest acceptable delay in seconds. =item --version Displays program version and exits. =back =head1 DISTRIBUTION The latest version is available from CPAN and from L. Copyright 1998-2009 by Wilson Snyder. This package is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. =head1 AUTHORS Wilson Snyder =head1 SEE ALSO L, L =cut ######################################################################