#/usr/local/bin/perl
#
# @(#) backup  22-Jul-91
# use line in crontab like this :
# 0 22 * * * /usr/etc/sysadm/backup >/dev/null 2>&1
# or call directly using e.g. backup -d thurs
#
# RAN 26-Jan-93 remove surf (sob, sob)
# RAN 12-Sep-92 allow incremental backup of one machine to be split
# RAN 10-Sep-92 allow full backup of one machine to be split
# IAN 09-Sep-92 put in /techs, remove /news from brimstone
# RAN 24-Jul-92 remove ariel
# RAN 23-May-92 put hostname into mail subject line
# RAN 09-May-92 put hostname into report line
# RAN 06-May-92 change Tuesday so fairy doesn't run out of tape
# RAN 18-Feb-92 move fairy to different day (Tuesday)
# RAN 17-Feb-92 add failure lines to summary
# RAN 29-Jan-92 use backup@brimstone:/dev/nrst1 to remove security hole
# RAN 09-Jan-92 modified to change $0 during run
# RAN 31-Dec-91 modified summary, added filename to report
# RAN 31-Dec-91 changed dump parameters
# RAN 31-Dec-91 added catching of signals
# RAN 26-Dec-91 added summary
# RAN 26-Dec-91 added saving of backuplogs to directory
# RAN 31-Oct-91 ariel had /usr/local/course removed.
# RAN 08-Oct-91 fairy added, brimstone has incremental every day
# Copyright (C) Richard Nuttall  richard@pipex.net All rights reserved.
# You may use this and change it so long as the copyright message stays

require "abbrev.pl";
require "getopts.pl";
require "helpers.pl";

&Getopts('Hd:h:l:r');
$usage = "[-H] [-d day] [-h host] [-l level] [-r]";
%help =
(
   'H',"print this help text",
   'h',"host to dump from",
   'l',"level of dump",
   'd',"day of week - defaults to today",
   'r',"report to stdout as well as file",
);

@days =('monday','tuesday','wednesday','thursday','friday','saturday','sunday','special');

%abbrev = ();
&abbrev(*abbrev,@days);

&today;
$day = $opt_d ? $opt_d : $DAY;
$day =~ tr/A-Z/a-z/;
$Day = $abbrev{$day};

$level = ($opt_l =~ /\d/) ? $opt_l : 5;
$host = $opt_h if $opt_h;

# check for number of args
&usage() if $opt_H || $#ARGV != -1;

die "No such day $day, stopping" unless $host || $Day;

$SIG{'INT'} = 'cleanup';
$SIG{'HUP'} = 'cleanup';
$num = 1; # number of file on tape, starts at 1
$who = 'backup';
$tempdir = '/brimstone/home/tmp';
$device = '/dev/nrst1';
$tapehost = 'brimstone';
$tapeuser = 'backup';
$revdate = $YEAR.$MON.$MDAY;
&today;
$logdir = "/home/backuplogs";
$logbase = "$logdir/$revdate";
$uniq = 1;
$logfile = "$logbase.$uniq";
while( -f $logfile)
{
   $uniq++;
   $logfile = "$logbase.$uniq";
}
$filew = length($logfile);
$hostw = length($tapehost);

# all hosts and the partitions you want to backup
%hosts = (
   'brimstone','/home /usr /export /var / /unipalm /archive /techs',
   'flash','/ /usr /src /src2 /oldroot /oldroot/usr',
   'bold','/ /usr /files',
   'unipalm','/ /usr /home',
   'fairy','/ /usr /home /src /src2',
);

# if you need to split all file systems on a host among several nights
%splits = (
   'brimstone1','/home /usr /export /var / /unipalm',
   'brimstone2','/archive /techs',
   'fairy1','/ /usr /home /src',
   'fairy2','/src2',
);

# list of all hosts for convenience
@hosts = (
   'brimstone',
   'flash',
   'bold',
   'wisk',
   'fairy',
   #'ariel',
   'unipalm',
);

#############################
# Main program starts here
#############################

$startday = $TODAY;
&report("Backup log for $TODAY from [$tapehost]");
&report("Saved in file $logfile");
die "Cannot access backup device [$device] on [$tapehost], stopping"
   unless &mtstat();
&rewind();

if ($host)
{
   &report("Manual backup of [$host], level [$level]");
   $pstype = "[manual]";
   &dump($host,$level) if &ping($host);
}
else
{
   &report("Manually actioned Backup") if $opt_d;
   &report("Backup for [$Day]");
   $pstype = "[$Day]";
   eval("&$Day()");
}

$normal++;
&cleanup;
############################
# subroutines below here
############################

