Skip to content

Instantly share code, notes, and snippets.

@chris-roerig
Last active May 15, 2020 13:25
Show Gist options
  • Save chris-roerig/5b6418a30749021714eb017420b2fc43 to your computer and use it in GitHub Desktop.
Save chris-roerig/5b6418a30749021714eb017420b2fc43 to your computer and use it in GitHub Desktop.
rsync backup with 6 day rotation
# copied from http://www.noah.org/engineering/src/shell/rsync_backup
# minor modifications made to support --exclude-from file
#!/bin/sh
#
# This maintains a one week rotating backup. This will normalize permissions on
# all files and directories on backups. It has happened that someone removed
# owner write permissions on some files, thus breaking the backup process. This
# prevents that from happening. All this permission changing it tedious, but it
# eliminates any doubts. I could have done this with "chmod -R +X", but I
# wanted to explicitly set the permission bits.
#
# Pass two arguments: rsync_backup SOURCE_PATH BACKUP_PATH
#
# $Id: rsync_backup 222 2008-02-21 22:05:30Z noah $
usage() {
echo "usage: rsync_backup [-v] [-n] SOURCE_PATH BACKUP_PATH"
echo " SOURCE_PATH and BACKUP_PATH may be ssh-style remote paths; although,"
echo " BACKUP_PATH is usually a local directory where you want the"
echo " backup set stored."
echo " -v : set verbose mode"
echo " -n : normalize directory and file permissions to 755 for dirs and 644 for files."
}
VERBOSE=0
NORMALIZE_PERMS=0
while getopts ":vnh" options; do
case $options in
v ) VERBOSE=1;;
n ) NORMALIZE_PERMS=1;;
h ) usage
exit 1;;
\? ) usage
exit 1;;
* ) usage
exit 1;;
esac
done
shift $(($OPTIND - 1))
SOURCE_PATH=$1
BACKUP_PATH=$2
EXCLUDE_LIST_PATH=$3
if [ -z $SOURCE_PATH ] ; then
echo "Missing argument. Give source path and backup path."
usage
exit 1
fi
if [ -z $BACKUP_PATH ] ; then
echo "Missing argument. Give source path and backup path."
usage
exit 1
fi
SOURCE_BASE=`basename $SOURCE_PATH`
PERMS_DIR=755
PERMS_FILE=644
if [ $VERBOSE ]; then
RSYNC_OPTS="-a --delete -v"
date
else
RSYNC_OPTS="-a --delete -q"
fi
# Create the rotation directories if they don't exist.
if [ ! -d $BACKUP_PATH ] ; then
mkdir $BACKUP_PATH
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.0 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.0
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.1 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.1
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.2 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.2
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.3 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.3
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.4 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.4
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.5 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.5
fi
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.6 ] ; then
mkdir $BACKUP_PATH/$SOURCE_BASE.6
fi
# TODO All these find operations to clean up permissions is going to add a lot
# of overhead as the backup set gets bigger. At 100 GB it's not a big deal. The
# correct thing would be to have an exception based system where I correct
# permissions when/if they cause a problem.
# Rotate backups.
if [ $NORMALIZE_PERMS ]; then
if [ $VERBOSE ]; then
echo "Normalizing file permissions."
fi
find $BACKUP_PATH/$SOURCE_BASE.6 -type d -exec chmod $PERMS_DIR {} \;
find $BACKUP_PATH/$SOURCE_BASE.6 -type f -exec chmod $PERMS_FILE {} \;
fi
rm -rf $BACKUP_PATH/$SOURCE_BASE.6
mv $BACKUP_PATH/$SOURCE_BASE.5 $BACKUP_PATH/$SOURCE_BASE.6
mv $BACKUP_PATH/$SOURCE_BASE.4 $BACKUP_PATH/$SOURCE_BASE.5
mv $BACKUP_PATH/$SOURCE_BASE.3 $BACKUP_PATH/$SOURCE_BASE.4
mv $BACKUP_PATH/$SOURCE_BASE.2 $BACKUP_PATH/$SOURCE_BASE.3
mv $BACKUP_PATH/$SOURCE_BASE.1 $BACKUP_PATH/$SOURCE_BASE.2
cp -al $BACKUP_PATH/$SOURCE_BASE.0 $BACKUP_PATH/$SOURCE_BASE.1
# Backup.
if [ $NORMALIZE_PERMS ]; then
if [ $VERBOSE ]; then
echo "Normalizing file permissions."
fi
find $BACKUP_PATH/$SOURCE_BASE.0 -type d -exec chmod $PERMS_DIR {} \;
find $BACKUP_PATH/$SOURCE_BASE.0 -type f -exec chmod $PERMS_FILE {} \;
fi
rsync $RSYNC_OPTS --exclude-from $EXCLUDE_LIST_PATH $SOURCE_PATH/. $BACKUP_PATH/$SOURCE_BASE.0/.
RSYNC_EXIT_STATUS=$?
if [ $NORMALIZE_PERMS ]; then
if [ $VERBOSE ]; then
echo "Normalizing file permissions."
fi
find $BACKUP_PATH/$SOURCE_BASE.0 -type d -exec chmod $PERMS_DIR {} \;
find $BACKUP_PATH/$SOURCE_BASE.0 -type f -exec chmod $PERMS_FILE {} \;
fi
# Ignore error code 24, "rsync warning: some files vanished before they could be transferred".
if [ $RSYNC_EXIT_STATUS = 24 ] ; then
RSYNC_EXIT_STATUS=0
fi
# Create a timestamp file to show when backup process completed successfully.
if [ $RSYNC_EXIT_STATUS = 0 ] ; then
rm -f $BACKUP_PATH/$SOURCE_BASE.0/BACKUP_ERROR
date > $BACKUP_PATH/$SOURCE_BASE.0/BACKUP_TIMESTAMP
else # Create a timestamp if there was an error.
rm -f $BACKUP_PATH/$SOURCE_BASE.0/BACKUP_TIMESTAMP
echo "rsync failed" > $BACKUP_PATH/$SOURCE_BASE.0/BACKUP_ERROR
date >> $BACKUP_PATH/$SOURCE_BASE.0/BACKUP_ERROR
echo $RSYNC_EXIT_STATUS >> $BACKUP_PATH/$SOURCE_BASE.0/BACKUP_ERROR
fi
if [ $VERBOSE ]; then
date
fi
exit $RSYNC_EXIT_STATUS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment