Pages

Thursday, July 12, 2012

Backing Up with Rsync

There's always a moment of butterflies when your machine hangs, or doesn't  boot up, or shows some cryptic message and dies. In the few minutes following my last such catastrophe, I berated myself for not taking regular backups on an external drive. Then I started to look at trying to recover the data using a live CD. When I finally got the new OS going I decided the first thing to do was to set up a system to silently backup the system every once in a while, either to a USB hard drive or to a network drive. So I wrote a script to do this using rsync. The script is as follows, with explanations for each line...



#!/bin/bash
#This tells the shell that this is a bash script
#Script to backup the contents of my desktop machine to an external device
#identified by the following UUID:

TARGET_UUID=84f15456-ce64-52be-c488-e88125e623a30;
#This line defines which device is to be used as the backup device. For example, #backups must be made ONLY to a specific hard disk, not just any device that may #be plugged in. If a new backup device is to be used, change the UUID! If a new #backup device is to be used, change the UUID!
#

MAINLOG=/home/someuser/serverbackup.log
#Set a variable with the name of a main log file. This will contain broad info, #like date of last backup and success or failure stats.
VERBOSELOG=/home/someuser/backupdetails.log
#This file contains the details of what files were backed up, how much time it #took, etc etc.

BACKUPTARGET=/home/someuser/BACKUP/
#This is the location where the backup drive will be mounted. If the drive is #mounted in the same location.
#NOTE: USB devices usually get automounted on insertion in Ubuntu. If this is the #case, you may want to either 
# 1. disable automount for that particular device,
# 2. Mount to a fixed location always
# 3. allow automount and then figure out at run time if the device is mounted,
# and where. Naturally this is the most robust approach but my script assumes automount has been disabled for my drive.

#Status Variable, used for logging also
ERROR=0;        #0:Success , Non-Zero:Failure(s)
#This is a status variable which will keep accumulating the error values

#Alias for RSync:
alias rsync='rsync -az --delete-after'
shopt -s expand_aliases
#I don't want to be typing out the full rsync command, so I make an alias for it. #Note that when a bash script is executed, NONE of the environment variables or #aliases from the original shell are available to it. It runs in a 'fresh and #clean' shell, so to speak. 
#Moreover, even if an alias is defined, it DOES not get expanded unless explicitly #told to do so using the "shopt" command

#Rsync Options: 
#-az archive mode: preserve directory structure, permissions, etc
#--delete-after: delete files from the target that are no longer on the source
#IF your target is an NTFS formatted disk, or a drive on a windows machine,
# then links cannot be copied. So use the --no-l (no links) option also.

# The date of the lastbackup is stored in a file called
# lastdiskbackup
#A file with the date of the last backup is kept. This prevents us from making a #backup when a very recent backup has already been made. This is VERY useful when #the backups are to be made automatically via a cron job.

if [ -e lastdiskbackup ]; then
#If it does not exist then create it
echo "";
#Just a dummy statement
else
date --date="10 years ago" > lastdiskbackup;
fi


#Calculate when the last backup was made

DAYS_SINCE_LAST_BACKUP=$(echo $"(( $(date +%s) - $(date --date="`cat lastdiskbackup`" +%s) ))/(60*60*24)"|bc)

#If the last backup to disk was done today, then don't backup again.
if [ $DAYS_SINCE_LAST_BACKUP = 0 ]; then
echo "Last backup was just $DAYS_SINCE_LAST_BACKUP ago. Quitting"
#Exit from the script
exit 0;
fi

echo "*********************************************************************" >> $MAINLOG
echo "`date`" >> $MAINLOG
echo "Backing up to Disk" >> $MAINLOG
echo "" >> $MAINLOG

#Pretty print to the main log


echo "*********************************************************************" >> $VERBOSELOG
echo `date` >> $VERBOSELOG
echo "" >> $VERBOSELOG
#Pretty print to the verbose log

#********************************************************************
#Mount Local Drive for backup  
if [ -e /dev/disk/by-uuid/$TARGET_UUID ] ; then
echo "Backup Drive Found...">> $VERBOSELOG
else
echo "Fatal: Disk Not found" >> $MAINLOG
exit 0
fi

echo "Mounting Backup Drive...">> $VERBOSELOG
mount /dev/disk/by-uuid/$TARGET_UUID /some/folder/ &>> $VERBOSELOG
echo "" >> $VERBOSELOG
echo "" >> $VERBOSELOG


#I put this to check for the existence of a certain file. In case there is 
#a problem with the mount, or the wrong drive gets mounted this is 
#still a fall-back check to make sure that the expected drive has been 
#mounted in the right place.

if [ -e /some/folder/testfile ] ; thenecho "" > /dev/null;
else
echo "Fatal: Backup Location not found" >> $MAINLOG
exit 0
fi

#--------------------------------------------------------------------
#BACKUPS
#--------------------------------------------------------------------
# The actual backups...
# make as many copies of this snippet, changing the arguments to rsync to suit
# your requirements. You should be backing up only really important stuff - 
# if you back up your entire /home you may end up backing up just a lot 
# of garbage that you cannot or will never use.
echo "Backing Up HOME" >> $VERBOSELOG
echo "--------------" >> $VERBOSELOG
rsync /home/myuser/ $DEST >> $VERBOSELOG
ERROR=$[$ERROR+$?];
echo "" >> $VERBOSELOG

#--------------------------------------------------------------------



# Now we are done with the backing up; remove (unmount)

# the backup disk

echo "Unmounting backup drive:" >> $VERBOSELOG
umount $BACKUPTARGET >> $VERBOSELOG

if [ $ERROR = 0 ]; then
echo "Successfully Completed backup" >> $MAINLOG
else
echo "Backup Unsuccessful. There were errors. [Code: $ERROR]" >> $MAINLOG
fi

#Change date in the file to reflect this backup
date > lastdiskbackup


Now for the last part of the exercise: creating a launcher. Until Unity and GNOME came along, things were fine - a right click on the desktop bar would let you add a launcher. Now in unity you need to do something extra - create a file in /usr/share/applications as explained here. Not happy with the icon? Select one from /usr/share/icons and type in the file name in the field for icon.


No comments: