February 2005

A rsync on Demand Script: Part One

In the daily life of a system administrator (whether at work or play) the issue of backups invariably comes up. The eventual plan is to use a CDRW or DVDRW/CDRW to permanently and periodically backup select data files. Surprisingly, there is not much data that needs backed up so cdroms are ideal. In the meantime, however, duplication is the best bet. To tackle the problem, there are a variety of approaches.

The Options and Choice

The options considered were not very many and rest assured there are a myriad more to choose from. Note that the requirements are for disaster, not versioning (use CVS for that).

  • Create a tarball-datestring.tgz and do something with it...
  • Secure copy tarballs or whole directories to another host.
  • NFS Copy tarballs or whole directories to another host.
  • FTP tarballs or whole directories to another host.
  • Run rsync in daemon mode.
  • Use rsync on demand.

Each case has its own merits. Secure copying everything seems a bit heavy handed for the actual copying while using NFS for backups is somewhat inappropriate. FTP - too crude. Using rsync in one of two modes, daemon mode or on demand makes the most sense since the requirement is for a single machine disaster mitigation.

Why write a script?

In all fairness, straight from cron on the system the files are going to, the following works just fine as long as public-key is setup for the ssh account in use:

        rsync -az --delete -e ssh hostname_or_ip:/path/to/sync/src /path/to/dst

In cron the command can be run that way - but for a few things:

  • Having (not necessarily using) the ability to trap and/or log.
  • Being able to easily run it by hand in case of failure.

It is always nice to leave the door open, however.

The sync_on_demand.sh Script

The script is, for now, incredibly simple. Here is the whole script, then a dissection to follow:

#!/bin/sh
progname=${0##*/}
toppid=$$

PROTO=ssh
UTIL=rsync
UTIL_FLAGS="-az --delete -e $PROTO"

bomb()
{
        cat >&2 <<ERRORMESSAGE

ERROR: $@
*** ${progname} aborted ***
ERRORMESSAGE
        kill ${toppid}
        exit 1
}

for i in $PROTO $UTIL
do
        if ! type ${i} >/dev/null; then
                bomb "${i} not found"
        fi
done

if ! type getopts >/dev/null 2>&1; then
        bomb "/bin/sh shell is too old; try ksh or bash"
fi

while getopts s:d: ch; do
        case ${ch} in
                s)
                        SRC=${OPTARG}
                        ;;
                d)
                        DST=${OPTARG}
                        ;;
        esac
done
shift $((${OPTIND} - 1))

$UTIL $UTIL_FLAGS $SRC $DST || 
        bomb "Could not run ${UTIL}  ${UTIL_FLAGS} ${SRC} ${DST}

exit 0

Head Section

#!/bin/sh
progname=${0##*/}
toppid=$$
  • Tell the system what shell is being used.
  • Snag the name of the script.
  • Grab the topPID.
PROTO=ssh
UTIL=rsync
UTIL_FLAGS="-az --delete -e $PROTO"
  • What protocol and transfer command.
  • The command of the sync utility.
  • The sync utility commands options and arguments.

The bomb() Routine

bomb()
{
        cat >&2 <<ERRORMESSAGE

ERROR: $@
*** ${progname} aborted ***
ERRORMESSAGE
        kill ${toppid}
        exit 1
}
  • Redirect in the error string from the called.
  • Print out the name, abort and abort message.
  • Print out the error message.
  • Kill the top PID.
  • Exit with an error code 1.

Checks Section

for i in $PROTO $UTIL
do
        if ! type ${i} >/dev/null; then
                bomb "${i} not found"
        fi
done

if ! type getopts >/dev/null 2>&1; then
        bomb "/bin/sh shell is too old; try ksh or bash"
fi
  • Make sure the transfer command and utility exist.
  • Check to see if the shell supports getopts.

Options and Arguments

while getopts s:d: ch; do
        case ${ch} in
                s)
                        SRC=${OPTARG}
                        ;;
                d)
                        DST=${OPTARG}
                        ;;
        esac
done
shift $((${OPTIND} - 1))
  • Setup a while loop to get the -s and -d options for source and destination respectively.
  • case in the options.
  • decrement the options index.

Run the Command

$UTIL $UTIL_FLAGS $SRC $DST || 
        bomb "Could not run ${UTIL}  ${UTIL_FLAGS} ${SRC} ${DST}

Put it all together and run the rsync on demand:

sync_on_demand.sh -s atlas:/home/foo -d /home/foo/atlas_home

Note that the destination directory is not called something like ~/atlas_home.foo, because the particular arguments used will create ~/atlas_home/foo which makes it easier to add more home directories later.

Advantages to the Script

The first and foremost is that it can be copied to any system and used. Note that the source can be going from one computer to another versus from the destination computer, they are in fact interchangeable and only distinguished to make sense of the script itself.

What the Script is Missing

The script is missing a few things that might be nice:

  • There is no usage or help information of any sort.
  • There is no logging whatsoever, which seems a little pointless considering the effort put into writing the script.
  • It is likely that extended options to change some of the default values might be desirable.
  • What about multiple synchronizations in different locations?

In part two, the aforementioned missing items (and possibly more as they surface) will be addressed.

Next: Rsync Script Part Two