Zimbra FOSS Full Backup

From vwiki
Jump to navigation Jump to search

The following script is a modified version of one that can found on the Zimbra Forum here - http://www.zimbra.com/forums/administrators/15275-solved-yet-another-backup-script-community-version.html. It performs a full (offline) backup of your whole Zimbra installation. I've...

  • Changed some of the logging (added timestamps, reduced verbosity)
  • Added FTP option so that backup's can be FTP'ed off

See Zimbra Backup for a bit of guidance on how to run, and see Zimbra FOSS User Backup for how to perform an online, user only backup.

#!/bin/bash
## *** Info ***
# VERSION:  .0.8 alpha, proposed 1/3/2010
#		- fix EMAILCC bug
#		- make -V work as advertised
#		- update version output for accuracy
#		- use full date stamp in backup log rather than only time
#		- add trailing / to default TO_MEDIA_DIR as advised in comment
#           SSS - Modified by Simon Strutt 2010/12/09
#			- Added FTP functionality 
#		- Further modified 2011/03/02
#			- Changed logging (added timestamps, reduced verbosity)
# USAGE:    -h or --help for help & usage.
#           -f or --full for Full backup.
#           -d or --diff for Diff backup.
#           -V or --version for version info.
#           --INSTALL	 for script install and setup.
#
# This is a backup script for the FOSS version of Zimbra mail server.
# The script is free and open source and for use by anyone who can find a use for it.
#
# THIS SCRIPT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND/OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS DOCUMENT, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CONTRIBUTORS:
# heinzg of osoffice.de (original author)
# Quentin Hartman of Concentric Sky, qhartman[AT]concentricsky.com (refactor and cleanup)
# Vincent Sherwood of IT Solutions Ltd., vincents[AT]itsolutions.ie (bugfix and addons)
# Patrick Bennett of PEB Consulting, patrick[AT]pebcomputing.com
# Simon Strutt of SandfordIT Ltd., simon[AT]sandfordit.com
#
# What this script does:
# 1. Makes daily off-line backups, at a service downtime of ~ < 2 min.
# 2. Weekly backup cycle - 1 full backup & 6 diffs.
# 3. Predefined archive sizes, for writing backups to CD or DVD media...
# 4. Backup archive compression.
# 5. Backup archive encryption.
# 6. Backup archive integrity checks and md5 checksums creation.
# 7. Automated DR - Off-site copy of backup archives via ssh.
# 8. Install and setup function for needed software (Ubuntu Systems only)
# 9. Weekly eMail report & eMail on error - including CC address.
#
# This script makes use of following tools:
# apt-get, cron, dar, dpkg, mailx, md5sum, rsync, ssh, uuencode, wget, zimbra mta.
#
# We have opted to use a pre-sync directory to save on "down time", but this 
# causes one to have huge additional space usage.
# But hard drives are cheep today!
#
# What is still to come or needs work on:
# 1. Recovery option
# 2. Better documentation

##------- CONFIG -------#
# Edit this part of the script to fit your needs.

#--- Directories ---#
# Please add the trailing "/" to directories!
ZM_HOME=/opt/zimbra/			# where zimbra lives
SYNC_DIR=/tmp/fakebackup/		# intermediate dir for hot/cold syncs. must have at least as much free space as ZM_HOME consumes
ARCHIVEDIR=/Backup/zimbra_dars/		# where to store final backups
TO_MEDIA_DIR=/Backup/burn/

#--- PROGRAM OPTIONS ---# 
RSYNC_OPTS="-aHK --delete --exclude=*.pid" # leave these unless you are sure you need something else

#--- ARCHIVE NAMES ---#
BACKUPNAME="ZimbraBackup"		# what you want your backups called
FULL_PREFIX="FULL"			# prefix used for full backups
DIFF_PREFIX="DIFF"			# prefix used for differential backups
BACKUPDATE=`date +%Y%m%d`		# date format used in archive names
# BACKUPWEEK=`date +%W`  		# Week prefix used for backup weekly rotation and naming
# VJS - Commented out above, and added below to allow Weekly baseline to be any day of week.
#          Needs full set of tests to be run, including archiving old weeks data, etc.
BACKUPWEEKFILE="/opt/zimbra/backup.week"
case $1 in
-f | --full)
date +%W > $BACKUPWEEKFILE
;;
-d | --diff)
    if [ ! -e "$BACKUPWEEKFILE" ]
    then
        echo Backup Week identifier file "$BACKUPWEEKFILE" not found !
        echo You must run a FULL backup before a DIFF backup
        exit 1
    fi
;;
*)
;;
esac
BACKUPWEEK=`cat $BACKUPWEEKFILE`        # Week prefix used for backup weekly rotation and naming

