mirror of
https://0xacab.org/liberate/backupninja.git
synced 2024-11-10 04:42:31 +01:00
225 lines
5.8 KiB
Plaintext
225 lines
5.8 KiB
Plaintext
###############################################################
|
|
#
|
|
# This handler slowly creates a backup of each user's maildir
|
|
# to a remote server. It is designed to be run with low overhead
|
|
# in terms of cpu and bandwidth so it runs pretty slow.
|
|
#
|
|
# if destdir is /backup/maildir/, then it will contain the files
|
|
# daily.1
|
|
# daily.2
|
|
# daily.3
|
|
# weekly.1
|
|
# weekly.2
|
|
# monthly.1
|
|
# if keepdaily is 3, keepweekly is 2, and keepmonthly is 1.
|
|
#
|
|
##############################################################
|
|
|
|
getconf rotate yes
|
|
getconf remove yes
|
|
|
|
getconf loadlimit 5
|
|
getconf speedlimit 0
|
|
getconf keepdaily 5
|
|
getconf keepweekly 3
|
|
getconf keepmonthly 1
|
|
|
|
getconf srcdir /var/maildir
|
|
getconf destdir
|
|
getconf desthost
|
|
getconf destport 22
|
|
getconf destuser
|
|
|
|
# strip trailing /
|
|
destdir=${destdir%/}
|
|
srcdir=${srcdir%/}
|
|
|
|
# used for testing
|
|
getconf letter
|
|
getconf user
|
|
|
|
[ -d $srcdir ] || fatal "source directory $srcdir doesn't exist"
|
|
|
|
[ ! $test ] || testflags="--dry-run -v"
|
|
rsyncflags="$testflags -e 'ssh -p $destport'"
|
|
flags_mail="$rsyncflags --archive --ignore-existing --delete --numeric-ids --size-only --bwlimit=$speedlimit"
|
|
flags_folders="$rsyncflags --archive --delete --numeric-ids"
|
|
excludes='--exclude ".Trash/*" --exclude ".Mistakes/*" --exclude ".Spam/*"'
|
|
|
|
# see if we can login
|
|
debug "ssh -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'"
|
|
if [ ! $test ]; then
|
|
result=`ssh -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1' 2>&1`
|
|
if [ "$result" != "1" ]; then
|
|
fatal "Can't connect to $desthost as $destuser."
|
|
fi
|
|
fi
|
|
|
|
##################################################################
|
|
### FUNCTIONS
|
|
|
|
# remote run the args remotely
|
|
function rrun() {
|
|
debug ssh -o PasswordAuthentication=no $desthost -l $destuser $@
|
|
if [ ! $test ]; then
|
|
debug ssh -o PasswordAuthentication=no $desthost -l $destuser $@
|
|
fi
|
|
}
|
|
|
|
function do_letters() {
|
|
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
|
|
do_maildirs "$srcdir/$i"
|
|
done
|
|
}
|
|
|
|
function do_maildirs() {
|
|
local dir=$1
|
|
[ -d $dir ] || fatal "directory $dir not found."
|
|
for userdir in `ls -1 $dir`; do
|
|
do_userdir $userdir
|
|
done
|
|
}
|
|
|
|
function do_user() {
|
|
local user=$1
|
|
local letter=${user:0:1}
|
|
local dir="$srcdir/$letter/$user"
|
|
[ -d $dir ] || fatal "maildir $dir not found".
|
|
|
|
while 1; do
|
|
load=`uptime | sed 's/^.*load average: \\([^,]*\\).*$/\\1/'`
|
|
if [ $load -lt $loadlimit ]; then
|
|
info "load $load, sleeping..."
|
|
sleep 600
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
|
|
cmd="rsync $maildirrsyncflags $excludes '$dir' '$destuser@$desthost:$destdir/maildir/$letter'"
|
|
debug $cmd
|
|
# ret=`rsync $maildirrsyncflags $excludes '$dir' '$destuser@$desthost:$destdir/maildir/$letter' 2>&1`
|
|
}
|
|
|
|
# remove any maildirs from backup which might have been deleted
|
|
# and add new ones which have just been created.
|
|
|
|
function do_remove() {
|
|
local tmp1=/tmp/maildirtmpfile$$
|
|
local tmp2=/tmp/maildirtmpfile$$
|
|
|
|
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
|
|
ls -1 "$srcdir/$i" | sort > $tmp1
|
|
ssh -p $destport $desthost ls -1 '$destdir/maildir/$i' | sort > $tmp2
|
|
for deluser in `join -v 2 $tmp1 $tmp2`; do
|
|
cmd="ssh -p $destport $desthost rm -vr '$destdir/maildir/$i/$deluser/'"
|
|
debug $cmd
|
|
done
|
|
done
|
|
rm $tmp1
|
|
rm $tmp2
|
|
}
|
|
|
|
function do_rotate() {
|
|
backuproot=$destdir
|
|
now=`date %s`
|
|
seconds_daily=86400
|
|
seconds_weekly=604800
|
|
seconds_monthly=2628000
|
|
|
|
ssh -o PasswordAuthentication=no $desthost -l $destuser <<EOF
|
|
keepdaily=$keepdaily
|
|
keepweekly=$keepweekly
|
|
keepmonthly=$keepmonthly
|
|
|
|
for rottype in daily weekly monthly; do
|
|
seconds=\`echo seconds_\${rottype}\`
|
|
|
|
dir="$backuproot/\$rottype"
|
|
if [ ! -d \$dir.1 ]; then
|
|
echo "Warning: \$dir.1 does not exist. This backup is missing, so we are skipping the rotation."
|
|
continue
|
|
elif [ ! -f \$dir.1/created ]; then
|
|
echo "Warning: \$dir.1/created does not exist. This backup may be only partially completed, so we are skipping the rotation."
|
|
continue
|
|
fi
|
|
|
|
# Rotate the current list of backups, if we can.
|
|
oldest=\`ls -d $\dir.* | sed 's/^.*\.//' | sort -n | tail -1\`
|
|
for (( i=\$oldest; i > 0; i-- )); do
|
|
if [ -d \$dir.\$i ]; then
|
|
if [ -f \$dir.\$i/rotated ]; then
|
|
rotated=\`tail -1 \$dir.\$i/rotated\`
|
|
else
|
|
rotated=0
|
|
fi
|
|
cutoff_time=\$(( now - (seconds*i) ))
|
|
if [ \$rotated -gt \$cutoff_time ]; then
|
|
next=\$(( i + 1 ))
|
|
echo "mv \$dir.\$i \$dir.\$next"
|
|
mv \$dir.\$i \$dir.\$next
|
|
date +%c%n%s > \$dir.\$next/rotated
|
|
else
|
|
echo "Info: skipping rotation of \$dir.\$i because it was already rotated within the last " \$((cutoff_time/86400)) " days."
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
|
|
max=\$((keepdaily+1))
|
|
if [ ( \$keepweekly -a -d $backuproot/daily.\$max ) -a ! -d $backuproot/weekly.1 ]; then
|
|
echo mv $backuproot/daily.\$max $backuproot/weekly.1
|
|
mv $backuproot/daily.\$max $backuproot/weekly.1
|
|
date +%c%n%s > $backuproot/weekly.1/rotated
|
|
fi
|
|
|
|
max=\$((keepweekly+1))
|
|
if [ ( \$keepmonthly -a -d $backuproot/weekly.\$max ) -a ! -d $backuproot/monthly.1 ]; then
|
|
echo mv $backuproot/weekly.\$max $backuproot/monthly.1
|
|
mv $backuproot/weekly.\$max $backuproot/monthly.1
|
|
date +%c%n%s > $backuproot/monthly.1/rotated
|
|
fi
|
|
|
|
for rottype in daily weekly monthly; do
|
|
max=\`echo keep\${rottype}\`
|
|
max=\$((max+1))
|
|
dir="$backuproot/\$rottype"
|
|
oldest=\`ls -d $\dir.* | sed 's/^.*\.//' | sort -n | tail -1\`
|
|
|
|
# if we've rotated the last backup off the stack, remove it.
|
|
for (( i=\$oldest; i >= \$max; i-- )); do
|
|
if [ -d \$dir.\$i ]; then
|
|
echo "Info: removing \$dir.\$i"
|
|
rm -rf \$dir.\$i
|
|
fi
|
|
done
|
|
done
|
|
EOF
|
|
}
|
|
|
|
|
|
###
|
|
##################################################################
|
|
|
|
### ROTATE BACKUPS ###
|
|
|
|
if [ "$rotate" == "yes" ]; then
|
|
do_rotate
|
|
fi
|
|
|
|
### REMOVE OLD MAILDIRS ###
|
|
|
|
if [ "$remove" == "yes" ]; then
|
|
debug remove
|
|
fi
|
|
|
|
### ROTATE BACKUPS ###
|
|
|
|
if [ "$letter" != "" ]; then
|
|
debug letter
|
|
fi
|
|
|
|
if [ "$user" != "" ]; then
|
|
debug user
|
|
fi
|