#!/usr/bin/perl #Written by Jeff Ohlman. #this perl script forks two processes, monitors them and then kills them if either process terminates with rc gt #allowed. #Copyright (C) 2002 Jeff Ohlman - jeffohlmanx@yahoo.com. Remove the x from my name to email me. # #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. # #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. # #for more information on GNU goto www.gnu.org use strict; use POSIX ":sys_wait_h"; use Config; sub baby_sitter; sub catch; my $kid; my $fork_1_pid; my $fork_2_pid; my $max_rc_1; my $max_rc_2; my %hash; die "Purpose: fork and monitor 2 processes\nUsage: monitor.pl \"command string 1\" \"command string 2\" \"max rc 1\" \"max rc 2\"\nNote: use double quotes if command has spaces.\n" if $#ARGV != 3; my $fork_1 = $ARGV[0]; my $fork_2 = $ARGV[1]; my $max_rc_1 = $ARGV[2]; my $max_rc_2 = $ARGV[3]; our $our_pgrp = $$ if ! defined $our_pgrp; our $rc; our $fork_1_pid = fork; defined ($fork_1_pid) or die "couldn't fork: ($!)"; if ( $fork_1_pid ) { sleep 1; our $fork_2_pid = fork; defined ($fork_2_pid) or die "couldn't fork: ($!)"; if ($fork_2_pid) { use sigtrap 'handler', \&catch, 'INT'; baby_sitter; } else { sleep 2; exec("$fork_2"); exit; } } else { sleep 2; exec("$fork_1"); exit; } sub catch { #this will trap any interupts and ensure that all children are terminated my $signame = shift; my $stdout = select(STDOUT); #so the log gets written during extended interupts $| = 1; print "SIG$signame received. Terminating process group $our_pgrp.\n"; select $stdout; my $i=0; { local $SIG{'INT'} = 'IGNORE'; kill( '-INT', $our_pgrp ); my $k; do { $k = waitpid(-1, &WNOHANG); #after 2 minutes and then exit - named pipes will cause a process to block. die "monitor.pl timed out waiting for process group to terminate\n" if $i++ > 120; sleep 1; } until $k == -1; } } sub baby_sitter { sleep 2; $hash{$fork_1_pid,'pid'}=$fork_1; $hash{$fork_2_pid,'pid'}=$fork_2; $hash{$fork_1_pid,'max'}=$max_rc_1; $hash{$fork_2_pid,'max'}=$max_rc_2; print "Process group is $our_pgrp.\n"; print "Child $hash{$fork_1_pid,'pid'} pid is $fork_1_pid. - it can have a max rc of $hash{$fork_1_pid,'max'}\n"; print "Child $hash{$fork_2_pid,'pid'} pid is $fork_2_pid. - it can have a max rc of $hash{$fork_2_pid,'max'}\n"; my $i=2; my $kid; while ( $i ) { do { $kid = waitpid(-1, &WNOHANG); sleep 1; } until ($kid != 0); $i--; our $rc=( $? >> 8 ); if ( $rc > $hash{$kid,'max'} ) { warn "monitor.pl detected a failure in process $kid\n"; warn "Process $kid return code is ", $rc >> 8, ".\n"; warn "Process $kid is \"$hash{$kid,'pid'}\"\n"; #the kill should transfer ctl to the handler routine kill ( 'INT', $$); } print "Process $kid complete - return code is $rc\n"; } } END { $?=$rc };