#--- ARCHIVE SIZE ---#
ARCHIVESIZE="4395M"			# storage media size, for full-backup archiving
# VJS - Uncomment next line for testing multi-DAR scenario on small mail store.
#ARCHIVESIZE="50M"			# storage media size, for full-backup archiving
COMPRESS="9"				# valid answers are 1 - 9 ( 9 = best )

#--- Encryption Options ---#
# !! !!! !!! CRYPT is a legacy option and should best not be used for future compatibility !!! !!! !!
CRYPT="no"				# valid answers are "yes" or "no" BEST IS LEFT AS IS
PASSDIR=/etc/`basename $0`/ 		# the directory the encryption hash is stored in. 
PASSFILE="noread"			# the file containing the password hash

#--- Log Settings ---#
EMAIL="admin@domain.com"		# the address to send logs to
# VJS - Added CC email to avoid errors sending report
EMAILCC="admin2@domain.com"		# another address to send to, blank for none
LOG="/var/log/zim_backup.log"		# log location
# VJS - Added chewitt suggestion for optional listing on report email
ATTACHLIST="no"				# attach backup file or not?
# VJS - Added FILTERLIST to remove all except changed or removed files from the listing
FILTERLIST="yes"  			# Answer "yes" or "no" - "no" lists everything. "yes" filters out unchanged files.

#--- SSH REMOTE DR COPY ---#
# This option will secure copy your archives to a remote server via 'scp'
DRCP="no"				# valid answers are "yes" or "no" 
SSHUSER="you"				# recommend creating a user on the remote machine just for transferring backups	
SSHKEY="rsa"				# recommended answers are "rsa" or "dsa" but "rsa1" is also valid.
REMOTEHOST="remote.server.fqdn"		# can use IP too
REMOTEDIR="/tmp/"			# where you want your backups saved.

#--- FTP REMOTE DR COPY ---#
# SSS - The options allows FTP'ing to a remote FTP server(!)
DRFTP="yes"				# Yes to enable, anything else not to
FTPSERVER="ftp.domain.local"
FTPUSER="backup-user"
FTPPASS="backup-pass"
FTPDIR="/Backup/app-mail"

#--- Use Hacks? ---#
# Built in hacks to fix common problems
#Hack to start Stats, even run zmlogprocess if needed
STATHACK="yes" 				# valid answers are "yes" or "no"


## ~~~~~!!!! SCRIPT RUNTIME !!!!!~~~~~ ##
# Best you don't change anything from here on, 
# ONLY EDIT IF YOU KNOW WHAT YOU ARE DOING

ROOT_UID=0
if [ "$UID" -ne "$ROOT_UID" ]
then
	echo "Run script as "root"."
	echo
exit 1
fi
	
# Static Variables and other setup

# Find absolute paths of required binaries
DAR_BIN=`whereis dar | awk '{print $2}'`
MAILX_BIN=`whereis mailx | awk '{print $2}'`
RSYNC_BIN=`whereis rsync | awk '{print $2}'`
SSH_BIN=`whereis ssh | awk '{print $2}'`
MD5SUM_BIN=`whereis md5sum | awk '{print $2}'`
UUENCODE_BIN=`whereis uuencode | awk '{print $2}'`
FTP_BIN=`whereis ftp | awk '{print $2}'`

STATPIDBASE="$ZM_HOME""zmstat/pid/" 	# Location of Zimbra's PID files
touch $LOG 				# Create log file
HOSTNAME=`hostname --fqdn` 		# Set hostname
STARTTIME=(`date +%s`) 			# Script Timer start

# Set mail function CC address - if not null, add "-c" cmd switch
if [ -n "$EMAILCC" ]; then
        EMAILCC="-c $EMAILCC"
fi

### Functions ###

function mail_log {
	cat $LOG | mail $EMAILCC -s "Zimbra backup error on $HOSTNAME" $EMAIL
	if [ "$2" = "down" ]
	then
		cat $LOG | mail $EMAILCC -s "Zimbra Down on $HOSTNAME" $EMAIL
	fi
}

function config_fail {
	 echo "Please check script Config, and try again"
	 exit 1
}	    

function install_fail {
	 echo "Had a problem installing $1, please ask for help in the forums"
	 exit 1
}

function check_req_bin {
	if [ ! -e "$1" ]
    then
    	echo "Please install "`echo $1 | awk -F / '{print $NF}'`"!"
	echo "Try running the script with --INSTALL"
	exit 1
    fi

}

function check_req_dir {
	if [ ! -d $1 ]
    then
   	echo "Required directory $1 not found!"
   	if [ "$2" = "create" ]
   	then
   		echo
        echo "$REQ_DIR not found!"
		echo -n "Create $REQ_DIR "y" or "n": "
		read ANSWER
		if [ "$ANSWER" = "y" ]
		then
	    	mkdir -vp -m 600 $REQ_DIR
		else
	    	config_fail
	    fi
	else    	
		mail_log
		exit 1
    fi
    fi
}

