--- /dev/null
+#!/bin/bash
+#
+# wizbackup 2.0 - Simple rsync backup
+# Based on incremental-backup 0.1 by Matteo Mattei
+#
+# Copyright 2006 Matteo Mattei <matteo.mattei@gmail.com>
+# Copyright 2007, 2008, 2009, 2010, 2011 Bernie Innocenti <bernie@codewiz.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License,
+# or (at your option) any later version.
+
+
+if [ $# -lt 2 ]
+then
+ echo "Usage: $0 SOURCE DEST [RSYNC_OPTS]"
+ exit 1
+fi
+
+# Fail on any error; Treat undefined variables as errors
+set -e -u
+
+#####################################################################
+# CONFIGURATION
+#####################################################################
+
+# Source path
+SRC=$1; shift
+
+# DESTINATION DIRECTORY (must exists)
+DEST=$1; shift
+
+# NOTE: --timeout needs to be large enough: if a large dir tree don't change a lot of time can pass without I/O
+# NOTE: --inplace will clobber linked files in older snapshots. DON'T USE IT!
+RSYNC_OPTIONS="-HAXa --stats --timeout 1800 --numeric-ids --delete --delete-excluded --ignore-errors $@"
+# NUMBER OF SAVED ARCHIVES
+N_SNAPSHOT=45
+RESULT=500
+
+DATE=`date +"%Y%m%d"`
+DEST="`echo $DEST | sed -e 's/\/$//'`"
+
+
+# Use "backup" ssh key with ssh protocol, or password file for rsync protocol
+if [ "${SRC%:*}" == "rsync" ]; then
+ RSYNC_PWD="--password-file=/etc/wizbackup.pwd --contimeout 10"
+else
+ export RSYNC_RSH="ssh -i /root/.ssh/id_backup -c arcfour -x -o VerifyHostKeyDNS=yes"
+ RSYNC_PWD=""
+fi
+
+# Error tolerant grep
+tgrep()
+{
+ grep "$@"
+ return 0
+}
+
+do_backup()
+{
+ set -o pipefail
+ echo "$(date): Starting rsync: rsync $RSYNC_PWD $RSYNC_OPTIONS $SRC $DEST/$DATE/"
+ rsync $RSYNC_PWD $RSYNC_OPTIONS "$SRC" "$DEST/tmp/" 2>&1 | tgrep -v -E 'vanished|some files'
+ RESULT=$?
+ case "$RESULT" in
+ 0|24)
+ RESULT=0 # Ignore error 24 (Partial transfer due to vanished source files)
+ # Cleanup old incomplete backups
+ if [ -d "$DEST/$DATE" ]; then
+ echo "$(date): Removing existing backup $DEST/$DATE"
+ rm -rf "$DEST/$DATE"
+ fi
+ mv "$DEST/tmp" "$DEST/$DATE"
+ ;;
+ *)
+ echo "$(date): rsync failed: $RESULT"
+ echo "$(date): Leaving incomplete backup in $DEST/tmp"
+ ;;
+ esac
+ set +o pipefail
+}
+
+do_link()
+{
+ # Safety net (4 slashes just in case)
+ case "$DEST" in
+ /|//|///|////) exit 666 ;;
+ esac
+
+ if [ ! -d "$DEST" ]; then
+ echo "$(date): Creating missing destination directory $DEST."
+ mkdir -p "$DEST" || exit 667
+ fi
+
+ pushd "$DEST" >/dev/null || exit 668
+
+ # Remove old backups
+ local old="`ls | head -n -$N_SNAPSHOT`"
+ if [ ! -z "$old" ]; then
+ echo "$(date): Removing oldest snapshot(s): $old..."
+ rm -rf "$old" || exit 669
+ fi
+
+ local newest=`ls | tail -n 1`
+ if [ -z "$newest" ]; then
+ echo "$(date): No previous snapshot found, performing a full backup!"
+ elif [ -d "$DEST/tmp" ]; then
+ echo "$(date): Continuing with preexisting snapshot $DEST/tmp"
+ else
+ echo "$(date): Linking snapshot $DEST/$newest to $DEST/tmp"
+ # TODO: Creating the hardlinks takes a lot of time.
+ # Perhaps we could save time by recycling the oldest snapshot
+ cp -lR "$DEST/$newest" "$DEST/tmp" || exit 670
+ fi
+
+ popd >/dev/null
+}
+
+do_test()
+{
+ # Avoid clobbering the latest snapshot if the remote host does
+ # not allow us to connect
+ # --contimeout: sometimes hangs on connection...
+ rsync $RSYNC_PWD $RSYNC_OPTIONS --dry-run --no-recursive "$SRC" >/dev/null
+ RESULT=$?
+ if [ $RESULT -ne 0 ]; then
+ echo "$(date): rsync test failed: $RESULT. Aborting."
+ exit $RESULT
+ fi
+}
+
+######################
+# MAIN
+######################
+
+# make sure to be root
+if (( `id -u` != 0 )); then { echo "Sorry, must be root. Exiting..."; exit; } fi
+
+echo "$(date): START backup: $SRC -> $DEST"
+do_test
+do_link
+do_backup
+echo "$(date): END backup: $SRC -> $DEST"
+
+exit $RESULT
--- /dev/null
+#!/bin/bash
+#
+# WizBackup Driver 1.0
+# Copyleft 2011 Bernie Innocenti <bernie@codewiz.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License,
+# or (at your option) any later version.
+
+if [ $# -lt 1 ]
+then
+ echo "Usage: $0 [MACHINE-TAB]"
+ echo
+ echo "The MACHINE-TAB file contains hostnames of machines to be backed up, one per line."
+ echo "Empty lines and lines starting with '#' are ignored."
+ exit 1
+fi
+
+HOSTS=`cat $1 | egrep -v '^#|^ *$'`
+
+LOGGROUP=`basename $1`
+LOGDIR=/var/log/wizbackup
+LOCKDIR=/var/lock/wizbackup
+EXCLUDES_DIR=/root/rsync-backups/exclude
+DEST=/backup
+
+today=`date +"%Y%m%d"`
+mkdir -p $LOGDIR
+mkdir -p $LOCKDIR
+
+if [ "`tty`" = "not a tty" ]; then
+ OUTLOGFILE="$LOGDIR/$LOGGROUP-$today.log"
+else
+ LOGFILE=/dev/stdout
+fi
+
+for host in $HOSTS; do
+ opts="--exclude-from $EXCLUDES_DIR/ALWAYS"
+ if [ -f "$EXCLUDES_DIR/$host" ]; then
+ opts="$opts --exclude-from $EXCLUDES_DIR/$host"
+ fi
+
+ start_time=$(date +%s)
+ flock $LOCKDIR/$host wizbackup "$host:/" "$DEST/$host/" $opts >>$LOGFILE 2>&1
+ result=$?
+ end_time=$(date +%s)
+
+ report="$(date):$host:$(($end_time-$start_time)):$result"
+ echo $report >>$LOGDIR/$LOGGROUP-report-$today.log
+ [ $result != 0 ] && echo "$report" >>$LOGDIR/$LOGGROUP-fail-$today.log
+done
+
+# TODO: send fail log email report
+# TODO: delete logs older than 45 days