#!/usr/local/bin/perl

#
#     Copyright (c) 1997  San Diego Supercomputer Center (SDSC)
#             San Diego, California, USA
#  
#     Users and possessors of this source code are hereby granted a
#     nonexclusive, royalty-free copyright and design patent license
#     to use this code in individual software.  License is not
#     granted for commercial resale, in whole or in part, without
#     prior written permission from SDSC.  This source is provided
#     "AS IS" without express or implied warranty of any kind.
# 

#
# rbackup.all - Performs 'dump' of filesystems to hpss:/backups,
#               based on "/etc/fstab".
#
# Author - Chris Daharsh
#          $Revision: 1.14 $
#          $Date: 1997/06/03 23:15:26 $
#

### BEGIN MAIN ###

if (@ARGV > 0) {
   if ($ARGV[0] =~ /^\d{1}$/) {
      $level = $ARGV[0];
   }
   else {
      print "Usage: rbackup.all <level>\n";
      exit(1);
   }
}

#
# Include file for system dependent variables.
#
require "/backups/localinfo.pl";

#
# Set non-system-dependent variables.
#
chop($start_time = `date`);
@date_fields = split(/\s+/, $start_time);
$year = $date_fields[5];
chop($date = `date +%m%d`);
$date = $year . $date;
chop($hostname = `/bin/hostname`);
$output_dir = "/scratch/rmtback/$hostname";
$report_log = '/backups/rbackup.log';
$failed_log = "/backups/$date.failed";
$lock_file = '/backups/rbackup.lock';
$report_to = 'backupcheckr@sdsc.edu';
$tvalue = '60';  # Predetermined value (KB/sec) for setting $timeout.
$pftp_put = '/usr/local/bin/pftp.exe hpss setcos 20, umask 537, put';
$pftp = '/usr/local/bin/pftp.exe hpss';

#
# Check for $lock_file, and report "exited" or "started".
#
open(MAIL, "|/usr/bin/mail $report_to");
if (-e $lock_file) {
   print MAIL "Subject: $hostname - Backup exited!\n\n$lock_file exists.";
   close(MAIL);
   exit(1);
}
open(LOCK, ">$lock_file");
print LOCK $$;              # Write PID to $lock_file.
close(LOCK);
print MAIL "Subject: $hostname - Backup started.\n\nPID $$";
close(MAIL);

#
# Deterimine level of backup based on 6 week cycle.
# week=(secs since start of 1970)/(secs in a week)%(cycle length in weeks)
#
if ($level eq "") {
   $week = time / (60*60*24*7) % 6;
   if ($date_fields[0] eq 'Sat') {
      if ($week eq $level_0) { $level = 0; }
      else { $level = 3; }
   }
   else { $level = 6; }
}

#
# Get the size of each filesystem for setting $timeout.
#
@df_out = `$df`;
foreach (@df_out) {
    @line = split(/\s+/, $_);
    $fs_size{@line[5]} = @line[2];
}

#
# Fork one "child" process for each filesystem.
#
$running = 0;
while ($fs = pop(@fs_list)) {
   $running++;
   unless (fork) { ########## Begin "child" Process
      $mfs = $fs;
      $mfs =~ s/\//=/g;                           # Replace all '/' with '='.
      setpgrp();                                  # Set GPID to PID.
      $SIG{'ALRM'} = 'child_handler';             # Set signal handler.
      $SIG{'TERM'} = 'child_handler';
      $timeout = ($fs_size{$fs}/$tvalue) + 600;   # Set timeout value.
      alarm($timeout);                            # Enable alarm.

      if (! -d $output_dir) {
         umask(0);
         mkdir($output_dir, 0755);
         umask(022);
      }
      open(STDOUT, ">$output_dir/$mfs.$date.dump") || die "Can't redirect stdout";
      open(STDERR, ">&STDOUT") || die "Can't dup stdout";
      select(STDERR); $| = 1;
      select(STDOUT); $| = 1;

      system("$pftp_put  \\|\\\"$dump ${level}sfu 1000000 - $fs\\\"  \
             /backups/$hostname/$mfs/$date.$level"); # Perform dump.

      $retval = $? >> 8;
      if ($retval) {
         write_to_failed_log($fs,$retval);
      }
      alarm(0);   # Disable alarm.
      exit(0);    # Exit "Grandchild" process.

      sub child_handler {   # First aurument is signal name.
         local($retval) = @_;
         write_to_failed_log($fs,$retval);
         kill(9, -$$);       # Kill this process and its children.
         exit(1);            # Just in case.
      }
   } ########## End "child" Process

   if ($running >= $max_children) {
      wait;
      $running--;
   }

} # End while loop

while ($running > 0) {        # Don't continue until all children are done.
   wait;
   $running--;
}

$isdeleted = unlink($lock_file);
if ($isdeleted == 0) {
   open(MAIL, "|/usr/bin/mail $report_to");
   print MAIL "Subject: $hostname - Could not delete $lock_file.\n";
   close(MAIL);
}

#
# Start gathering backup statistics, and write and deliver report.
#
chop($finish_time = `date`);

@dir_out = `$pftp dir /backups/$hostname/*/$date.$level`;

foreach (@dir_out) {
   @line = split(/\s+/, $_);
   $bytes += @line[4];
}
$mbytes = $bytes / 1048576;

if (-r $failed_log) {
   $num_failed = `wc -l $failed_log`;
   $num_failed = $num_failed / 2;
}
else { $num_failed = 0; }

$output = "------------------------------------------------------------------ \
Level:    $level \
Start:    $start_time \
Finish:   $finish_time \
Total MB: $mbytes backed up to HPSS \
Failed:   $num_failed \
------------------------------------------------------------------\n";

open(RLOG, ">>$report_log");
print RLOG $output;
close(RLOG);

open(MAIL, "|/usr/bin/mail $report_to");
print MAIL "Subject: $hostname - Backups completed.\n\n$output";
close(MAIL);
exit;

### END MAIN ###

#
# Function: Writes name of failed filesystem to $failed_log.
# Input: $fs from failing child process.
#        $retval for error checking.
#
sub write_to_failed_log {
   open(FLOG, ">>$failed_log");
   print FLOG "# $retval\n$fs\n";
   close(FLOG);
}

# End of File


