# http://www.mikerubel.org/computers/rsync_snapshots/
#
# feedback: rhatto at riseup.net | gpl
+# lot of enhancements grabbed from "rsnap" handler by paulv at bikkel.org
#
-# config file options
+# Config file options
# -------------------
#
# [general]
# backupdir = folder relative do $mountpoint where the backup should be stored
# days = number of backup increments (min = 5)
# lockfile = lockfile to be kept during backup execution
+# enable_mv_timestamp_bug = set to "yes" if your system isnt handling timestamps correctly
+# tmp = temp folder
#
# [source]
+# from = local or remote
+# testconnect = when "yes", test the connection for a remote source before backup
# include = include folder on backup
# exclude = exclude folder on backup
-# from = local or remote
# ssh = ssh command line (remote only)
-# rsync = rsync command line
+# rsync = rsync program
+# rsync_options = rsync command options
# exclude_vserver = vserver-name (valid only if vservers = yes on backupninja.conf)
+# numericids = when set to 1, use numeric ids instead of user/group mappings on rsync
+# compress = if set to 1, compress data on rsync (remote source only)
+# bandwidthlimit = set a badnwidth limit in kbps (remote source only)
+# remote_rsync = remove rsync program (remote source only)
#
# [services]
# initscripts = absolute path where scripts are located
# service = script name to be stoped at the begining of the backup and started at its end
#
+# You can also specify some system comands:
+#
+# [system]
+# rm = rm command
+# cp = cp command
+# touch = touch command
+# mv = mv command
+# fsck = fsck command
+#
# You dont need to manually specify vservers using "include = /vservers".
-# They are automatically backed-up if vserver is set to "yes" on your backupninja.conf.
+# They are automatically backuped if vserver is set to "yes" on you backupninja.conf.
#
+# config file evaluation
+
+setsection system
+getconf rm rm
+getconf cp cp
+getconf touch touch
+getconf mv mv
+getconf fsck fsck
+
setsection general
getconf log /var/log/backupninja-rub.log
getconf partition
getconf rotate
getconf days
getconf lockfile
+getconf nicelevel 0
+getconf enable_mv_timestamp_bug no
+getconf tmp /tmp
setsection source
getconf from local
-getconf rsync "rsync -av --delete"
+getconf testconnect no
+getconf rsync $RSYNC
+getconf rsync_options "-av --delete"
getconf ssh ssh
getconf user
getconf host
getconf include
getconf exclude
getconf exclude_vserver
+getconf numericids 0
+getconf compress 0
+getconf bandwidthlimit
+getconf remote_rsync rsync
setsection services
getconf initscripts
getconf service
+# function definitions
+
+function rotate {
+
+ # TODO: force to an absolute path
+
+ if [[ "$2" < 4 ]]; then
+ error "Rotate: minimum of 4 rotations"
+ exit 1
+ fi
+
+ if [ -d $1.$2 ]; then
+ $nice $mv $1.$2 $1.tmp
+ fi
+
+ for ((n=`echo "$2 - 1" | bc`; n >= 0; n--)); do
+ if [ -d $1.$n ]; then
+ dest=`echo "$n + 1" | bc`
+ $nice $mv $1.$n $1.$dest
+ $touch $1.$dest
+ fi
+ done
+
+ if [ -d $1.tmp ]; then
+ $nice $mv $1.tmp $1.0
+ fi
+
+ if [ -d $1.1 ]; then
+ $nice $cp -alf $1.1/. $1.0
+ fi
+
+}
+
+function move_files {
+
+ ref=$tmp/makesnapshot-mymv-$$;
+ $touch -r $1 $ref;
+ $mv $1 $2;
+ $touch -r $ref $2;
+ $rm $ref;
+
+}
+
backupdir="$mountpoint/$backupdir"
+# does $backupdir exists?
+
if [ ! -d "$backupdir" ]; then
error "Backupdir $backupdir does not exist"
exit 1
fi
+# setup number of increments
+
if [ -z "$days" ]; then
keep="4"
else
keep="`echo $days - 1 | bc -l`"
fi
+# lockfile setup
+
if [ ! -z "$lockfile" ]; then
- touch $lockfile || warning "Could not create lockfile $lockfile"
+ $touch $lockfile || warning "Could not create lockfile $lockfile"
fi
-for path in $exclude; do
- EXCLUDES="$EXCLUDES --exclude=$path"
-done
+# nicelevel setup
-if [ ! -z "$service" ]; then
- for daemon in $service; do
- info "Stopping service $daemon..."
- $initscripts/$daemon stop
- done
+if [ ! -z "$nicelevel" ]; then
+ nice="nice -n $nicelevel"
+else
+ nice=""
fi
-function rotate {
-
- # please use an absolute path
+# connection test
- if [[ "$2" < 4 ]]; then
- error "Rotate: minimum of 4 rotations"
- exit 1
+if [ "$from" == "remote" ] && [ "$testconnect" == "yes" ]; then
+ debug "$ssh -o PasswordAuthentication=no $user@$host 'echo -n 1'"
+ result=`ssh -o PasswordAuthentication=no $user@$host 'echo -n 1'`
+ if [ "$result" != "1" ]; then
+ fatal "Can't connect to $host as $user."
+ else
+ debug "Connected to $srchost successfully"
fi
+fi
- if [ -d $1.$2 ]; then
- mv $1.$2 $1.tmp
+# rsync options for local sources
+
+if [ "$from" == "local" ]; then
+
+ rsync_local_options="$rsync_options"
+
+ if [ ! -z "$numericids" ]; then
+ rsync_local_options="$rsync_local_options --numeric-ids "
fi
- for ((n=`echo "$2 - 1" | bc`; n >= 0; n--)); do
- if [ -d $1.$n ]; then
- dest=`echo "$n + 1" | bc`
- mv $1.$n $1.$dest
- touch $1.$dest
- fi
- done
+fi
- if [ -d $1.tmp ]; then
- mv $1.tmp $1.0
+# rsync options for remote sources
+
+if [ "$from" == "remote" ]; then
+
+ rsync_remote_options="$rsync_options --rsync-path=$remote_rsync"
+
+ if [ "$compress" == "1" ]; then
+ rsync_remote_options="$rsync_remote_options --compress"
fi
- if [ -d $1.1 ]; then
- cp -alf $1.1/. $1.0
+ fi [ ! -z "$bandwidthlimit" ]; then
+ rsync_remote_options="$rsync_remote_options --bwlimit=$bandwidthlimit"
fi
-}
+ if [ ! -z "$numericids" ]; then
+ rsync_remote_options="$rsync_remote_options --numeric-ids"
+ fi
+
+fi
+
+# set mv procedure
+
+if [ $enable_mv_timestamp_bug == "yes" ]; then
+ mv=move_files
+fi
+
+# set excludes
+
+for path in $exclude; do
+ EXCLUDES="$EXCLUDES --exclude=$path"
+done
+
+# stop services
+
+if [ ! -z "$service" ]; then
+ for daemon in $service; do
+ info "Stopping service $daemon..."
+ $initscripts/$daemon stop
+ done
+fi
echo "Starting backup at `date`" >> $log
+# mount backup destination folder as read-write
+
if [ "$read_only" == "1" ] || [ "$read_only" == "yes" ]; then
if [ -d "$mountpoint" ]; then
mount -o remount,rw $mountpoint
fi
fi
+# add vservers to included folders
+
if [ "$vservers_are_available" == "yes" ]; then
# sane permission on backup
done
fi
+# the backup procedure
+
for SECTION in $include; do
section="`basename $SECTION`"
info "Syncing $SECTION on $backupdir/$SECTION/$section.0..."
if [ "$from" == "local" ]; then
- debug $rsync $EXCLUDES /$SECTION/ $backupdir/$SECTION/$section.0/
- $rsync $EXCLUDES /$SECTION/ $backupdir/$SECTION/$section.0/ >> $log
+ debug $rsync $rsync_local_options $EXCLUDES /$SECTION/ $backupdir/$SECTION/$section.0/
+ $nice $rsync $rsync_local_options $EXCLUDES /$SECTION/ $backupdir/$SECTION/$section.0/ >> $log
if [ "$?" != "0" ]; then
warning "Rsync error when trying to transfer $SECTION"
fi
error "Config file error: either user or host was not specified"
exit 1
else
- debug $rsync $EXCLUDES -e "$ssh" $user@$host:/$SECTION/ $backupdir/$SECTION/$section.0
- $rsync $EXCLUDES -e "$ssh" $user@$host:/$SECTION/ $backupdir/$SECTION/$section.0 >> $log
+ debug $nice $rsync $rsync_remote_options $EXCLUDES -e "$ssh" $user@$host:/$SECTION/ $backupdir/$SECTION/$section.0
+ $nice $rsync $rsync_remote_options $EXCLUDES -e "$ssh" $user@$host:/$SECTION/ $backupdir/$SECTION/$section.0 >> $log
if [ "$?" != "0" ]; then
warning "Rsync error when trying to transfer $SECTION"
fi
exit 1
fi
- touch $backupdir/$SECTION/$section.0
+ $touch $backupdir/$SECTION/$section.0
done
+# remount backup destination as read-only
+
if [ "$read_only" == "1" ] || [ "$read_only" == "yes" ]; then
mount -o remount,ro $mountpoint
fi
+# check partition for errors
+
if [ "$fsck" == "1" ] || [ "$fsck" == "yes" ]; then
umount $mountpoint
if (($?)); then
warning "Could not umount $mountpoint to run fsck"
else
- fsck -v -y $partition >> $log
+ $nice $fsck -v -y $partition >> $log
mount $mountpoint
fi
fi
+# restart services
+
if [ ! -z "$service" ]; then
for daemon in $service; do
info "Starting service $daemon..."
done
fi
+# removes the lockfile
+
if [ ! -z "$lockfile" ]; then
- rm $lockfile || warning "Could not remove lockfile $lockfile"
+ $rm $lockfile || warning "Could not remove lockfile $lockfile"
fi
echo "Finnishing backup at `date`" >> $log