mirror of
https://0xacab.org/liberate/backupninja.git
synced 2024-09-19 23:21:40 +02:00
78884142e7
The modelines added match the emacs lines already present and also set the filetype to sh (just like the emacs lines).
353 lines
8.5 KiB
Bash
353 lines
8.5 KiB
Bash
# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
|
|
# vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
|
|
#
|
|
# backupninja handler to do incremental backups using
|
|
# rsync and hardlinks, based on
|
|
#
|
|
# 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
|
|
# -------------------
|
|
#
|
|
# [general]
|
|
# log = rsync log file
|
|
# partition = partition where the backup lives
|
|
# fscheck = set to 1 if fsck should run on $partition after the backup is made
|
|
# read_only = set to 1 if $partition is mounted read-only
|
|
# mountpoint = backup partition mountpoint or backup main folder
|
|
# 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
|
|
# nicelevel = rsync command nice level
|
|
# enable_mv_timestamp_bug = set to "yes" if your system isnt handling timestamps correctly
|
|
# tmp = temp folder
|
|
#
|
|
# [source]
|
|
# from = local or remote
|
|
# host = source hostname or ip, if remote backup
|
|
# testconnect = when "yes", test the connection for a remote source before backup
|
|
# include = include folder on backup
|
|
# exclude = exclude folder on backup
|
|
# ssh = ssh command line (remote only)
|
|
# 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 = remote 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 if you don't want the default system values:
|
|
#
|
|
# [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 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/backup/rsync.log
|
|
getconf partition
|
|
getconf fscheck
|
|
getconf read_only
|
|
getconf mountpoint
|
|
getconf backupdir
|
|
getconf rotate
|
|
getconf days
|
|
getconf lockfile
|
|
getconf nicelevel 0
|
|
getconf enable_mv_timestamp_bug no
|
|
getconf tmp /tmp
|
|
|
|
setsection source
|
|
getconf from local
|
|
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 {
|
|
|
|
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"
|
|
fi
|
|
|
|
# nicelevel setup
|
|
|
|
if [ ! -z "$nicelevel" ]; then
|
|
nice="nice -n $nicelevel"
|
|
else
|
|
nice=""
|
|
fi
|
|
|
|
# connection test
|
|
|
|
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
|
|
|
|
# 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
|
|
|
|
fi
|
|
|
|
# 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 [ ! -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
|
|
if (($?)); then
|
|
error "Could not mount $mountpoint"
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# add vservers to included folders
|
|
|
|
if [ "$vservers_are_available" == "yes" ]; then
|
|
|
|
# sane permission on backup
|
|
mkdir -p $backupdir/$VROOTDIR
|
|
chmod 000 $backupdir/$VROOTDIR
|
|
|
|
for candidate in $found_vservers; do
|
|
candidate="`basename $candidate`"
|
|
found_excluded_vserver="0"
|
|
for excluded_vserver in $exclude_vserver; do
|
|
if [ "$excluded_vserver" == "$candidate" ]; then
|
|
found_excluded_vserver="1"
|
|
break
|
|
fi
|
|
done
|
|
if [ "$found_excluded_vserver" == "0" ]; then
|
|
include="$include $VROOTDIR/$candidate"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# the backup procedure
|
|
|
|
for SECTION in $include; do
|
|
|
|
section="`basename $SECTION`"
|
|
|
|
if [ ! -d "$backupdir/$SECTION/$section.0" ]; then
|
|
mkdir -p $backupdir/$SECTION/$section.0
|
|
fi
|
|
|
|
info "Rotating $backupdir/$SECTION/$section..."
|
|
echo "Rotating $backupdir/$SECTION/$section..." >> $log
|
|
rotate $backupdir/$SECTION/$section $keep
|
|
info "Syncing $SECTION on $backupdir/$SECTION/$section.0..."
|
|
|
|
if [ "$from" == "local" ]; then
|
|
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
|
|
elif [ "$from" == "remote" ]; then
|
|
if [ -z "$user" ] || [ -z "$host" ]; then
|
|
error "Config file error: either user or host was not specified"
|
|
exit 1
|
|
else
|
|
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
|
|
fi
|
|
else
|
|
error "Invalid source $from"
|
|
exit 1
|
|
fi
|
|
|
|
$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 [ "$fscheck" == "1" ] || [ "$fscheck" == "yes" ]; then
|
|
umount $mountpoint
|
|
if (($?)); then
|
|
warning "Could not umount $mountpoint to run fsck"
|
|
else
|
|
$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..."
|
|
$initscripts/$daemon start
|
|
done
|
|
fi
|
|
|
|
# removes the lockfile
|
|
|
|
if [ ! -z "$lockfile" ]; then
|
|
$rm $lockfile || warning "Could not remove lockfile $lockfile"
|
|
fi
|
|
|
|
echo "Finnishing backup at `date`" >> $log
|
|
|