Changed program names
[chksht.git] / runcheck
diff --git a/runcheck b/runcheck
new file mode 100755 (executable)
index 0000000..d6589f2
--- /dev/null
+++ b/runcheck
@@ -0,0 +1,118 @@
+#!/usr/bin/perl
+use File::Basename;
+use strict;
+
+
+my $dir = shift;
+unless (-d $dir) {
+       print "Arg is not a directory";
+       exit 1;
+}
+my $me = basename $dir;
+my ($status, $details);
+
+sub do_command {
+       my $command = shift;
+       $command =~ /^(\w+)(\s+(.*))?$/;
+       my ($do, $args) = ($1, $3);
+       if ($do eq 'mail') {
+               open MAIL, '|-', qq!mail -s "$me $status" $args! or die "Could not mail";
+               print MAIL $details,"\n";
+               close MAIL;
+       } elsif ($do eq 'exec') {
+               system($args);
+       } elsif ($do eq 'pipe') {
+               open PIPE, '|-', $args;
+               print PIPE "$status\n";
+               print PIPE $details;
+               close PIPE;
+       }
+}
+
+
+my ($checkcommand, $every, %on);
+$on{success} = [];
+$on{failure} = [];
+$on{change} = [];
+
+open CONFIG, "$dir/check";
+while (<CONFIG>) {
+       my @words = split(/\s+/);
+       my $command = shift @words;
+       if ($command eq 'check') {
+               $checkcommand = join(' ', @words);
+       } elsif ($command eq 'on') {
+               my $when = shift @words;
+               if ($when eq 'failure') {
+                       push @{$on{failure}}, join(' ', @words);
+               } elsif ($when eq 'success') {
+                       push @{$on{success}}, join(' ', @words);
+               } elsif ($when eq 'change') {
+                       push @{$on{change}}, join(' ', @words);
+               } else {
+                       print "Unknown event in 'on', $dir/check line $.\n";
+               }
+       } elsif ($command eq 'every') {
+               $every = $words[0];
+       } else {
+               print "Unknown command '$command', $dir/check line $.\n";
+       }
+}
+close CONFIG;
+
+unless ($checkcommand) {
+       print "Check command not specified in $dir/check\n";
+       exit 1;
+}
+unless (@{$on{failure}} || @{$on{success}} || @{$on{change}}) {
+       print "No actions specified in $dir/check. This is probably a mistake.\n";
+}
+
+open STATUS, "$dir/checkstatus";
+chomp(my $oldstatus = <STATUS>);
+my $oldtime = (stat(STATUS))[9];
+close STATUS;
+
+my $td = time() - $oldtime;
+if ($td < $every) {
+       # Not time to recheck yet
+       #print "Not rechecking; ", $every - $td, " seconds to go.\n";
+       exit $oldstatus;
+}
+
+my ($pid, $hung, $exitstatus);
+$SIG{ALRM} = sub {
+       kill 9, $pid;
+       $hung = 1;
+};
+alarm 10;
+
+$pid = open CHECK, '-|', $checkcommand;
+$status = <CHECK>;
+$details = join('', <CHECK>);
+close CHECK;
+if ($hung) {
+       $status = 'TIMEOUT';
+       $details = 'Check did not complete within ten seconds';
+       $exitstatus = -1;
+} else {
+       $exitstatus = $? >> 8;
+}
+
+if ($exitstatus == 0 && $oldstatus != 0) {
+       do_command($_) foreach @{$on{success}};
+}
+if ($exitstatus != 0 && $oldstatus == 0) {
+       do_command($_) foreach @{$on{failure}};
+}
+if ($exitstatus != $oldstatus) {
+       do_command($_) foreach @{$on{change}};
+}
+
+open STATUS, ">$dir/checkstatus";
+print STATUS "$exitstatus\n";
+print STATUS "$status\n";
+print STATUS "$details\n";
+close STATUS;
+
+exit $exitstatus;