function do_install {
	# Check for configured Directories and Create them if needed
	for REQ_DIR in $SYNC_DIR $ARCHIVEDIR $TO_MEDIA_DIR
	do
    	check_req_dir $REQ_DIR create
	done
	
    # Check for needed software or try install it

    if [ ! -e "$MAILX_BIN" ]
    then
    	echo
	echo "'mailx' is not installed!"
	echo
	echo "For a "Howto" install mailx without postfix please visit the link below"
	echo "http://www.zimbra.com/forums/administrators/13528-sending-email-comand-line-logwatch-ubuntu-6-06-a.html#post70636"
	echo
	echo "Should I "try" install this for you?"
	echo
	echo "!! Only say yes if you are running Ubuntu!!"
	echo
	echo -n "install "y" or "n": "
	read ANSWER
	if [ $ANSWER = "y" ]
	then
            echo
	    echo "Downloading "mta-dummy" package to "/tmp""
	    cd /tmp
	    wget -v -S -c -t 40 --random-wait -T 60 http://ubuntu.lnix.net/misc/mta-dummy/mta-dummy_1.0_all.deb
	    if [ "$?" -ne "0" ]
	    then
            install_fail mta-dummy
	    fi
        echo
        dpkg -i mta-dummy_1.0_all.deb
        if [ "$?" -ne "0" ]
        then
            install_fail mta-dummy
        fi

        echo
        apt-get -y install mailx
        if [ "$?" -ne "0" ]
        then
            install_fail mailx
        fi
        echo
        echo "Writing config file "/etc/mail.rc""
	echo "set sendmail=$ZM_HOME"postfix/sbin/sendmail"" >> /etc/mail.rc
        else
            echo "This script would like to send you a mail or two... so please install a dummy mta for your Distro"
	    echo
	    exit 1
	fi
    fi


    if [ ! -e "$UUENCODE_BIN" ]
    then
    	echo
	echo "'uuencode' is not installed!"
	echo
	echo "Should I "try" install 'uuencode' for you?"
	echo
	echo "!! Only say yes if you are running Ubuntu!!"
	echo -n "install "y" or "n": "
	read ANSWER
	if [ $ANSWER = "y" ]
	then
	    apt-get -y install sharutils
	    if [ "$?" -ne "0" ]
	    then
        	install_fail sharutils
	    fi
	fi
    fi

    if [ ! -e "$DAR_BIN" ]
    then
    	echo
	echo "'dar' is not installed!"
	echo
	echo "Should I "try" install 'dar' for you?"
	echo
	echo "!! Only say yes if you are running Ubuntu!!"
	echo "!! You must have Universe enabled or this will fail!!"
	echo -n "install "y" or "n": "
	read ANSWER
	if [ $ANSWER = "y" ]
	then
	    apt-get -y install dar
	    if [ "$?" -ne "0" ]
	    then
		     install_fail dar
	    fi
	fi
    fi

    if [ ! -e "$SSH_BIN" ]
    then
    	echo
	echo "'ssh' is not installed!"
	echo
	echo "Should I "try" to install a 'ssh client & server' for you?"
	echo
	echo "!! Only say yes if you are running Ubuntu!!"
	echo -n "install "y" or "n": "
	read ANSWER
	if [ $ANSWER = "y" ]
	then
	    apt-get -y install openssh-server
	    if [ "$?" -ne "0" ]
	    then
            install_fail openssh-server
	    fi
	fi
    fi
    
    if [ $CRYPT = "yes" ]
    then
    	if [ ! -d "$PASSDIR" ]
    	then
    	    echo "Create $PASSDIR"
    	    echo -n "install "y" or "n": "
    	    read ANSWER
	    if [ $ANSWER = "y" ]
	    then
	        mkdir -vp -m 600 $PASSDIR
	        echo "done"
	        echo
	    else    
	    	config_fail
	    fi
	fi
    fi
	
	if [ ! -e "$PASSDIR""$PASSFILE" ]    
	then
    	    echo "Create $PASSFILE"
    	    echo -n "install "y" or "n": "
    	    read ANSWER
    	    if [ $ANSWER = "y" ]
	    then
	        touch "$PASSDIR""$PASSFILE"
	        chmod 600 "$PASSDIR""$PASSFILE"
	        echo "'G'enerate or 'E'nter a secure passphrase"
	        echo -n "please enter G or E: "
	        read ANSWER
	        if [ "$ANSWER" = "G" ]
	        then 
	            openssl rand -base64 48 -out "$PASSDIR""$PASSFILE" 2>/dev/null
	        else
	            echo -n "Enter a secure passphrase: "
	            read PASSPHRASE
	            echo $PASSPHRASE > "$PASSDIR""$PASSFILE"
	            echo "done"
	            echo
	        fi
	    else    
	        config_fail
	    fi
	fi
    
    echo
    if [ $DRCP = "yes" ]
    then
    	echo
	echo "For 'scp' to work, you have to have setup PKI authentication (passwordless login)"
	echo "Should I try setup this for you?"
    echo "If PKI authentication is already setup answer 'n'"
	echo -n "install "y" or "n": "
	read ANSWER
	if [ $ANSWER = "y" ]
	then
	    ssh-copy-id "$SSHUSER"@"$REMOTEHOST"
	    if [ "$?" -ne "0" ]
	    then
            	echo "$?"
		echo -n "Create ssh ID? "y" or "n": "
		read ANSWER
		    if [ $ANSWER = "y" ]
		    then
		        echo "Please accept the 'defaults'and DO NOT ENTER A 'passphrase' !!"
		        ssh-keygen -t "$SSHKEY"
		        echo
		        echo "copying your ID to $REMOTEHOST"
		        echo "please enter your '$SSHUSER' user password on '$REMOTEHOST' at the prompt"
                    if [ "$SSHKEY" = "rsa" ]
                    then
		                ssh-copy-id -i /root/.ssh/id_rsa "$SSHUSER"@"$REMOTEHOST"
                    elif [ "$SSHKEY" = "dsa" ]
                    then
		                ssh-copy-id -i /root/.ssh/id_dsa "$SSHUSER"@"$REMOTEHOST"
                    elif [ "$SSHKEY" = "rsa1" ]
                    then
		            ssh-copy-id -i /root/.ssh/identity "$SSHUSER"@"$REMOTEHOST"
                    fi
		    fi
	    fi
	fi
    fi

    echo
    echo "Install cronjob to automate the nightly backups?"
    echo -n "install "y" or "n": "
    read ANSWER
    if [ $ANSWER = "y" ]
    then
        echo "Setting the time when to start the backup cycle"
        crontab -l > $HOME/.crontab.save
        echo -n "At what hour? 0-23: "
        read HOUR
	echo
	echo -n "and what minute do you want the backup to start? 0-59: "
	read MINUTE
	echo
	echo "path to script e.g. /root/scripts"
	read SPATH
	echo "" >> $HOME/.crontab.save
        echo "$MINUTE $HOUR * * 1     /bin/bash     $SPATH/`basename $0` -f > $LOG 2>&1" >> $HOME/.crontab.save
        echo "$MINUTE $HOUR * * 2-7   /bin/bash     $SPATH/`basename $0` -d >> $LOG 2>&1" >> $HOME/.crontab.save
        echo "" >> $HOME/.crontab.save
        crontab $HOME/.crontab.save
        rm $HOME/.crontab.save
        echo
        crontab -l
        echo
        echo "Done setting up crontab"
        echo
    fi
}

