Image

Image

Search This Blog

Sunday, August 07, 2011

AUTOTBACK 3.0

A new version of the backup utility.
This is an evolution of the old AUTOTBACK script.
If the script is called without any command-line parameters it will check if "dialog" is installed on the system and it will start the "semi-graphical" interface, otherwise it will display the "usage parameters" and it will exit.

 The command line parameters are still the same:
$autotback ACTION DIRECTORY ARCHIVE MAIL PRINTER, where
- ACTION is backup or restore
- DIRECTORY represent, in case of ACTION=backup the source (what we will backup), or the destination (where the backup will be restored) when ACTION=restore. The default value is "/".
- ARCHIVE represent the location of backup. It is usually the tape device (by default is /dev/st0), but it can also be a simple file (/mnt/disk/archive_name.cpio - if we use an external drive mounted on /mnt/disk)
 - MAIL represent the email address(es) that will receive the backup report. If more than one email address is required, then, on the command line, those must be surrounded by double quotes ("aa@bb.c dd@ee.f gg@hh.i"). The default emails are "backupreport@xxxxxxxx.com root@localhost"
-PRINTER represents the name of the printer used for the report. The default value is empty. The printer MUST be already installed on the system!

#!/bin/sh
#       @(#) AUTOTBACK 3.4 08/09/12
#
# 08/06/2012 (sorin@xxxxxxxx.com) add pre/post actions, embedd dialog
# 17/10/2011 (sorin@xxxxxxxx.com) modify to use tar
# 18/07/2011 (sorin@xxxxxxxx.com) add the restore section, add command-line parmeters
# 10/08/2010 (sorin@xxxxxxxx.com) autoremove lock after 8hrs and reenable backup. remove hit report
# 28/08/2008 (sorin@xxxxxxxx.com) modified for rhel5. skip /proc /sys /tmp. send mail with the result
# modified 9/14/2000 to provide hit reporting on web site
#
#  Usage: $0 backup /source /dev/destination email@notification.address (printer)
#               if no source nor destination is provided, / will be saved to /dev/st0
#         $0 restore /destination /dev/source email@notification.address (printer)
#  when restore is called, the script  will ask you to select a partial restore
#  by typing a file mask. Just type Enter to do a full restore.
#  if no destination is provided, the restore is performed on / from /dev/st0
#  All the reports and temp files are kept in the /var/autotback directory
#
#
# Exit Codes: 0 - OK
#   1 - [ESC] pressed
#   2 - A lockfile exists
#   3 - Can't create dir (am I root? is it /var mounted rw?)
#   
#

# If not provided on the commandline, set local Variables. Must specify at least the main action (backup/restore)
unset SRC DES REC PRN
#if [ "$1" = "" ]; then echo "Usage: $0 {backup|restore} (files) (archive) (email) (printer)"; fi # if dialog exists start anyway
if [ ! "$2" = "" ]; then SRC=$2; else SRC=/; fi
if [ ! "$3" = "" ]; then DES=$3; else DES=/dev/st0; fi
if [ ! "$4" = "" ]; then REC=$4; else REC="backupreport@xxxxxxxx.com root@localhost"; fi
if [ ! "$5" = "" ]; then PRN=$5; fi

# System variables
#PRECOMMAND='/bin/mount -t cifs -o guest //192.168.1.16/images /mnt'
#POSTCOMMAND='/bin/umount /mnt'
ARCHIVER=tar
DEFAULTDIR=/var/autotback
LOCK=$DEFAULTDIR/backlock
REPORTFILE=$DEFAULTDIR/backrep$$
TEMPFILE=$DEFAULTDIR/backtmp$$
TEMPFILE2=$DEFAULTDIR/backtemp$$
TEMPFILEV=$DEFAULTDIR/vertmp$$
TEMPFILEV2=$DEFAULTDIR/vertemp$$
LIST=$DEFAULTDIR/list$$
TITLE="AUTOTBACK 3.4"
BACKTITLE="A dialog driven backup utility  (press [ESC] twice to exit)"
INTERRUPT="echo -en [ESC] Pressed, exiting...  "
HEADER="Backup Report for $HOSTNAME
(c)1991-2012 xxxxxxxx Inc.
===============================================================================
`date`
"

#########################
# Define main functions #
#########################

