Created
January 27, 2017 12:18
-
-
Save bbrala/1866ad499a08aecaf1be67b1c3150574 to your computer and use it in GitHub Desktop.
rsyc backup using hardlinks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# | |
# Based on http://www.noah.org/engineering/src/shell/rsync_backup | |
# Retention count 21 for making 3 backups each day for a week. | |
# | |
# This maintains a 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 2016-01-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." | |
} | |
# How many folders to rotate. 21 for 3 backups a day | |
RETENTION_COUNT=21 | |
VERBOSE=0 | |
NORMALIZE_PERMS=0 | |
while getopts ":vnh" options; do | |
echo $options | |
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 | |
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 | |
if [ ! -d $BACKUP_PATH ] ; then | |
mkdir $BACKUP_PATH | |
fi | |
COUNTER=$RETENTION_COUNT | |
while [ $COUNTER -ge 0 ] | |
do | |
if [ ! -d $BACKUP_PATH/$SOURCE_BASE.$COUNTER ] ; then | |
mkdir $BACKUP_PATH/$SOURCE_BASE.$COUNTER | |
fi | |
COUNTER=$(( $COUNTER - 1 )) | |
done | |
# 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 -eq 1 ]; then | |
if [ $VERBOSE ]; then | |
echo "Normalizing file permissions." | |
fi | |
find $BACKUP_PATH/$SOURCE_BASE.21 -type d -exec chmod $PERMS_DIR {} \; | |
find $BACKUP_PATH/$SOURCE_BASE.21 -type f -exec chmod $PERMS_FILE {} \; | |
fi | |
rm -rf $BACKUP_PATH/$SOURCE_BASE.$RETENTION_COUNT | |
COUNTER=$(( $RETENTION_COUNT - 1 )) | |
while [ $COUNTER -gt 1 ] | |
do | |
PREVIOUS=$(( $COUNTER - 1 )) | |
mv $BACKUP_PATH/$SOURCE_BASE.$PREVIOUS $BACKUP_PATH/$SOURCE_BASE.$COUNTER | |
COUNTER=$(( $COUNTER - 1 )) | |
done | |
cp -al $BACKUP_PATH/$SOURCE_BASE.0 $BACKUP_PATH/$SOURCE_BASE.1 | |
# Backup. | |
if [ $NORMALIZE_PERMS -eq 1]; then | |
if [ $VERBOSE -eq 1 ]; 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 $SOURCE_PATH/. $BACKUP_PATH/$SOURCE_BASE.0/. | |
RSYNC_EXIT_STATUS=$? | |
if [ $NORMALIZE_PERMS -eq 1 ]; then | |
if [ $VERBOSE -eq 1 ]; 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 -eq 24 ] ; then | |
RSYNC_EXIT_STATUS=0 | |
fi | |
# Create a timestamp file to show when backup process completed successfully. | |
if [ $RSYNC_EXIT_STATUS -eq 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 -eq 1 ]; 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