#/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  [email protected] 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");

}