function show_version {
    echo 
    echo "Version .0.8 alpha"
    echo "proposed 1/3/2010"
    echo "first published Feb 08"
    echo
    echo "Change Log January 2010:"
    echo "- fix EMAILCC bug"
    echo "- make -V work as advertised"
    echo "- update version output for accuracy"
    echo "- use full date stamp in backup log rather than only time"
    echo "- add trailing / to default TO_MEDIA_DIR as advised in comment"
    echo "Change Log March 08:"
    echo "- Use the su command insted if sudo to stop and start services"
    echo "- Using shutdown insted of stop with zmcontrol"
    echo "- DATE_VERSION.txt now contains date and version and is created with full backups"
    echo "- Built in some more checks"
    echo "- eMail notification on error"
    echo "- Documentation - Added more comments"
    echo "- Dar archive is now built from current dir" 
    echo "- Stats hack to make sure stats is starting again" 
    echo "- 260 more lines of code... and who knows how many bugs" 
    echo
}

function show_help {
 echo
    echo "Configure the "CONFIG" part of the script to suit your needs."
    echo
    echo "USAGE:    -h or --help for help & usage."
    echo "          -f or --full for Full backup."
    echo "          -d or --diff for Diff backup."
    echo "          --INSTALL    for script install and setup."
    echo 
    echo "Usage with cron, e.g."
    echo "0 3 * * 1     /bin/bash     /root/zmbac.sh -f > $LOG 2>&1"
    echo "0 3 * * 2-7   /bin/bash     /root/zmbac.sh -d >> $LOG 2>&1"
    echo
}

