#!/usr/bin/perl -w
use strict;

# become the guardian angel for a program
# and ressurect it when it dies.

####################
###### config ######
####################

# the application we are guarding
my $bin = '/some/binary';
my $bin_args = ''; # arguments to the binary
my $logfile = "/var/log/watchdog.log";
# end config

# signal handling
$SIG{HUP} = \&catch_hup;
$SIG{INT} = \&catch_int;

$| = 1; #unbuffer output
&init;
my $run = 1;
my $child_pid;
while ($run) {
	&run_bin;
}

# should never get here!
&log_line("$0 Dying");
exit 1;

#####################
######## SUBS #######

sub init {
	if (! -f $logfile) {
		open(LOG, ">$logfile") or die "$0: Couldn't open $logfile for writing: $!\n";
	}
	else {
		open(LOG, ">>$logfile") or die "$0: Couldn't open $logfile for writing: $!\n";
	}
	&log_line("initialized");
}

sub run_bin {
	undef $child_pid if $child_pid;
	$child_pid = fork();
	if ($child_pid == 0) {
		# this is the child process ..... when we exec() this process gets replaced with the application
		&log_line("Spawning child: $bin with pid $$");
		$bin .= " $bin_args" if $bin_args;
		# chatty binary? not anymore.
		open STDERR, '>/dev/null';
		open STDOUT, '>/dev/null';
		exec($bin);
	}
	else {
		# we are the parent
		waitpid($child_pid,0);
		# when the child dies waitpid will return ....
		&log_line("$bin died! Respawning ......");
	}
}

sub log_line {
	my $txt = shift;
	print LOG localtime()." $0: ".$txt."\n";
}

sub catch_hup {
	&bye_bye("HUP");
}

sub catch_int {
	&bye_bye("INT");
}

sub bye_bye {
	my $sig = shift;
	&log_line("received SIG$sig. Shutting down.");
	close LOG;
	&infanticide;
	undef $run;
	exit 0;
}

sub infanticide {
	kill(17, $child_pid); # send a SIGSTOP
	sleep 2; # give the child a chance to die
	if (kill(0, $child_pid) != 0) {
		# the child has not died yet ..... time to SIGKILL its ass
		kill(9, $child_pid);
	}
}
