Monday, January 20, 2014

Snapshot backup with Linux Rsync only when files change

I wrote this modified version of a snapshot backup shell script from
http://www.mikerubel.org/computers/rsync_snapshots

Highlights:

  • Snapshot takes place only when any changes are made to files (add/delete/rename etc.) and not on a set frequency, this is particularly useful in low file change situation where very old snapshots may be kept.
  • Snapshot rotation is not enabled, rather old snapshots are cleared solely based on the available space, this ensures that we have the oldest possible snapshot with us. (Code coming soon...)


#!/bin/bash

unset PATH # suggestion from H. Milz: avoid accidental use of $PATH

# ------------- system commands used by this script --------------------
ID=/usr/bin/id;
ECHO=/bin/echo;

MOUNT=/bin/mount;
RM=/bin/rm;
MV=/bin/mv;
CP=/bin/cp;
TOUCH=/bin/touch;
DIFF=/usr/bin/diff;
RSYNC=/usr/bin/rsync;


# ------------- file locations -----------------------------------------

MOUNT_DEVICE=/dev/sda1;
SNAPSHOT_RW=/media/usb;

# ------------- the script itself --------------------------------------

# make sure we're running as root
if [ `$ID -u` != 0 ]; then { $ECHO "Sorry, must be root.  Exiting..."; exit; } fi

# attempt to remount the RW mount point as RW; else abort
$MOUNT -o remount,rw $MOUNT_DEVICE $SNAPSHOT_RW ;
if [ $? != 0 ]; then
{
$ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite";
exit;
}
fi;

# step 1: delete any temporary snapshot that may exist
if [ -d $SNAPSHOT_RW/home/snapshot_current.tmp ] ; then \
$RM -rf $SNAPSHOT_RW/home/snapshot_current.tmp ; \
fi ;



# step 2: make a hard-link-only (except for dirs) copy of the latest snapshot,
# if that exists
if [ -d $SNAPSHOT_RW/home/snapshot_current ] ; then \
NEWSNAPSHOTNAME=`/bin/date -r $SNAPSHOT_RW/home/snapshot_current "+%F-%H%M%S"`
$CP -al $SNAPSHOT_RW/home/snapshot_current $SNAPSHOT_RW/home/snapshot_current.tmp ; \
fi;

# step 3: rsync from the system into the latest snapshot (notice that
# rsync behaves like cp --remove-destination by default, so the destination
# is unlinked first.  If it were not so, this would copy over the other
# snapshot(s) too!
$RSYNC \
-va --delete --delete-excluded \
/home/ $SNAPSHOT_RW/home/snapshot_current.tmp ;

# step 4: do a diff to see if anything changed
$DIFF -qr $SNAPSHOT_RW/home/snapshot_current/ $SNAPSHOT_RW/home/snapshot_current.tmp/
if [ $? = 0 ]; then
{
$ECHO "snapshot: no differences found, quitting.";
$RM -rf $SNAPSHOT_RW/home/snapshot_current.tmp ;
exit;
} fi;


$MV $SNAPSHOT_RW/home/snapshot_current $SNAPSHOT_RW/home/snapshot_$NEWSNAPSHOTNAME ;
$MV $SNAPSHOT_RW/home/snapshot_current.tmp $SNAPSHOT_RW/home/snapshot_current ;

# step 4: update the mtime of snapshot_current to reflect the snapshot time
$TOUCH $SNAPSHOT_RW/home/snapshot_current ;


# and thats it for home.
# now remount the RW snapshot mountpoint as readonly

$MOUNT -o remount,ro $MOUNT_DEVICE $SNAPSHOT_RW ;
if [ $? != 0 ]; then
{
$ECHO "snapshot: could not remount $SNAPSHOT_RW readonly";
exit;
} fi;


No comments:

Post a Comment