function do_stat_hack {
		        echo "`date +%X` Running A hack... This one to check and start Stats subsystem"
		#Checking if Stats is running
		sleep 5
		STAT_CK=(`su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol status" |grep -i stats | awk '{print $2}'`)
		if [ "$STAT_CK" = "Stopped" ]
	        then
                    echo "`date +%X` Stats is not running, thus booting Stats subsystem!"
                    echo
                    # Stopping Stats
		    su - $ZM_USER -c $ZM_HOME"bin/zmstatctl stop" 
                    if [ "$?" -ne "0" ]
                    then
                        echo "`date +%X` Stopping stats failed!"
                    else
		        echo "`date +%X` Stats have been stopped"
                        echo
                    fi
		
		    # Running Stats cronjob zmlogprocess manually 
                    su - $ZM_USER -c $ZM_HOME"libexec/zmlogprocess" > /tmp/logprocess.out 2>&1
                    if [ "$?" -ne "0" ]
                    then
                        echo "`date +%X` Error running 'logprocess'"
                    else
                        echo "`date +%X` Logprocess done..."
                    fi
                
		    # Running Stats cronjob zmqueuelog manually                
		    su - $ZM_USER -c $ZM_HOME"libexec/zmqueuelog"
                    if [ "$?" -ne "0" ]
                    then
                        echo "`date +%X` Error running 'libexec/zmqueuelog'"
                    else
                        echo "`date +%X` zmqueuelog done..."
                    fi
		    
		    # Starting Stats
		    su - "$ZM_USER" -c $ZM_HOME"bin/zmstatctl start"
	            if [ "$?" -ne "0" ]
		    then
		        echo "`date +%X` Starting stats failed!"
		    else
		        echo "`date +%X` Stats started..."
		    fi
        else
			echo "`date +%X` Hack not needed Stats seems to be running fine..."
        fi
}

