#!/bin/bash
#
# This is a simple snapshot-ish style backup with rsync and ssh, based on the
# principe from [1]. This script pushes a copy to a user account on a remote
# machine and doenst require root access on the remote machine.
#
# To automate the process ssh-keys can be exchanged such that root on the
# machine being backed up logs in as say "remotebackup" on the storage server,
# se how below.
#
# [1] http://www.mikerubel.org/computers/rsync_snapshots/
#
# Martin Leopold May 30. 2004
#
#
# Setup ssh-keys to allow root-login without PW:
# http://heanet.dl.sourceforge.net/sourceforge/backuppc/BackupPC-2.0.2_doc.html#step 5: client setup
#
# Key generation
# From the machine (and user) that is suppuse to be able to login somewhere
# (the pc storing it's backup somewhere) generate a key as "root" wo.
# pass-phrase:
#   ssh-keygen -t rsa -N ''
#       => public key in ~/.ssh/id_rsa.pub
#
# Key exchange
# Copy the public key to the machine that is suppose to allow login and add
# to authorized keys for the user allowing pw-less login:
#    touch ~/.ssh/authorized_keys2
#    cat id_rsa.pub >> ~/.ssh/authorized_keys2
#    chmod 700 ~/.ssh/authorized_keys2
#
# Test:
#    ssh remotebackup@serv.duplex.dk whoami
#
# You should edit ~/.ssh/authorized_keys2 and add further specifiers, eg:
# from, to limit which hosts can login using this key in authorized_keys2
#   from="backuppc.my.com" ssh-rsa [base64 key, eg: ABwBCEAIIALyoqa8....]
#
#
# Changes:
# 20/08-2009: Added BACKUP_CONFIG_FILE
# 23/10-2008: Cleanup
# 23/10-2008: Add PRE_CMD and POST_CMD
# 23/10-2008: Allow backups on localhost
# 22/10-2008: Changed sh to bash
# 16/11-2006: Added "EXCLUDE_FILE"
# 14/ 5-2006: Fixed bug: now more than one cmd arg is passed to rsync
# 24/ 4-2006: Changed --delete-after to --delete
# 20/ 1-2006: Stuffed all config options into one config file
#             /etc/backup.cfg
# 21/11-2005: Added BACKUP_SAVE_DIRS that sets how many copies are stored on
#             the server (set as env. variable)
# 20/ 5-2005: Added BACKUP_CONFIG_DIR to specify location of config-files
#             (this can be done as an env. variable).
# 21/ 3-2005: Added -z option for rsync
#  4/ 3-2005: Remotehost is now host and username
#  3/ 3-2005: Extra args to rsync can be given on commandline (ex. from cron)
#  2/ 3-2005: Uses config file instead of local variables
#  /etc/backup.dirs - list of dirs space separated
#  /etc/backup.hostname - name of remote dir
#  /etc/backup.rsyncargs - extra args for rsync (like --bwlimit=10)
#  /etc/backup.remotehost - ssh-style host and username


# Get backup config dir from env
if [ -z "$BACKUP_CONFIG_DIR" ]; then
     BACKUP_CONFIG_DIR="/etc"
fi

if [ -z "$BACKUP_CONFIG_FILE" ]; then
     BACKUP_CONFIG_FILE="backup.cfg"
fi

# Defaults
BACKUP_SAVE_DIRS=10
LBIN="/bin"

[ -f $BACKUP_CONFIG_DIR/$BACKUP_CONFIG_FILE ] && . $BACKUP_CONFIG_DIR/$BACKUP_CONFIG_FILE

CMDARGS=$@

if [ -n "$EXCLUDE_FILE" ]; then
  RSYNC_ARGS="$RSYNC_ARGS --exclude-from=$EXCLUDE_FILE"
fi

# Only append SSH prefix to commands if backing up to remote location
SSH_PRE=$LBIN
RSYNC_DEST=$REMOTE_BACKUP_DIR
if [ `echo $REMOTE_HOST | grep \@` ] ; then
 if [ -z `echo $REMOTE_HOST | grep \@localhost` ] ; then
  SSH_PRE="$LPATH/ssh $REMOTE_HOST $RBIN"
  RSYNC_ARGS+=" -e ssh"
  RSYNC_DEST="$REMOTE_HOST:$RSYNC_DEST"
 fi
fi

if [ -n "$PRE_CMD" ] ; then
  $PRE_CMD
fi

for DIR in $DIRS_TO_BACKUP; do
 BASE=`$LPATH/basename $DIR`

 # Save the last dir for recycle
 LAST_DIR=$REMOTE_BACKUP_DIR/$BASE.$(($BACKUP_SAVE_DIRS-1))
 TMP_DIR=$REMOTE_BACKUP_DIR/$BASE.tmp
 $SSH_PRE/mv -f $LAST_DIR $REMOTE_BACKUP_DIR/$BASE.tmp

 # Move all dirs one step forward .1 -> .2, .0 -> .1, etc.
 for (( i=$BACKUP_SAVE_DIRS-1 ;  $i > 0 ; i=$i-1)); do
   CUR_DIR=$REMOTE_BACKUP_DIR/$BASE.$(($i-1))
   $SSH_PRE/mv -f $CUR_DIR $REMOTE_BACKUP_DIR/$BASE.$i
 done

 # Recycle last dir for increased speed. If number of backup-cycles hasn't
 # reached maximum yet - no recycle will happen which should decrease speed
 $SSH_PRE/mv -f $TMP_DIR $REMOTE_BACKUP_DIR/$BASE.0

 # Copy second but last (.1) with hard links to conserve space (to .0)
 echo Backing up $DIR to $REMOTE_BACKUP_DIR/$BASE.1/
 $SSH_PRE/cp -alf $REMOTE_BACKUP_DIR/$BASE.1/. $REMOTE_BACKUP_DIR/$BASE.0

 # Rsync backup to .0 dir
 $LPATH/rsync $RSYNC_ARGS $CMDARGS -z --rsync-path=$RPATH/rsync \
   -a --delete $DIR/ $RSYNC_DEST/$BASE.0/
done

if [ -n "$POST_CMD" ] ; then
  $POST_CMD
fi

