#!/usr/bin/perl -w # # run_if_modified # # AUTHOR: # Dan Harkless # # COPYRIGHT: # This file is Copyright (C) 2008 by Dan Harkless, and is released under the # GNU General Public License . # # USAGE: # % run_if_modified [-v] # # EXAMPLE: # % run_if_modified /var/named/DNSBLs/bind-list.dsbl.org \ # "sudo -u dsbl_u rsync -t rsync.dsbl.org::dsbl/bind-list.dsbl.org ." \ # "rndc reload" # # DESCRIPTION: # run_if_modified will examine the modification timestamp on the specified # , run , and then, if the timestamp has been modified, # run . # # Note that if has a leading path, run_if_modified will cd to that # directory before doing anything else. # # -v may be specified as a first, optional parameter for a verbose reckoning # (printed to stdout) of what's going on. # # The example above portrays using run_if_modified in a case where you have a # DNS zone you need to load via some other method than normal zone transfer, # like a DNS Blackhole List retrieved by rsync or wget. The example given # would be put in root's crontab (or the crontab of another user that has # 'rndc reload' privileges) -- the sudo as user dsbl_u is so that if there's a # security hole in your retrieval command (like the one found in wget in late # 2002) that allows arbitrary files owned by the user running the command to # be overwritten by a malicious server, damage will be restricted to that # (hopefully single-purpose) user. # # DATE MODIFICATION # ========== ================================================================== # 2008-09-02 "use English qw(-no_match_vars)": avoid regex performance penalty. # 2003-03-10 If a command run by system() returns nonzero status, $OS_ERROR # will be set to "No such file or directory.", so it's not # appropriate to print it in this situation. # 2003-02-21 Original. ## Modules used ################################################################ use English qw(-no_match_vars); # allow use of names like @ARG rather than @_ use File::Basename; # for basename() and fileparse() ## Prototypes ################################################################## sub my_die; sub my_system; sub verbose; ## Subroutines ################################################################# sub my_die { print STDERR "$progname: @ARG Aborting.\n"; exit 1; } sub my_system { verbose("system(\"@ARG\")"); system(@ARG) == 0 or my_die("system(\"@ARG\") returned nonzero status."); } sub usage{ print STDERR "Usage: $progname [-v] \n"; exit 1; } sub verbose{ if ($verbose) { print "$progname: @ARG\n"; } } ## Main ######################################################################## $progname = basename($PROGRAM_NAME); if (scalar(@ARGV) < 3) { usage(); } if ($ARGV[0] eq "-v") { shift; $verbose = 1; } if (scalar(@ARGV) != 3) { usage(); } $file_with_path = shift; $update_command = shift; $if_modified_command = shift; ($file, $dir) = fileparse($file_with_path); verbose("chdir(\"$dir\")"); chdir($dir) or my_die("chdir(\"$dir\"): $OS_ERROR."); @file_stat = stat($file); if (not @file_stat) { $old_modtime = 0; print STDERR "$progname: Warning: stat(\"$file\"): $OS_ERROR.\n"; } else { $old_modtime = $file_stat[9]; verbose('$old_modtime = ' . $old_modtime); } my_system($update_command); @file_stat = stat($file); if (not @file_stat) { my_die("stat(\"$file\"): $OS_ERROR."); } $new_modtime = $file_stat[9]; verbose('$new_modtime = ' . $new_modtime); if ($old_modtime != $new_modtime) { my_system($if_modified_command); }