#!/usr/bin/perl -w

#
#	Snafui.com - Perl script for checking that a mount is still connected
#
#  A perl script to be run by Cron to check whether a mounted file system is still mounted.
#  When developing I had samba in mind so my variables might reflect that, change as necessary.
#

use strict;
use Net::SMTP;

my $addr_from = 'from@email.addr';
my @addr_to   = ( 'to1@email.addr', 'to2@email.addr' );
my $host_smtp = 'localhost';
my $subject   = 'SMBMount Status';

#
#   List the mount points you want to watch. Best way to pull this off is to list a directory
#   inside your mountpoint because we'll be checking whether that exists or not.
#   If /mnt/server is our mount point, put /mnt/server/an_inside_dir
#

my @dirs = qw(
   /mnt/server/an_inside_dir/
);

my $lock_base = '/tmp/check_smbmount_status';


for my $dir ( @dirs )
{
   my $notification_flag_file = $dir;                                      # start with the directory we're scanning.
   $notification_flag_file =~ s/\//_/g;                                   # convert /mnt/server/an_inside_dir to _mnt_server_an_inside_dir.
   $notification_flag_file =~ s/\.\.//g;                                   # just making sure nothing funny happens with the path, sneaking '..' in there could be hairy.
   $notification_flag_file = $lock_base . '_' . $notification_flag_file;  # notif file name/path is now /tmp/check_smbmount_status__mnt_server_an_inside_dir

   if ( opendir(MNTDIR, $dir) )
   {
      # Check if there is a notification file. If so delete it and send a notification that things are back to normal.
      if ( -f $notification_flag_file )
      {
         unlink $notification_flag_file;

         if ( ! send_email($host_smtp, $addr_from, $subject, "$dir is back!", @addr_to) )
         {
            # If the email notification failed just print to Cron.
            print "$dir is back and SMTP notify failed\n";
         }
      }
   }
   else
   {
      my $error = $!;      # I get the feeling the -f op uses $! too so we'll copy it.

      next if ( -f "$notification_flag_file" );   # Skip notifying if we're already notified once.

      if ( send_email($host_smtp, $addr_from, $subject, "$dir is not readable: [$error]", @addr_to) )
      {
         # We use a temporary file to flag whether we've notified about this problem already so we don't do it repeatedly.
         open CREATENOTIF, ">$notification_flag_file";
         print CREATENOTIF '1';
         close CREATENOTIF;
      }
      else
      {
         #
         #  print something out for cron as a last ditch effort to notify that there was a problem.
         #
         print "$dir is not readable: [$!] and SMTP notify failed too.\n";
      }
   }
   closedir MNTDIR;
}


#
#   Send email via Net::SMTP. If constructor or methods fail then return undef, else return true.
#   Args are the SMTP host, From: addr, subject, message, and list of email addrs to send to.
#
sub send_email
{
   my ( $host_smtp, $from_addr, $subject, $message, @to_list ) = @_;

   my $smtp = Net::SMTP->new($host_smtp)                 or return;
      $smtp->mail($from_addr)                            or return;
      $smtp->to(@to_list)                                or return;
      $smtp->data()                                      or return;
      $smtp->datasend('To: ', join(', ',@addr_to), "\n") or return;
      $smtp->datasend("Subject: $subject\n")             or return;
      $smtp->datasend("\n")                              or return;
      $smtp->datasend("$message\n")                      or return;
      $smtp->dataend()                                   or return;
   return $smtp->quit();
}