Listing 1: dnatRpt Perl script


#!/usr/local/bin/perl
#=====================================================
# AUTHOR: Dave Brillhart
# FILE:   dnatRpt
#-----------------------------------------------------
# This PERL program checks every host listed in a
# selectable configuration file for connectivity.
# If reachable - it determines how long the host has
# been up. The program then generates and optionally
# mails a report based on its findings. UNIX (and
# optionally VMS via DECnet) hosts can be checked.
#
# Usage: dnatRpt [ -rpt -silent hostnameFile ]
#
# Rtn_Value: #_hosts_unavailable
#=====================================================

#-----------------------------------------------------
$rcPath   = "/usr/local/etc/";
$rptFile  = "/tmp/dnatRpt_$$";
$chkFile  = "/tmp/dnat911";
$rID      = "peru";
$rdclCmd  = "/usr/local/bin/rdcl";
$pingCmd  = "/usr/etc/ping";
$rshCmd   = "/usr/ucb/rsh";
$rupCmd   = "/usr/local/bin/rup";
$mailCmd  = "/usr/ucb/mail";
$dow      = (Sunday,Monday,Tuesday,
             Wednesday,Thursday,Friday,
             Saturday,Sunday)[(localtime)[6]];
$sub      = "Downtime Tracking Status Report - $dow";
#-----------------------------------------------------

$rpt = 0; $silent = 0; $rcFile = "dnatHosts"; $| = 1;
while ($ARGV[0]) {     # digest command line options #
  if    ($ARGV[0] eq "-rpt")   { $rpt   = 1; }
  elsif ($ARGV[0] eq "-silent") { $silent = 1; }
  else  { $rcFile = $ARGV[0]; }
  shift;
}

open(HOSTS,"<$rcPath$rcFile") ||
  die "Can't open $rcPath$rcFile file.\n";
open(RPT,">$rptFile") ||
  die "Can't open $rptFile file.\n";
open(CHK,">$chkFile") ||
  die "Can't open $rptFile file.\n";

if ($silent == 0 && $rpt == 0)
  { print "\n[ DNAT: Will NOT mail reports. ]\n"; }
elsif ($silent == 0 && $rpt == 1)
  { print "\n[ DNAT: Will mail reports. ]\n"; }

print RPT "***************************************\n";
print RPT "******   System Status Report    ******\n";
print RPT "***************************************\n";

#----------------------------------------------------#
# Main loop - Check each host and generate report    #
#----------------------------------------------------#
$ucnt = $rcnt = 0;            # host status counters #
while ($host = <HOSTS>)  # process all hosts in file #
{
  chop $host;                      # remove new line #
  $host =~ y/ / /s;    # squeeze spaces into 1 space #
  if (length($host) < 2) { next; }     # skip blanks #
  if ($host =~ m/^\#.*$/) { next; }  # skip comments #

  #--------------------------------------------------#
  # if the line is enclosed in double quotes, it is  #
  # interpreted as a section header for the report.  #
  #--------------------------------------------------#
  if ($host =~ m/^\"(.*)\"$/) {
    print RPT "\n$1\n";
    print RPT "-----------------------------------\n";
    next;             # get next line from host file #
  }

  $pos = index($host,"#");  # parse in-line comments #
  if ($pos > -1) { $host = substr($host,0,$pos); }
  if ($silent == 0) { print "\n + processing $host"; }
  #--------------------------------------------------#
  # if the hostname ends in "::" then use DECnet and #
  # derive uptime from the top of "show system" cmd. #
  #--------------------------------------------------#
  if ($host =~  m/^([^:]+)::.*$/) {
    $host = $1;         # strip off the double colon #
    $cmd = "$rdclCmd $host show system 2>&1 |";
    open(CMD, $cmd) ||
      die "ERROR: Couldn't run $cmd: $!\n";
    $available = 0; $uplong = 0;
    while ($cmdLine = <CMD>) {
      chop $cmdLine;
      if ($cmdLine =~
          m/^.*\s+Uptime\s+(\d+)\s+([\d:]+)/) {
        $available = 1; $days = $1;
      }
      if ($available == 1 && $days > 0)
        { $uplong = 1; }
    }
    close(CMD);
  }
  #--------------------------------------------------#
  # otherwise it must be UNIX, use TCP/IP, try 'rup' #
  # first (faster), then 'rsh' if rup fails.         #
  #--------------------------------------------------#
  else {
    # if string "alive" is missing, host unavailable #
    $available = 0;
    $ping = `$pingCmd $host 2>&1`;
    if ($ping =~ m/^.*alive.*$/) { $available = 1; }
 
    $uptime = $uplong = $rupOK = 0;
    if ($available) {    # host alive, go get uptime #
      $uptime = `$rupCmd $host 2>&1`;
      if ($uptime =~ m/^.* up .*$/) { $rupOK = 1; }
      if ($rupOK) {   # rup command appeared to work #
        if ($uptime =~ m/^.*up (.*) day.*$/)
          { $uplong = 1; $days = $1; }
      }
      else {       # rup failed, try rsh'ing to host #
        $uptime = `$rshCmd $host -l $rID uptime 2>&1`;
        if ($uptime =~ m/^.*up (.*) day.*$/)
          { $uplong = 1; $days = $1; }
      }
    }
  }

  #--------------------------------------------------#
  # append host status to the end of report file     #
  #--------------------------------------------------#
  if ($available == 0) {
    printf(RPT "%-15s %s\n",$host,
           "** HOST UNAVAILABLE **");
    printf(CHK "%-15s %s\n",$host,
           "** HOST UNAVAILABLE **");
    if ($silent == 0) { print "... ** UNAVAILABLE!"; }
    $ucnt++;
  }
  elsif ($uplong == 0) {
    printf(RPT "%-15s %s\n",$host,
           "** HOST RESTARTED **");
    printf(CHK "%-15s %s\n",$host,
           "** HOST RESTARTED **");
    if ($silent == 0) { print "... ** RESTARTED!"; }
    $rcnt++;
  }
  else {
    if ($silent == 0) { print "... OKAY!"; }
    printf(RPT "%-15s [up %3s days]\n",$host,$days);
  }
}

print RPT "\nTOTAL UNAVAILABLE: $ucnt  ";
print RPT " RESTARTED:    $rcnt\n";
print RPT "***************************************\n";
close(RPT); close(CHK);

if ($silent == 0)       # display report on /dev/tty #
  { print "\n"; system("cat $rptFile"); }

if ($rpt == 0)                 # do not mail reports #
  { unlink $rptFile; exit $ucnt; }

#----------------------------------------------------#
# Mail the DNAT report to all appropriate aliases.   #
# 'dnatSunday', 'dnatAdmin', & 'dnatAlert' are mail  #
# aliases defined in the /etc/aliases file.          #
#----------------------------------------------------#
if ($dow eq "Sunday") {         # Send to dnatSunday #
  $mc = "$mailCmd -s '$sub' dnatSunday < $rptFile";
  system($mc);
}
if ($rcnt > 0) { # Send to dnatAlert if any rebooted #
  ($sub1 = $sub) =~ s/Down/*ALERT* : Down/;
  $mc = "$mailCmd -s '$sub1' dnatAlert < $rptFile";
  system($mc);
}
else {             # Send to dnatAdmin every morning #
  ($sub1 = $sub) =~ s/Down/Daily Down/;
  $mc = "$mailCmd -s '$sub1' dnatAdmin < $rptFile";
  system($mc);
}

unlink $rptFile;
exit $ucnt;


