From: Nelson Elhage Date: Sun, 20 Sep 2009 23:32:29 +0000 (-0400) Subject: Import crondiff X-Git-Url: https://snippets.scripts.mit.edu/gitweb.cgi/Scripts/git/.git/commitdiff_plain/b0e0b6e8f67bf2ce7cf9da9fb451f91dd2146968 Import crondiff --- diff --git a/crondiff/crondiff.pl b/crondiff/crondiff.pl new file mode 100644 index 0000000..b30cb46 --- /dev/null +++ b/crondiff/crondiff.pl @@ -0,0 +1,101 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); + +=head1 NAME + +crondiff.pl - Run command periodically and compare their output. + +=head1 DESCRIPTION + +crondiff.pl is designed to be run from cron periodically. It takes as +input a list of commands to run. Each time it is invoked, it runs the +commands listed, and sends mail to the user running the script if the +output of that command has changed since the last run. + +=head1 USAGE + +=over 4 + +=item + +Create a file C<~/.crondiff/cmdlist>, containing one line per file, of +commands to be checked. + +=item + +Add C to your crontab. The following example runs it +directly out of the locker (not necessarily a good idea!) every hour: + + # m h dom mon dow command + 0 * * * * PATH=/bin:/usr/bin: perl /mit/snippets/crondiff/crondiff.pl + +=back + +=head1 ASSUMPTIONS + +=over 4 + +=item + +Mail goes to C<$USER@mit.edu>, for the user who runs this script. + +=item + +Mail will be sent using C. + +=back + +If you don't like these assumptions, patches are welcome :) + +=cut + +my $confdir = $ENV{HOME} . "/.crondiff"; +unless($ENV{USER}) { + chomp(my $user = `id -un`); + $ENV{USER} = $user; +}; +my $mailto = $ENV{USER} . '@mit.edu'; +my @mailer = qw(mutt -x); + +my $cachedir = "$confdir/cache"; + +mkdir("$cachedir") unless -e "$cachedir"; + +open(my $clist, "<", "$confdir/cmdlist") + or exit; + +while(my $cmd = <$clist>) { + chomp($cmd); + my $hash = md5_hex($cmd); + my $pid = fork; + if($pid == 0) { + # Child + close(STDOUT); + close(STDERR); + open(STDOUT, ">>", "$cachedir/$hash.new"); + open(STDERR, ">>", "$cachedir/$hash.new"); + exec($cmd); + } + waitpid($pid, 0); + if($? != 0) { + # Exited with error, should send mail, but punting for now. + unlink("$cachedir/$hash.new"); + next; + } elsif(-f "$cachedir/$hash" + && system("diff -q $cachedir/$hash.new $cachedir/$hash > /dev/null 2>&1") != 0) { + # Output changed + if(($pid = fork) == 0) { + close(STDOUT); + open(STDOUT, "|-", @mailer, $mailto, '-s', "Output of [$cmd]"); + system("date"); + print "----\n"; + system("diff", "-u", "-U", "0", "$cachedir/$hash", "$cachedir/$hash.new"); + exit; + } else { + waitpid($pid, 0); + } + } + rename("$cachedir/$hash.new", "$cachedir/$hash"); +}