#!/usr/local/bin/perl -w # Globals --------------------------------------------------------------------- # Sane default location of the mtree executable. # Can be changed with the --mtree option. my $mtree="/usr/sbin/mtree"; # Sane default location of the mtree file checksum database. # Can be changed with the --checksum-file option. my $checksum_file="/usr/mtree/fs.mtree"; # Sane default location of the mtree file exclude list. # Can be changed with the --exclude-file option. my $exclude_file="/usr/mtree/fs.exclude"; # Stores the executable name, mainly to refer to ourselves in help. my $executable=$0; # Stores the list of filesystem changes reported by mtree. my $changes=""; # Stores the list of e-mail addresses to send results to. my @emails; # Whether or not to scan for file changes. # (default behavior, disabled in case of -uo) my $scan_for_changes=1; # Whether or not to update the checksums. (requires -u flag) my $update=undef; # Top level directory to monitor for changes. # (can be edited with the -p option.) my $path="/"; # Whether or not to print scan results to stdout. # (Default behavior, see -q option to disable.) my $print_results=1; # Path to the sendmail executable. # (see --sendmail option to change.) my $sendmail="/usr/sbin/sendmail"; # Logfile location. # (see -l option to change.) my $log="/var/log/mtree.log"; # e-mail reply-to address. (see --reply-to option) my $reply_to=undef; # e-mail subject (see --subject option). my $subject="Filesystem changes for " . `date`; # Display script usage & help. ------------------------------------------------ sub show_help { print ' Usage: ' . $executable . ' [OPTION] ... Show or E-mail out a list of changes to the file system. mtree operation options: -u, --update Updates the file checksum database after showing/mailing changes. -uo, --update-only Only update the file checksum database. -p, --path Top level folder to monitor (default: /) -q, --quiet Do not output scan results to stdout or any other output. Path configuration options: -l, --log Logfile location (default: /var/log/mtree.log) --mtree Set the location of the mtree executable. (default is /usr/sbin/mtree) --checksum-file Set the location of the file containing the mtree file checksums. (defaul: /usr/mtree/fs.mtree) --exclude-file Set the location of the file containing the list of files and folders to exclude from the mtree scan. (default is /usr/mtree/fs.exclude) E-mail options: -e, --email Adds specified e-mail address as destination. --sendmail Set the location of the sendmail executable. (default: /usr/sbin/sendmail) --reply-to Set the e-mail reply-to address. --subject Sets The e-mail subject. Misc options: -h, --help Display this help text. Example usage: ' . $executable . ' -uo ' . $executable . ' -u -q -e foo@example.com -e bar@example.com ' . $executable . ' /var/www --mtree /usr/local/sbin/mtree '; } # Parses a command line argument and it's param. ------------------------------ sub parse_commandline_argument { my $arg = shift; my $param = shift; if (substr($arg,0,1) eq '-') { if ($arg eq '--mtree') { $mtree = $param; } if ($arg eq '--sendmail') { $sendmail = $param; } if ($arg eq '-q' or $arg eq '--quiet') { $print_results = undef; } if ($arg eq '--reply-to') { $reply_to = $param; } if ($arg eq '--subject') { $subject = $param; } if ($arg eq '--checksum-file') { $checksum_file = $param; } if ($arg eq '-l' or $arg eq '--log') { $log = $param; } if ($arg eq '--exclude-file') { $exclude_file = $param; } if ($arg eq '-h' or $arg eq '--help') { show_help(); exit 0; } if ($arg eq '-e' or $arg eq '--email') { if ($param =~ m/\@/) { push(@emails,$param); } else { die "Invalid e-mail address: $param\n"; } } if ($arg eq '-u' or $arg eq '--update') { $update=1; } if ($arg eq '-uo' or $arg eq '--update-only') { $update=1; $scan_for_changes=undef; } } } # Script entry point. --------------------------------------------------------- # Parse commandline arguments. my $argc=0; foreach my $argument(@ARGV) { chomp($argument); if ($argc != $#ARGV) { my $next_argument = $ARGV[$argc+1]; chomp($next_argument); parse_commandline_argument($argument,$next_argument); } else { parse_commandline_argument($argument); } $argc++; } # Check if we have all the necesary components. (-x $mtree) or die "$mtree is not executable.\n"; (-w $checksum_file) or die "$checksum_file is not writeable.\n"; (-r $exclude_file) or die "$exclude_file is not readable.\n"; if ($scan_for_changes) { (-w $log) or die "$log is not writeable.\n"; } if ($#emails >= 1) { (-x $sendmail) or die "$sendmail is not executable.\n"; } if ($print_results) { print "\nScanning for changes...\n"; } # Get the list of changed files if desired. if ($scan_for_changes) { $changes=`$mtree -f $checksum_file -X $exclude_file -p $path`; # If there are no changes since last scan, then # we're done with everything. # <= 3 to account for \n\r and maybe a space... if (length($changes) <= 3 ) { if ($print_results) { print "All done.\n"; } exit 0; } # Write changes to log file. open LOGFILE,">>$log" or die $!; print LOGFILE $changes; close LOGFILE; # Output changes if desired. if ($print_results) { print "$changes\n"; } # E-mail out changes if desired. foreach my $mail(@emails) { if ($print_results) { print "E-mailing $mail ...\n"; } chomp($mail); open(SENDMAIL, "|$sendmail -t") or die "Cannot open $sendmail: $!"; print SENDMAIL "To: $mail\n"; if ($reply_to) { chomp($reply_to); print SENDMAIL "Reply-to: $reply_to\n"; } if ($subject) { chomp($subject); print SENDMAIL "Subject: $subject\n"; } print SENDMAIL "Content-type: text/plain\n\n"; print SENDMAIL $changes; close(SENDMAIL); } } # Update checksum file if desired. if ($update) { if ($print_results) { print "Updateing checksums...\n"; } system("$mtree -c -X $exclude_file -p $path > $checksum_file"); } if ($print_results) { print "All done.\n"; } # done. exit 0;