########
# lock #
########

lock ()
{
# Check if another job is running
if [ -r $LOCK ]
then
    # if we have wall, announce the trouble
    if [ ! "$(whereis wall | cut -d: -f2)" = "" ]; then wall " We have a little issue with the BACKUP ! Please verify $DEFAULTDIR"; fi
    echo "`date` - Another job is running or the last backup did not finished well. Please check $DEFAULTDIR !" >> $REPORTFILE
    # check the age of the lockfile, if it is older then 23 hrs, chances are that nobody checked the log
    ((DIFF=`date +%s`-`cat $LOCK`))
    if [ $DIFF -gt 82800 ]; then echo "`date` - Lockfile more than 23 hours old, autocleaning... the backup will run!" >> $REPORTFILE; rm -f $LOCK; fi
    if [ -r $LOCK ]
    then
        if [ ! "$(whereis mail | cut -d: -f2)" = "" ]; then cat $REPORTFILE | mail -s "$0 Warning from $HOSTNAME" $REC 2>/dev/null; fi
        if [ "$PRN" = "" ]; then echo "Skip print, no printer defined" >> $REPORTFILE; elif [ ! "$(whereis lp |cut -d: -f2)" = "" ]; then lp -d $PRN $REPORTFILE; fi
        exit 2
    fi
fi

# Cleanup obsolete traces and create defaultdir
rm -rf $DEFAULTDIR 2> /dev/null
mkdir -p $DEFAULTDIR 2> /dev/null
if [ ! -d $DEFAULTDIR ] ; then echo "CAN'T MAKE $DEFAULTDIR"; exit 3; fi
touch $REPORTFILE $TEMPFILE $TEMPFILE2 $TEMPFILEV $TEMPFILEV2 $LIST

# Create lockfile
echo "`date +%s`">$LOCK
}

##################
# extract dialog #
##################

extract_dialog ()
{
# If dialog is not in path and the system is linux - !!! TBD - NOT USED IN v3.4 !!!
if [ ! "`uname -a | grep Linux`" == "" ]; then
    echo "Dialog not found, Do you want to try to extract our own dialog? y/n"
    read extract
    if [ "$extract" = "y" ] || [ "$extract" = "Y" ]; then 
     # Find the tar archive at the end of this script. It starts after the line "---DEMARK---"
     # It was added there with a simple 'cat binary.tar.bz2 >> $this_script'
     binstart=`expr $(grep --text --line-number '^---DEMARK---$' $0 | cut -f1 -d:) + 1`
     # Extract the tar archive on /tmp
     tail -n +$binstart $0 | tar -C/tmp -xjvf -
    fi
fi
}

#####################
# graphic interface #
#####################

