Added hung check handling
[chksht.git] / runcheckdir
1 #!/usr/bin/perl
2 use File::Basename;
3 use strict;
4
5
6 my $dir = shift;
7 unless (-d $dir) {
8         print "Arg is not a directory";
9         exit 1;
10 }
11 my $me = basename $dir;
12 my ($status, $details);
13
14 sub do_command {
15         my $command = shift;
16         $command =~ /^(\w+)(\s+(.*))?$/;
17         my ($do, $args) = ($1, $3);
18         if ($do eq 'mail') {
19                 open MAIL, '|-', qq!mail -s "$me $status" $args! or die "Could not mail";
20                 print MAIL $details,"\n";
21                 close MAIL;
22         } elsif ($do eq 'exec') {
23                 system($args);
24         } elsif ($do eq 'pipe') {
25                 open PIPE, '|-', $args;
26                 print PIPE "$status\n";
27                 print PIPE $details;
28                 close PIPE;
29         }
30 }
31
32
33 my ($checkcommand, $every, %on);
34 $on{success} = [];
35 $on{failure} = [];
36 $on{change} = [];
37
38 open CONFIG, "$dir/check";
39 while (<CONFIG>) {
40         my @words = split(/\s+/);
41         my $command = shift @words;
42         if ($command eq 'check') {
43                 $checkcommand = join(' ', @words);
44         } elsif ($command eq 'on') {
45                 my $when = shift @words;
46                 if ($when eq 'failure') {
47                         push @{$on{failure}}, join(' ', @words);
48                 } elsif ($when eq 'success') {
49                         push @{$on{success}}, join(' ', @words);
50                 } elsif ($when eq 'change') {
51                         push @{$on{change}}, join(' ', @words);
52                 } else {
53                         print "Unknown event in 'on', $dir/check line $.\n";
54                 }
55         } elsif ($command eq 'every') {
56                 $every = $words[0];
57         } else {
58                 print "Unknown command '$command', $dir/check line $.\n";
59         }
60 }
61 close CONFIG;
62
63 unless ($checkcommand) {
64         print "Check command not specified in $dir/check\n";
65         exit 1;
66 }
67 unless (@{$on{failure}} || @{$on{success}} || @{$on{change}}) {
68         print "No actions specified in $dir/check. This is probably a mistake.\n";
69 }
70
71 open STATUS, "$dir/checkstatus";
72 chomp(my $oldstatus = <STATUS>);
73 my $oldtime = (stat(STATUS))[9];
74 close STATUS;
75
76 my $td = time() - $oldtime;
77 if ($td < $every) {
78         # Not time to recheck yet
79         #print "Not rechecking; ", $every - $td, " seconds to go.\n";
80         exit $oldstatus;
81 }
82
83 my ($pid, $hung, $exitstatus);
84 $SIG{ALRM} = sub {
85         kill 9, $pid;
86         $hung = 1;
87 };
88 alarm 10;
89
90 $pid = open CHECK, '-|', $checkcommand;
91 $status = <CHECK>;
92 $details = join('', <CHECK>);
93 close CHECK;
94 if ($hung) {
95         $status = 'TIMEOUT';
96         $details = 'Check did not complete within ten seconds';
97         $exitstatus = -1;
98 } else {
99         $exitstatus = $? >> 8;
100 }
101
102 if ($exitstatus == 0 && $oldstatus != 0) {
103         do_command($_) foreach @{$on{success}};
104 }
105 if ($exitstatus != 0 && $oldstatus == 0) {
106         do_command($_) foreach @{$on{failure}};
107 }
108 if ($exitstatus != $oldstatus) {
109         do_command($_) foreach @{$on{change}};
110 }
111
112 open STATUS, ">$dir/checkstatus";
113 print STATUS "$exitstatus\n";
114 print STATUS "$status\n";
115 print STATUS "$details\n";
116 close STATUS;
117
118 exit $exitstatus;