#!/bin/sh # For the beginning of the script, # search forward for "The script starts here:" # This script can be called as either # runbackup full # or # runbackup incremental # or # runbackup inc # (That last one is equivalent to incremental) # If we're called as "runbackup full", then we backup the complete # filesystem to tape. We write the file directly to tape, since it # probably wouldn't fit on the disk. # If we're called as "runbackup inc", then we do a listed incremental # backup of the complete filesystem, creating the file # $BACKUPFILENAME, and then we copy that file to tape. We leave that # file where it is, so that we can make a second copy of it to another # tape, if we so choose. # These two jobs are so different that they should probably be done in # different scripts, but putting them into the same script ensures # that they both use the same filenames for the listfile, logfile, # etc. # We assume that /dev/tape is a symlink to /dev/nht0, the # non-rewinding tape device (i.e., the device that does not # automatically rewind the tape after each write), because the "mt" # command uses the default device /dev/tape. # If this is not the case, edit the definition of "MTCOMMAND" below # to include the device as an argument to mt, as in # MTCOMMAND="/bin/mt -f /dev/nht0" # (in which you many also need to change the path to the mt command # if it's not in /bin). umask 022 #DIRTOBACKUP="/home /root /var/spool/mail /etc /var/log" DIRTOBACKUP=/ BACKUPDIR=/var/backups LOGFILE=$BACKUPDIR/Backups.log MESSAGEFILE=$BACKUPDIR/Backups.messages LISTFILE=$BACKUPDIR/Listfile.lst LASTBACKFILE=$BACKUPDIR/Lastbackup.date EXCLUDEFILE=$BACKUPDIR/Exclude.lst TAPEDEVICE=/dev/tape MTCOMMAND="/bin/mt -f $TAPEDEVICE" # The following is used only if we're doing an incremental backup: BACKUPFILENAME=$BACKUPDIR/files/IncrBackup.`date '+%Y.%m.%d'`.tgz MACHINE=`hostname` # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # Define functions: wait_until_tape_ready () { # We wait a maximum of 60 seconds until the tape drive # is ready to perform another command. # We do this by using "mt tell" to inquire into the current # tape position, and check to see if that command completed # successfully. # We check this every 5 seconds and return 0 when it's ready. # If it's not ready after 60 seconds, we return 1. let NUMTRIES=1 until [ $NUMTRIES -gt 12 ]; do $MTCOMMAND tell > /dev/null 2>&1 if [ $? -eq 0 ]; then return 0 fi sleep 5 let NUMTRIES=NUMTRIES+1 $MTCOMMAND tell > /dev/null 2>&1 done echo " Error: Tape still not ready after 60 seconds: `date`"\ | tee -a $MESSAGEFILE echo " Script exiting" | tee -a $MESSAGEFILE exit 1 } # wait_until_tape_ready # -------------------------------------------------------------------- rewind_tape () { wait_until_tape_ready $MTCOMMAND rewind if [ $? -ne 0 ]; then echo " Error: Can't rewind tape: `date`" | tee -a $MESSAGEFILE echo " Script exiting" | tee -a $MESSAGEFILE exit 1 fi return 0 } # rewind_tape # -------------------------------------------------------------------- retension_tape () { wait_until_tape_ready $MTCOMMAND retension if [ $? -ne 0 ];then echo " Error: Unable to retension the tape: `date`"\ | tee -a $MESSAGEFILE echo " (Is there a tape in the drive?)" | tee -a $MESSAGEFILE echo " Script exiting" | tee -a $MESSAGEFILE exit 1 fi return 0 } # retension_tape # -------------------------------------------------------------------- show_usage () { echo "Usage:" echo " Either \"$PROGNAME full\" for a full backup, or" echo " \"$PROGNAME inc\" for an incremental backup, or" echo " \"$PROGNAME incremental\" for an incremental backup." } # show_usage # -------------------------------------------------------------------- prepare_tape_for_write () { # retension the tape twice, and then go to the end of the data: echo "Retensioning tape, first of two times, `date`..."\ | tee -a $MESSAGEFILE retension_tape echo "Retensioning tape, second of two times, `date`..."\ | tee -a $MESSAGEFILE retension_tape echo "Seeking to the end of data on the tape, `date`..."\ | tee -a $MESSAGEFILE wait_until_tape_ready $MTCOMMAND eod if [ $? -ne 0 ]; then echo " Error: Unable to go to the end of the data: `date`"\ | tee -a $MESSAGEFILE echo " Script exiting" | tee -a $MESSAGEFILE exit 1 fi # Find the present block number, and delete all non-digits # from the output of "mt tell" so that we have only the number: echo "Finding the block number at end of data, `date`..."\ | tee -a $MESSAGEFILE wait_until_tape_ready BLOCKNO=`$MTCOMMAND tell | tr -d -c 0123456789` } # prepare_tape_for_write # -------------------------------------------------------------------- run_fullbackup () { # This function does a full backup, directly to tape: echo | tee -a $MESSAGEFILE echo "Beginning a full backup of $MACHINE, `date`" | tee -a $MESSAGEFILE prepare_tape_for_write NOW=`date` echo | tee -a $MESSAGEFILE echo "Beginning full backup of $MACHINE, $NOW" | tee -a $MESSAGEFILE # Remove the listed-incremental record file so that # a full backup will be done: rm -f $LISTFILE tar -czvX $EXCLUDEFILE\ -V "Full backup of $MACHINE on $NOW"\ --listed-incremental=$LISTFILE\ -f $TAPEDEVICE\ --totals\ $DIRTOBACKUP >> $MESSAGEFILE 2>&1 echo >> $LOGFILE echo "Full backup of $MACHINE, $NOW" >> $LOGFILE echo " (gzipped tarfile) beginning at block $BLOCKNO" >> $LOGFILE # -------------------------------------------------------------------- echo $NOW > $LASTBACKFILE # Find the block number that follows the date we've written: echo "Finding block number at end of new data, `date`"\ | tee -a $MESSAGEFILE wait_until_tape_ready NEWBLOCKNO=`$MTCOMMAND tell | tr -d -c 0123456789` echo " Next backup will begin at block $NEWBLOCKNO" >> $LOGFILE # -------------------------------------------------------------------- # Go back to the beginning of the newly written file, # and run a compare. echo "Seeking to beginning of new file before comparing, `date`..."\ | tee -a $MESSAGEFILE $MTCOMMAND seek $BLOCKNO echo "Beginning compare of new backup: `date`" | tee -a $MESSAGEFILE wait_until_tape_ready # cd to / so that the paths will match up right: cd / /bin/tar --compare -z -f $TAPEDEVICE >> $MESSAGEFILE 2>&1 echo "Compare of new backup completed: `date`" | tee -a $MESSAGEFILE # -------------------------------------------------------------------- echo "Putting tape offline, `date`..." | tee -a $MESSAGEFILE wait_until_tape_ready $MTCOMMAND offline if [ $? -ne 0 ]; then echo " Error: Unable to put tape offline: `date`"\ | tee -a $MESSAGEFILE echo "Script exiting." | tee -a $MESSAGEFILE exit 1 fi # -------------------------------------------------------------------- echo "Backup script complete: `date`" | tee -a $MESSAGEFILE exit 0 } # run_fullbackup # -------------------------------------------------------------------- run_incbackup () { # This function does an incremental backup if [ ! -d $BACKUPDIR/files ];then echo "Directory $BACKUPDIR/files doesn't exist; script exiting"\ | tee -a $MESSAGEFILE exit 1 fi if [ -f $BACKUPFILENAME ] then echo "$BACKUPFILENAME already exists; script exiting"\ | tee -a $MESSAGEFILE exit 1; fi if [ ! -f $LISTFILE ];then echo "LISTFILE $LISTFILE doesn't exist; script exiting"\ | tee -a $MESSAGEFILE exit 1 fi # -------------------------------------------------------------------- if [ -f $LASTBACKFILE ]; then THEN=`cat $LASTBACKFILE` else THEN="I don't know when" fi NOW=`date` echo | tee -a $MESSAGEFILE echo "Beginning listed incremental backup from $THEN to $NOW"\ | tee -a $MESSAGEFILE tar -czvX $EXCLUDEFILE\ --listed-incremental=$LISTFILE\ -V "Listed incremental backupof $MACHINE from $THEN to $NOW"\ -f $BACKUPFILENAME\ --totals\ $DIRTOBACKUP >> $MESSAGEFILE 2>&1 echo >> $LOGFILE echo "Incremental backup of $MACHINE (gzipped tarfile):" >> $LOGFILE echo " From $THEN to $NOW" >> $LOGFILE echo $NOW > $LASTBACKFILE # -------------------------------------------------------------------- # Do a compare to check the backup file contents: # cd to / so that the paths will match up right: cd / echo "Beginning compare of new backup, `date`" | tee -a $MESSAGEFILE /bin/tar --compare -z -f $BACKUPFILENAME >> $MESSAGEFILE 2>&1 echo "Compare of new backup completed: `date`" | tee -a $MESSAGEFILE # -------------------------------------------------------------------- # Copy the backup file to tape: prepare_tape_for_write echo "Beginning to copy $BACKUPFILENAME to tape, `date`" >> $LOGFILE echo " beginning at block $BLOCKNO" >> $LOGFILE echo "Beginning to copy $BACKUPFILENAME to tape, `date`"\ | tee -a $MESSAGEFILE cp $BACKUPFILENAME $TAPEDEVICE wait_until_tape_ready NEWBLOCKNO=`$MTCOMMAND tell | tr -d -c 0123456789` echo " Next backup will begin at block $NEWBLOCKNO" >> $LOGFILE # -------------------------------------------------------------------- # Go back to the beginning of the newly written file on tape # and run a compare. echo "Seeking to beginning of new file before comparing, `date`..."\ | tee -a $MESSAGEFILE $MTCOMMAND seek $BLOCKNO echo "Beginning compare of new backup: `date`" | tee -a $MESSAGEFILE wait_until_tape_ready cmp $BACKUPFILENAME $TAPEDEVICE >> $MESSAGEFILE 2>&1 echo "Compare of new backup completed." | tee -a $MESSAGEFILE echo "Putting tape offline, `date`..." | tee -a $MESSAGEFILE wait_until_tape_ready $MTCOMMAND offline if [ $? -ne 0 ]; then echo " Error: Unable to put tape offline: `date`"\ | tee -a $MESSAGEFILE echo "Script exiting" | tee -a $MESSAGEFILE exit 1 fi # -------------------------------------------------------------------- echo "Backup script complete: `date`" | tee -a $MESSAGEFILE echo | tee -a $MESSAGEFILE exit 0 } # run_incbackup # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # -------------------------------------------------------------------- # The script starts here: umask 022 PROGNAME="`basename $0`" BACKTYPE=$1 if [ ! -d $BACKUPDIR ]; then echo "Directory $BACKUPDIR doesn't exist; script exiting" exit 1 fi if [ ! -f $EXCLUDEFILE ]; then echo "EXCLUDEFILE $EXCLUDEFILE doesn't exist; script exiting" exit 1 fi case $BACKTYPE in full) run_fullbackup exit 0 ;; incremental | inc) run_incbackup exit 0 ;; "") echo "$PROGNAME Error: Incorrect usage"\ | tee -a $MESSAGEFILE show_usage exit 1 ;; *) echo "$PROGNAME Error: Unrecognized backup type"\ | tee -a $MESSAGEFILE show_usage exit 1 ;; esac