void ()
{
# Make the TERM display white on blue
setterm -clear all -foreground white -background blue 

# Check if another job is running
lock

# present the user the choice of backup, resctore or scheduler
dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel --menu "Choose an Option" 11 30 3 1 "Create a Backup" 2 "Restore from Backup" 3 "Schedule a Backup" 2>/tmp/input.$$
sel=$?
choice=`cat /tmp/input.$$`
rm -f /tmp/input.$$
case $sel in
    0)
    if [ "$choice" = "1" ]; then 
 #dialog choose what, where, to backup, to whom we send email, where we print (if we print)
 dialog --title "$TITLE (SPACE to select what to save)" --backtitle "$BACKTITLE" --nocancel \
 --fselect "/" 12 46 2>/tmp/input.$$
        sel=$?
        SRC=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Select the destination device" 8 25 /dev/st0 2>/tmp/input.$$
        sel=$?
        DES=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Type the notification emails" 8 47 "backupreport@xxxxxxxx.com root@localhost" 2>/tmp/input.$$
        sel=$?
        REC=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        REC=\"$REC\"
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK &&  exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Type the Printer name (if any)" 8 25 2>/tmp/input.$$
        sel=$?
        PRN=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
        --infobox "Performing the Backup procedure. Please wait..." 6 25
        # call the backup function with the right command line options. Remove lock before
 rm -f $LOCK && backup
    fi
    
    if [ $choice = 2 ]; then 
        ##dialog choose where to restore, from where, to whom we send email, where we print (if we print)
 dialog --title "$TITLE (SPACE to select where to save)" --backtitle "$BACKTITLE" --nocancel \
 --fselect "/" 12 47 2>/tmp/input.$$
        sel=$?
        SRC=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Select the source device" 8 25 /dev/st0 2>/tmp/input.$$
        sel=$?
        DES=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Type the notification emails" 8 47 "backupreport@xxxxxxxx.com root@localhost" 2>/tmp/input.$$
        sel=$?
        REC=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        REC=\"$REC\"
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK &&  exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Type the Printer name (if any)" 8 25 2>/tmp/input.$$
        sel=$?
        PRN=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
        --infobox "Performing the Restore procedure. Please wait..." 6 25
        # call the restore function with the right command line options. remove lock before
        rm -f $LOCK && restore
    fi

    if [ $choice = 3 ]; then 
 # before schedule a new backup, check is there is another one already programmed
 myname=`echo $0 | sed -e's/\.\///'` # Remove ./ from $0
 if [ ! `crontab -l | grep -c $myname` = 0 ]; then 
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --yes-label "Keep" --no-label "Delete" --yesno "A backup is alredy scheduled, What do you want to do with it? \n `crontab -l | grep $myname`" 10 46
 sel=$?
        case $sel in
        0) # keep the old scheduled backups in crontab, nothing to do
        ;;
        1)
        # delete old backup from crontab
 crontab -l | sed -e "/$myname/d" > /tmp/tmpcron.$$
        /usr/bin/crontab < /tmp/tmpcron.$$
        rm -f /tmp/tmpcron.$$
        ;;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 fi

 ##start to schedule. choose days of week (MON-FRI preselected)
        dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel --checklist "Choose days of Backup (Use SPACE to select)" 18 26 12 0 Sunday off 1 Monday on 2 Tuesday on 3 Wednesday on 4 Thursday on 5 Friday on 6 Saturday off --and-widget 2>/tmp/input.$$
        sel=$?
        sed -i -e 's/\"//g' -e 's/\ /\,/g' /tmp/input.$$
        week=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 ##choose time of backup (23:30 seems to be a good default choice)
        dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel --timebox "Choose time for Backup (Use arrows to modify)" 5 26 23 30 00 2>/tmp/input.$$
        sel=$?
        hr=`cat /tmp/input.$$ | cut -f1 -d:`
        min=`cat /tmp/input.$$ | cut -f2 -d:`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac

        # choose what, where, to whom we send email, where we print (if we print)
 dialog --title "$TITLE (SPACE to select what to save)" --backtitle "$BACKTITLE" --nocancel \
 --fselect "/" 12 46 2>/tmp/input.$$
        sel=$?
        SRC=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Select the destination device" 8 25 /dev/st0 2>/tmp/input.$$
        sel=$?
        DES=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Type the notification emails" 8 47 "backupreport@xxxxxxxx.com root@localhost" 2>/tmp/input.$$
        sel=$?
        REC=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        REC=\"$REC\"
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK &&  exit 1;;
        esac
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
 --inputbox "Type the Printer name (if any)" 8 25 2>/tmp/input.$$
        sel=$?
        PRN=`cat /tmp/input.$$`
        rm -f /tmp/input.$$
        case $sel in
        0);;
        255) $INTERRUPT && rm -f $LOCK && exit 1;;
        esac

 #insert the line in crontab
        crontab -l > /tmp/tmpcrontab.$$
        echo "$min $hr * * $week $myname backup $SRC $DES $REC $PRN" >> /tmp/tmpcrontab.$$
        /usr/bin/crontab < /tmp/tmpcrontab.$$
        rm -f /tmp/tmpcrontab.$$
 dialog --title "$TITLE" --backtitle "$BACKTITLE" --nocancel \
        --infobox "New crontab is installed...\n `crontab -l | grep $myname`" 10 45
    fi
    ;;
    255) $INTERRUPT && rm -f $LOCK && exit 1;;
esac

# end of graphical part, restore TERM
setterm -default

# remove lock
sleep 1
rm $LOCK
}

###################
# backup & verify #
###################

