]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/env perl | |
2 | use strict; | |
3 | use warnings; | |
4 | use Digest::MD5 qw(md5_hex); | |
5 | ||
6 | =head1 NAME | |
7 | ||
8 | crondiff.pl - Run command periodically and compare their output. | |
9 | ||
10 | =head1 DESCRIPTION | |
11 | ||
12 | crondiff.pl is designed to be run from cron periodically. It takes as | |
13 | input a list of commands to run. Each time it is invoked, it runs the | |
14 | commands listed, and sends mail to the user running the script if the | |
15 | output of that command has changed since the last run. | |
16 | ||
17 | =head1 USAGE | |
18 | ||
19 | =over 4 | |
20 | ||
21 | =item | |
22 | ||
23 | Create a file C<~/.crondiff/cmdlist>, containing one line per file, of | |
24 | commands to be checked. | |
25 | ||
26 | =item | |
27 | ||
28 | Add C<crondiff.pl> to your crontab. The following example runs it | |
29 | directly out of the locker (not necessarily a good idea!) every hour: | |
30 | ||
31 | # m h dom mon dow command | |
32 | 0 * * * * PATH=/bin:/usr/bin: perl /mit/snippets/crondiff/crondiff.pl | |
33 | ||
34 | =back | |
35 | ||
36 | =head1 ASSUMPTIONS | |
37 | ||
38 | =over 4 | |
39 | ||
40 | =item | |
41 | ||
42 | Mail goes to C<$USER@mit.edu>, for the user who runs this script. | |
43 | ||
44 | =item | |
45 | ||
46 | Mail will be sent using C<mutt -x>. | |
47 | ||
48 | =back | |
49 | ||
50 | If you don't like these assumptions, patches are welcome :) | |
51 | ||
52 | =cut | |
53 | ||
54 | my $confdir = $ENV{HOME} . "/.crondiff"; | |
55 | unless($ENV{USER}) { | |
56 | chomp(my $user = `id -un`); | |
57 | $ENV{USER} = $user; | |
58 | }; | |
59 | my $mailto = $ENV{USER} . '@mit.edu'; | |
60 | my @mailer = qw(mutt -x); | |
61 | ||
62 | my $cachedir = "$confdir/cache"; | |
63 | ||
64 | mkdir("$cachedir") unless -e "$cachedir"; | |
65 | ||
66 | open(my $clist, "<", "$confdir/cmdlist") | |
67 | or exit; | |
68 | ||
69 | while(my $cmd = <$clist>) { | |
70 | chomp($cmd); | |
71 | my $hash = md5_hex($cmd); | |
72 | my $pid = fork; | |
73 | if($pid == 0) { | |
74 | # Child | |
75 | close(STDOUT); | |
76 | close(STDERR); | |
77 | open(STDOUT, ">>", "$cachedir/$hash.new"); | |
78 | open(STDERR, ">>", "$cachedir/$hash.new"); | |
79 | exec($cmd); | |
80 | } | |
81 | waitpid($pid, 0); | |
82 | if($? != 0) { | |
83 | # Exited with error, should send mail, but punting for now. | |
84 | unlink("$cachedir/$hash.new"); | |
85 | next; | |
86 | } elsif(-f "$cachedir/$hash" | |
87 | && system("diff -q $cachedir/$hash.new $cachedir/$hash > /dev/null 2>&1") != 0) { | |
88 | # Output changed | |
89 | if(($pid = fork) == 0) { | |
90 | close(STDOUT); | |
91 | open(STDOUT, "|-", @mailer, $mailto, '-s', "Output of [$cmd]"); | |
92 | system("date"); | |
93 | print "----\n"; | |
94 | system("diff", "-u", "-U", "0", "$cachedir/$hash", "$cachedir/$hash.new"); | |
95 | exit; | |
96 | } else { | |
97 | waitpid($pid, 0); | |
98 | } | |
99 | } | |
100 | rename("$cachedir/$hash.new", "$cachedir/$hash"); | |
101 | } |