# Day by day backups
# Use '&incremental' and '&full' with hosts from @hosts
sub monday
{
   &incremental('brimstone');
   &full('flash','bold');
}

sub tuesday
{
   &incremental('brimstone');
   &full('fairy1');
}

sub wednesday
{
   &incremental('brimstone2');
   &full('brimstone1');
}

sub thursday
{
   &incremental('brimstone');
   &full('unipalm');
   &full('fairy2');
}

sub friday
{
   &incremental('brimstone1');
   &full('brimstone2');
}

# used if not the default daily backup
sub special
{
   &report("Special manual for [@hosts]");
   &check(@hosts);
   &report("End of Backup log for $startday");

   system("/usr/ucb/Mail -s \"Backup log of [$tapehost] for $startday\" $who < $logfile");

   unlink($logfile);
   exit 0;
}

# support functions

sub incremental
{
   local($host);

   foreach $host (@_)
   {
     local($realhost) = $host;

     chop($realhost = $host) if $splits{$host};
     next if ( ! &ping($realhost) );
     &dump($host,5);
   }
}

sub check
{
   local($host,$ret);

   foreach $host (@_)
   {
     $ret = &ping($host);
     &report("Ping of [$host] returns [$ret]");
   }
}

sub full
{
   local($host);

   foreach $host (@_)
   {
     local($realhost) = $host;

     chop($realhost = $host) if $splits{$host};
     next if ( ! &ping($realhost) );
     &dump($host,0);
   }
}

sub dump
{
   local($Host,$level) = @_;
   local($command);
   local($fs);
   local($fss);
   local($host) = $Host;

   if ($splits{$Host})
   {
      chop($host = $Host);
      $fss = $splits{$Host};
   }
   else
   {
      $fss = $hosts{$host};
   }

   local(@fs) = split(' ',$fss);
   local($ret);
 
   &report("\nWill dump [$fss] from [$host]");
   foreach $fs (@fs)
   {
      if ($host eq $tapehost)
      {
         $command = "/usr/etc/dump $level" .
                    "ucbsdf 56 5190 41000000 $device $fs";
      }
      else
      {
         $command = "/usr/ucb/rsh $host /usr/etc/rdump $level" .
                    "ucbsdf 56 5190 41000000 ${tapeuser}@$tapehost:$device $fs";

      }
      &report($command);
      push(@list, sprintf("$TODAY %3.0d $level   $logfile %${hostw}s $fs",$num,$host));
      $0 = "BACKUP $pstype $TODAY ${host}:$fs";
      $num++;
      $ret = system("$command >> $logfile 2>&1");
      push(@list,"$TODAY Command returns [$ret] for above action") if $ret;
      &report("Command returns [$ret]\n") if $ret;
   }
   &report('');
}

sub ping
{
   local($host) = @_;
   $_ = `/usr/etc/ping $host 1`;
   return 1 if /is alive$/;
   if (/^no answer from/)
   {
      &report("\nCannot ping [$host], skipping this host\n\n");
      push(@list,"$TODAY Cannot ping [$host], skipping this host");
      return 0;
   }
   &report("Strange result [$_] from ping [$host], skipping this host\n");
   return 0;
}

sub mtstat
{
   return ! system("mt -f $device status > /dev/null 2>&1");
}

sub rewind
{
   $ret = system("mt -f $device rewind > /dev/null 2>&1");
   &fatal("Tape rewind command failed, error code [$ret]") if $ret;
   &report("Rewinding tape") unless $ret;
}

sub eject
{
   &rewind();
   $ret = system("mt -f $device offline > /dev/null 2>&1");
   &report("Tape eject command failed, error code [$ret]\n") if $ret;
   &report("Ejecting tape\n") unless $ret;
}

sub fatal
{
   open(LOG,">> $logfile") || die "Cannot open [logfile], stopping";
   print(LOG @_,"\n");
   print(LOG "\nFATAL ERROR, DUMP ABORTED\n");
   close(LOG);
   exit(1);
}

sub report
{
   open(LOG,">> $logfile");
   print(LOG @_,"\n");
   close(LOG);
   print(@_,"\n") if $opt_r;
}

sub cleanup
{
   $0 = "BACKUP $pstype $TODAY cleaning up";
   &report("\nAbnormal exit, cleaning up") unless $normal;
   &eject();
   &today;
   &report("Backup for [$Day] finished at $TIME on $TODAY");
   &report("\nSummary follows :");
   &report(sprintf("\nDate      Num Lev %-${filew}s %${hostw}s Filesystem\n",
      "File","Host"));
   foreach (@list)
   {
      &report($_);
   }

   system("/usr/ucb/Mail -s \"Backup log of [$tapehost] for $startday\" $who < $logfile");

}