function do_backup {
	TYPE=$1

	# VJS - Added Date/time stamp for log file
	echo ===============
	date +'%a %x %X'
	
	if [ $TYPE = "full" ]
	then
		PREFIX=$FULL_PREFIX
	elif [ $TYPE = "diff" ]
	then
		PREFIX=$DIFF_PREFIX
	else
		echo "`date +%X` Invalid Backup Type!"
		exit 1
	fi	
	
	# VJS - Added Backup type for log file
	echo Performing $PREFIX backup
	#echo ============================
	
  # VJS - Added ARCHIVENAME and changed all subsequent lines that referenced the other variable string to just use $ARCHIVENAME
  	ARCHIVENAME="$BACKUPWEEK"_"$BACKUPNAME"_"$BACKUPDATE"_"$PREFIX"
	
	# Check for required directories and helper apps
    for REQ_BIN in $DAR_BIN $MAILX_BIN $RSYNC_BIN $SSH_BIN $MD5SUM_BIN $UUENCODE_BIN
    do
    	check_req_bin $REQ_BIN
    done

    for REQ_DIR in $ZM_HOME $SYNC_DIR $ARCHIVEDIR $TO_MEDIA_DIR
    do
    	check_req_dir $REQ_DIR
    done
    # SSS [not req] echo "$TYPE Backup started at: `date`"
	# Check to make sure we have not already done a backup today.
    CURRENTNAME2=`ls -A -1 "$ARCHIVEDIR""$ARCHIVENAME"*dar 2> /dev/null | head -qn1` 
    
  # VJS - Changed *dar to .1.dar to prevent CURRENTFULL getting multi-line output where the full backup 
  #       went to more than a single DAR file
  #  CURRENTFULL=`ls -A -1 "$ARCHIVEDIR""$BACKUPWEEK"*"$FULL_PREFIX"*dar 2>/dev/null | cut -d . -f1 `
    CURRENTFULL=`ls -A -1 "$ARCHIVEDIR""$BACKUPWEEK"*"$FULL_PREFIX".1.dar 2>/dev/null | cut -d . -f1 `

    if [ -f "$CURRENTNAME2" ]
    then
        echo "`date +%X` Full Zimbra Backup failed! FOUND A BACKUP WITH SAME NAME"
        echo "Please check why! You should only run this script once a day with the current backup date settings!"
        mail_log
        exit 1
  # VJS - Added check for a full backup prior to allowing a diff backup to begin. 
  #       It will ultimarely fail at the DAR step if no full backup exists - so better to stop it now.
    elif [ -f $CURRENTFULL ] && [ $TYPE = "diff" ]
    then
        echo "`date +%X` Diff Zimbra Backup failed! FOUND NO FULL BACKUP FOR CURRENT WEEK"
        echo "Please check why! You should only run this script with -d option once a full backup (-f option) has been run for the week!"
        mail_log
        exit 1
  # VJS - Added -f to $CURRENTFULL test, so it will clear folder in advance of starting new week FULL backup
  # elif [ $CURRENTFULL ] && [ $TYPE = "full" ]
    elif [ -f $CURRENTFULL ] && [ $TYPE = "full" ]
    then
		# Look for old backups and put then in directory from where you write them to some form of
    	# storage media
    	LAST_FULL_DAR=`ls -A -1 $ARCHIVEDIR | grep $BACKUPNAME | cut -d _ -f1 | head -n1`

    	if [ -z "$LAST_FULL_DAR" ]
    	then
        	echo "`date +%X` No old backups found"
	    elif [ "$LAST_FULL_DAR" -lt "$BACKUPWEEK" ]
    	then
        	echo "`date +%X` Old backups found: Last week $LAST_FULL_DAR, Current $BACKUPWEEK"
        	echo 
        	for i in `ls -A -1 "$ARCHIVEDIR""$LAST_FULL_DAR"_"$BACKUPNAME"*`
        	#for i in `ls -A -1 "$ARCHIVEDIR""$LAST_FULL_DAR"_"$BACKUPNAME"*dar`
            do
                mv $i $TO_MEDIA_DIR
                if [ "$?" -ne "0" ]
                then
                    echo "`date +%X` error during move: $i --> $TO_MEDIA_DIR"
                #else
                    # SSS echo "$i moved to $TO_MEDIA_DIR"
                fi
            done
    	fi
    fi
    # Checking for a backup file collisions. Creating Date and Marker file.
    CURRENTNAME1=`ls -A -1 "$ARCHIVEDIR""$ARCHIVENAME"*dar 2> /dev/null | head -qn1`
    if [ -f "$CURRENTNAME1" ]
    then
        echo
        echo "`date +%X` Full Zimbra Backup failed!" 
        echo "FOUND A BACKUP WITH SAME NAME IN $ARCHIVEDIR >> Please check why ????"
        echo "!! You should only run this script once a day with the current backup date settings !!"
		mail_log
		exit 1
    else
        su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol -v" > /dev/null
		if [ -z "$?" ]
    	then 
        	echo "`date +%X` zmcontrol has some problems! check config or call for help..."
		else
	    	#echo "Setting date & version Marker into "$ZM_HOME"DATE_VERSION.txt"
	    	echo "$BACKUPDATE" > "$ZM_HOME"DATE_VERSION.txt
	    	su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol -v" | grep ^R >> "$ZM_HOME"DATE_VERSION.txt
		fi
	fi
	# HotSync to backup directory
	echo "`date +%X` Doing a hotsync of $ZM_HOME to $SYNC_DIR" 
	nice -19 $RSYNC_BIN $RSYNC_OPTS $ZM_HOME $SYNC_DIR 
	if [ "$?" -ne "0" ]
	then
		echo "`date +%X` rsync threw a hotsync error. this is not unusual, continuing..."
    fi
	echo "`date +%X` Disabling the Zimbra crontab..."
	#Disable zimbra user's crontab, we don't want it starting any jobs while we backup
	crontab -u $ZM_USER -l > "$ZM_HOME"crontab.org
	if [ "$?" -ne "0" ]
	then
	    echo "`date +%X` could not backup "$ZM_USER"'s crontab..." 
	    echo "continuing with out changing users crontab!"
	    exit 1
	else
	    touch "$ZM_HOME"crontab.blank
	    crontab -u $ZM_USER "$ZM_HOME"crontab.blank
	    rm "$ZM_HOME"crontab.blank
   	fi
	
	#Starting 'service downtime' counter
	DOWNTIMEA=(`date +%s`)
	# Stopping Zimbra
	echo "`date +%X` Stopping the Zimbra server..."
	echo
	su - $ZM_USER -c $ZM_HOME"bin/zmcontrol stop" 
	if [ "$?" -eq "1" ]
	then
	    echo "`date +%X` zmcontrol shutdown had an error!"
	    mail_log
	    exit 1
	fi
    # Some times I still have zimbra procs running, so I murder them! :-O
    sleep 10
    PROX=(`ps -u $ZM_USER | awk '{print $1}' | grep -v PID`)
    if [ "$PROX" ]
    then
        ps -u $ZM_USER | awk '{print $1}' | grep -v PID | xargs kill -s 15
        echo "`date +%X` Had to kill some left over procs..."
    fi
    # ColdSyncing the zimbra server
    echo "`date +%X` Doing a fast cold sync..." 
	$RSYNC_BIN $RSYNC_OPTS $ZM_HOME $SYNC_DIR 
    if [ "$?" -ne "0" ]
    then
        echo "`date +%X` rsync threw an error!"
	    echo "`date +%X` This should not happen at this stage... exiting!"
	    mail_log
		exit 1
    fi	
	# Starting the Zimbra server again
    # Reinstate zimbra user's crontab
	echo "`date +%X` Reinstating Zimbra's crontab..."
	crontab -u $ZM_USER "$ZM_HOME"crontab.org
	if [ "$?" -ne "0" ]
	then
	    echo "`date +%X` Could not reinstate "$ZM_USER"'s crontab!!"
	    echo "Please do this manually!"
	    mail_log
	    exit 1
	fi
	# Starting Zimbra services again
	echo "`date +%X` Starting Zimbra..."
	su - "$ZM_USER" -c $ZM_HOME"bin/zmcontrol start"
    if [ "$?" -ne "0" ]
    then
        echo "`date +%X` There was an error starting Zimbra!"
        mail_log
        exit 1
    fi
	# Service Timerc
	DOWNTIMEB=(`date +%s`)
	RUNTIME=$(expr $DOWNTIMEB \- $DOWNTIMEA)
	hours=$(($RUNTIME / 3600))
	# VJS - changed seconds to RUNTIME so minutes get computed correctly if backup runs over an hour
	#       seconds=$(($RUNTIME  % 3600))
	RUNTIME=$(($RUNTIME  % 3600))
	minutes=$(($RUNTIME  / 60))
	seconds=$(($RUNTIME  % 60))
	echo "`date +%X` Svc down time - $hours:$minutes:$seconds"
	# Do Hacks?
    if [ $STATHACK = "yes" ]
	then
		do_stat_hack
	fi
           
    # Status Check to see that is running
	STATUS=(`su - "$ZM_USER" -c "/opt/zimbra/bin/zmcontrol status" | grep -i Stopped`)
    if [ "$STATUS" ] 
    then 
        echo "`date +%X` Services that are not running"
        echo $STATUS
        mail_log down
    fi
  echo "`date +%X` Writing a $TYPE backup: ""$ARCHIVENAME"
	echo "into: $ARCHIVEDIR with file sizes of max: $ARCHIVESIZE"
	cd $SYNC_DIR
	if [ "$CRYPT" = "yes" ]
	then
	    KEY=`cat "$PASSDIR""$PASSFILE"`
	    echo "`date +%X` Saving Encrypted Archive..."
		if [ "$TYPE" = "full" ]
		then
			nice -19 $DAR_BIN -K bf:$KEY -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
			-Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
			-Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
			-c "$ARCHIVEDIR""$ARCHIVENAME" -Q
		elif [ "$TYPE" = "diff" ]
		then
		    nice -19 $DAR_BIN -J bf:$KEY -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
			-Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
			-Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
			-c "$ARCHIVEDIR""$ARCHIVENAME" -Q\
			-A "$CURRENTFULL" -Q
		else
			echo "Unkown Backup Type. Fail."
			mail_log
			exit 1
		fi
	else        
	    echo "`date +%X` Saving Unencrtyped Archive..."
		if [ "$TYPE" = "full" ]
		then
			nice -19 $DAR_BIN -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
		    -Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
		    -Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
		    -c "$ARCHIVEDIR""$ARCHIVENAME" -Q
		elif [ "$TYPE" = "diff" ]
		then
	    	nice -19 $DAR_BIN -s $ARCHIVESIZE -z$COMPRESS -Z "*.gz" -Z "*.zip"\
		    -Z "*.bz2" -Z "*.tgz" -Z "*.zgz" -Z "*.jar" -Z "*.tiff" \
		    -Z "*.jpg" -Z "*.png" -Z "*.gif" -Z "*.jpeg" -R `pwd` \
		    -c "$ARCHIVEDIR""$ARCHIVENAME" -Q\
		    -A "$CURRENTFULL" -Q
		else
			echo "Unkown Backup Type. Fail."
			mail_log
			exit 1
		fi
	fi
    if [ "$?" -ne "0" ]
    then
        echo "`date +%X` Dar had a problem!"
        mail_log
        exit 1
    else
	    # Create MD5 Checksums to verify archives after writing to media or network transfers
	    cd $ARCHIVEDIR
	    # VJS - Changed from simple assignment of FILENAME to creating a loop
	    #       This allows for backups that span more than one DAR file
	    # FILENAME=`ls -A "$ARCHIVENAME"*`
	    for FILENAME in `ls -A "$ARCHIVENAME"*`
	  do
	    # VJS - Added do for start of loop
	    if [ -e $FILENAME ]
	    then 
	    	echo "`date +%X` Creating MD5 Checksum for $FILENAME..."
		    $MD5SUM_BIN -b $FILENAME > "$FILENAME".md5
		    if [ "$?" -ne "0" ]
		    then
		        echo "`date +%X` MD5 Checksum failed!"
		        mail_log
		        exit 1
		    fi
	    else
	    	echo "`date +%X` $FILENAME not found!"
			echo "This should not happen"
			mail_log
			exit 1
	    fi
	    # VJS - Added done for end of loop
	  done
	fi
	# DRCP Section. To scp newly created archives to a remote system
	if [ "$DRCP" = "yes" ]
	then
	    CPNAME=`ls -A "$ARCHIVENAME"*`
	    echo "copy archive to $REMOTEHOST" remote directory $REMOTEDIR
	    scp -i /root/.ssh/id_rsa $CPNAME "$SSHUSER"@"$REMOTEHOST":"$REMOTEDIR"
		if [ "$?" -ne "0" ]
		then
		    echo "`date +%X` Error copying archive and checksum to $REMOTEHOST"
		    mail_log
		    exit 1
        fi 
	fi

	# FTP Section (SSS)
       if [ "$DRFTP" = "yes" ]
         then
               # FTP section
               # SSS
	       echo "`date +%X`  starting FTP..."
               $FTP_BIN -inv $FTPSERVER<<ENDFTP
               user $FTPUSER $FTPPASS
               bin
               cd $FTPDIR
               mput "$ARCHIVENAME"*
               close
               bye
ENDFTP

               if [ "$?" == "0" ]
               then
                       echo "`date +%X` FTP upload completed successfully"
               else
                       echo "`date +%X` FTP upload failed !!!"
               fi
	fi    
  # over view of all the files which where backed up
  echo "Creating file listing from archive..."
  # VJS - Implemented chewitt suggestion to name the text listings with the same format filename as the backups. 
  #       This makes the directory cleaner, and makes it easier to clear the directory at the start of the next week.
  # VJS - Added  $FILTERLIST check to allow filtering out unchanged lines from the listing.
  #       Use | grep -v "\[     \]       \[-----\]"  to list only Saved and REMOVED files
  if [ "$CRYPT" = "yes" ]
	then
	    KEY=`cat "$PASSDIR""$PASSFILE"`
  		if [ "$FILTERLIST" = "yes" ]
  		then
		    nice -19 $DAR_BIN -K bf:$KEY -l "$ARCHIVEDIR""$ARCHIVENAME" -Q | grep -v "\[     \]       \[-----\]" \
		    > "$ARCHIVEDIR""$ARCHIVENAME".txt && gzip -9 "$ARCHIVEDIR""$ARCHIVENAME".txt
		  else
		    nice -19 $DAR_BIN -K bf:$KEY -l "$ARCHIVEDIR""$ARCHIVENAME" -Q \
		    > "$ARCHIVEDIR""$ARCHIVENAME".txt && gzip -9 "$ARCHIVEDIR""$ARCHIVENAME".txt
		  fi
	else        
  		if [ "$FILTERLIST" = "yes" ]
  		then
		    nice -19 $DAR_BIN -l "$ARCHIVEDIR""$ARCHIVENAME" -Q | grep -v "\[     \]       \[-----\]" \
		    > "$ARCHIVEDIR""$ARCHIVENAME".txt && gzip -9 "$ARCHIVEDIR""$ARCHIVENAME".txt
		  else
		    nice -19 $DAR_BIN -l "$ARCHIVEDIR""$ARCHIVENAME" -Q  \
		    > "$ARCHIVEDIR""$ARCHIVENAME".txt && gzip -9 "$ARCHIVEDIR""$ARCHIVENAME".txt
		  fi
	fi
    # Script Timer
    STOPTIME=(`date +%s`)
    RUNTIME=$(expr $STOPTIME \- $STARTTIME)
    hours=$(($RUNTIME / 3600))
		# VJS - changed seconds to RUNTIME so minutes get computed correctly if backup runs over an hour
		#       seconds=$(($RUNTIME  % 3600))
		RUNTIME=$(($RUNTIME  % 3600))
    minutes=$(($RUNTIME  / 60))
    seconds=$(($RUNTIME  % 60))
    echo
    #echo "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" 
    echo "`date +%X` $TYPE Zimbra Backup completed" 
    echo "Backup took Hr:$hours Min:$minutes Sec:$seconds to complete" 
    echo ":::::::::::::::Cheers Osoffice for the script:::::::::::::::::::::::"
# VJS - Added chewitt suggestion for optional listing on report email
		if [ "$ATTACHLIST" = "yes" ]
		then
	    (cat $LOG; $UUENCODE_BIN "$ARCHIVEDIR""$ARCHIVENAME".txt.gz "$ARCHIVEDIR""$ARCHIVENAME".txt.gz) \
	    | mail $EMAILCC -s "Zimbra Backup (week $BACKUPWEEK) for $HOSTNAME" $EMAIL
		else
		  cat $LOG | mail $EMAILCC -s "Zimbra Backup (week $BACKUPWEEK) for $HOSTNAME" $EMAIL
		fi
}

## End Functions ##


# Find out who is the zimbra proc user
ZM_USER=`ps -ef | grep "$ZM_HOME" | grep "java" | grep -v "zmmailboxdmgr" | awk '{print $1}' | head -n 1`
if [ -z $ZM_USER ]
then
    echo "Unable to determine the zimbra user!"
    config_fail
elif [ "$ZM_USER" = "root" ]
then
	echo "Zimbra user should never be root!"
	config_fail
fi

case $1 in
-V | -v | --version)
	show_version
;;
-H | -h | --help)
	show_help
;;
--INSTALL)
	do_install    
;;
-f | --full)
	do_backup full
;;
-d | --diff)
	do_backup diff
;;
*)
    echo "use -h or --help for assistance"
;;
esac
exit 0