backup ()
{

# Check if another job is running
lock

# Start backup
if [ ! "$PRECOMMAND" == "" ]; then
$PRECOMMAND >>$REPORTFILE
fi

echo "$HEADER 
Backup of $HOSTNAME started
The command line was: $0 backup $SRC $DES $REC $PRN
 ">>$REPORTFILE

# Start saving
cd $SRC
echo "Start WRITING $SRC to $DES on `date`">>$REPORTFILE 
# In any case exclude /proc /sys /tmp /mnt
if [ "$ARCHIVER" == "tar" ]
then 
 tar --verbose --exclude=/proc --exclude=/sys --exclude=/tmp --exclude=/mnt --totals -b2048 -cpvf $DES $SRC >>$TEMPFILE 2>$TEMPFILE2
else
 echo "Enumerating the list of files and removing special folders
 ">>$REPORTFILE
 find . -depth -print | grep -v "./sys/" | grep -v "./proc/" | grep -v "./tmp/" | grep -v "./mnt/" >$LIST
 cat $LIST | cpio -ocvB >$DES 2>>$TEMPFILE
fi
backstat=$?
echo "
Following are the last lines recorded during saving:" >>$REPORTFILE
tail $TEMPFILE | head -9 >>$REPORTFILE
tail -n1 $TEMPFILE >>$REPORTFILE
echo "
WRITE exit status = $backstat
">> $REPORTFILE
if [ $backstat -ne 0 ]
then
 if [ $backstat -eq 1 ]
 then
    echo "*** Backup may be incomplete or have missing files ***">>$REPORTFILE
 elif [ $backstat -eq 2 ]
 then
  if [ `grep "Error exit delayed from previous errors" $TEMPFILE2` ]
   then
    echo "*** Backup may be incomplete or have missing files ***">>$REPORTFILE
   else
    echo "*** Backup has encounter a fatal ERROR. Please check ***">>$REPORTFILE
   fi
 else
    echo "*** Backup may contain an ERROR ***">>$REPORTFILE
 fi
else
    echo "*** Backup COMPLETED OK ***">>$REPORTFILE
fi

echo "Tape WRITING completed on `date`">>$REPORTFILE

if [ ! "$ARCHIVER" == "tar" ]
then 
set `tail -1 $TEMPFILE | cut -d: -f2 | cut -d" " -f2`
BACKTOT=$1
else
BACKTOT=`grep "Total bytes" $TEMPFILE2 | cut -d: -f2 | cut -d" " -f2`
fi
echo "
Total of amount of saved bytes was $BACKTOT
">>$REPORTFILE

#Tape Verify
echo "Starting VERIFY on $DES `date`">>$REPORTFILE
if [ "$ARCHIVER" == "tar" ]
then 
 tar --verbose --exclude=/proc --exclude=/sys --exclude=/tmp --exclude=/mnt --totals -b2048 -tpvf $DES >>$TEMPFILEV  2>>$TEMPFILEV2
else
 cpio -icvtB <$DES >>$TEMPFILEV 2>>$TEMPFILEV2
fi
verstat=$?
echo "
Following are the last lines recorded during verify:" >>$REPORTFILE
tail $TEMPFILEV | head -9 >>$REPORTFILE
tail $TEMPFILEV2 | head -9 >>$REPORTFILE
echo "
VERIFY exit status = $verstat
">>$REPORTFILE
if [ $verstat -ne 0 ]
then
    echo "***  Verify may contain an ERROR ***
    ">>$REPORTFILE
fi
echo "Verify completed for $HOSTNAME on `date` 
">>$REPORTFILE
if [ ! "$ARCHIVER" == "tar" ]
then 
set `tail -1 $TEMPFILEV2 | cut -d: -f2 | cut -d" " -f2`
VERTOT=$1
else
VERTOT=`grep "Total bytes" $TEMPFILEV2 | cut -d: -f2 | cut -d" " -f2`
fi
echo "Total of amount of verified bytes was $VERTOT
">>$REPORTFILE

if [[ $backstat -ne 0 || ($verstat -ne 0 || "$BACKTOT" != "$VERTOT") ]]
then
 if [ $verstat -eq 1 ]
 then
    echo "***  Verify may be incomplete ***">>$REPORTFILE
 elif [ $verstat -eq 2 ]
 then
    echo "***  Verify has encounter a fatal ERROR. Please check ***">>$REPORTFILE
 else
    echo "***  The backup may contain an ERROR  ***">>$REPORTFILE
 fi
 # put a warning
 echo "***  WARNING!!! BACKUP TRANSFER TOTALS DID NOT MATCH  ***
***                   PLEASE VERIFY                   ***
">>$REPORTFILE
 # Send the report
 if [ ! "$(whereis mail | cut -d: -f2)" = "" ]; then cat $REPORTFILE | mail -s "Backup ERROR on $HOSTNAME" $REC 2>/dev/null; fi
else
 # Gives the OK
 echo "*** Transfer Totals Concur ***
">>$REPORTFILE
 # Send the report
 if [ ! "$(whereis mail | cut -d: -f2)" = "" ]; then cat $REPORTFILE | mail -s "Backup OK on $HOSTNAME" $REC 2>/dev/null; fi
fi
# Print the report
if [ "$PRN" = "" ]; then echo "Skip print, no printer defined" >> $REPORTFILE; elif [ ! "$(whereis lp |cut -d: -f2)" = "" ]; then lp -d $PRN $REPORTFILE; fi

# Eject if mt is installed
if [ ! "$(whereis mt |cut -d: -f2)" = "" ]; then mt -f $DES rewoffl; fi

# remove lock
sleep 1
rm $LOCK

if [ ! "$POSTCOMMAND" == "" ]; then
$POSTCOMMAND >>$REPORTFILE
fi
}

