GOPHERSPACE.DE - P H O X Y
gophering on gopher.linkerror.com
#!/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;