###########
# restore #
###########
restore ()
{
# Check if another job is running
lock

# Start restore
if [ ! "$PRECOMMAND" == "" ]; then
$PRECOMMAND >>$REPORTFILE
fi

echo "$HEADER Restore started on `date`
The command line was: $0 restore $SRC $DES $REC $PRN
Choosing the files to restore...">>$REPORTFILE

#choose the files to restore
echo "Type the name of the files you want to restore (CR = all the archive)
(ex: to restore everything from /etc/sysconfig type etc/sysconfi*):"
read RES

echo "Restoring $RES from $DES to $SRC." >> $REPORTFILE
mkdir -p $SRC 2>/dev/null
cd $SRC

if [ "$ARCHIVER" == "tar" ]
then 
 tar --exclude=/proc --exclude=/sys --exclude=/tmp --exclude=/mnt --totals -b2048 -xpvf $DES $RES >>$TEMPFILE 2>>$TEMPFILE2
else
 cpio -icvdmB $RES < $DES >>$TEMPFILE 2>>$TEMPFILE2
fi
resstat=$?

echo "RESTORE exit status = $resstat
">>$REPORTFILE

if [ $resstat -ne 0 ]
then
    echo "***  RESTORE may contain an ERROR ***
    ">>$REPORTFILE
fi

# Prepare the report
echo "Following are the special cases reported during restore:" >>$REPORTFILE
tail $TEMPFILE | head -9 >> $REPORTFILE
tail $TEMPFILE2 | head -9 >> $REPORTFILE
set `tail -1 $TEMPFILE2 | cut -d: -f2 | cut -d" " -f2`
RESTOT=$1
echo "Total of amount of restored bytes was $RESTOT
">>$REPORTFILE
# Send the report
if [ ! "$(whereis mail | cut -d: -f2)" = "" ]; then cat $REPORTFILE | mail -s "Restore report for $HOSTNAME" $REC 2>/dev/null; fi
# Print the report
if [ "$PRN" = "" ]; then echo "Skip print, no printer defined">> $REPORTFILE; elif [ ! "$(whereis lp |cut -d: -f2)" = "" ]; then lp -d $PRN $REPORTFILE; fi

# Eject if mt is installed
if [ ! "$(whereis mt |cut -d: -f2)" = "" ]; then mt -f $DES rewoffl; fi

# remove lock
sleep 1
rm $LOCK

if [ ! "$POSTCOMMAND" == "" ]; then
$POSTCOMMAND >>$REPORTFILE
fi
}

###################
# Starting script #
###################
case "$1" in
backup)
    backup;;
restore)
    restore;;
*)
# If it was called without parameters check if dialog exist and call the interface
    if [ "$(whereis dialog | cut -d: -f2)" = "" ]; then
    extract_dialog
     echo "Usage: $0 backup (source) (destination) (email) (printer)
     $0 restore (destination) (source) (email) (printer)     
     "
   else
    void
   fi
   ;;
esac

# ensure a safe exit
exit 0

---DEMARK---

Blog Archive