1 ###############################################################
3 # This handler slowly creates a backup of each user's maildir
4 # to a remote server. It is designed to be run with low overhead
5 # in terms of cpu and bandwidth so it runs pretty slow.
7 # if destdir is /backup/maildir/, then it will contain the files
14 # if keepdaily is 3, keepweekly is 2, and keepmonthly is 1.
16 ##############################################################
27 getconf srcdir /var/maildir
41 [ -d $srcdir ] || fatal "source directory $srcdir doesn't exist"
43 [ ! $test ] || testflags="--dry-run -v"
44 rsyncflags="$testflags -e 'ssh -p $destport'"
45 flags_mail="$rsyncflags --archive --ignore-existing --delete --numeric-ids --size-only --bwlimit=$speedlimit"
46 flags_folders="$rsyncflags --archive --delete --numeric-ids"
47 excludes='--exclude ".Trash/*" --exclude ".Mistakes/*" --exclude ".Spam/*"'
50 debug "ssh -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'"
52 result=`ssh -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1' 2>&1`
53 if [ "$result" != "1" ]; then
54 fatal "Can't connect to $desthost as $destuser."
58 ##################################################################
61 # remote run the args remotely
63 debug ssh -o PasswordAuthentication=no $desthost -l $destuser $@
65 debug ssh -o PasswordAuthentication=no $desthost -l $destuser $@
69 function do_letters() {
70 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
71 do_maildirs "$srcdir/$i"
75 function do_maildirs() {
77 [ -d $dir ] || fatal "directory $dir not found."
78 for userdir in `ls -1 $dir`; do
85 local letter=${user:0:1}
86 local dir="$srcdir/$letter/$user"
87 [ -d $dir ] || fatal "maildir $dir not found".
90 load=`uptime | sed 's/^.*load average: \\([^,]*\\).*$/\\1/'`
91 if [ $load -lt $loadlimit ]; then
92 info "load $load, sleeping..."
99 cmd="rsync $maildirrsyncflags $excludes '$dir' '$destuser@$desthost:$destdir/maildir/$letter'"
101 # ret=`rsync $maildirrsyncflags $excludes '$dir' '$destuser@$desthost:$destdir/maildir/$letter' 2>&1`
104 # remove any maildirs from backup which might have been deleted
105 # and add new ones which have just been created.
107 function do_remove() {
108 local tmp1=/tmp/maildirtmpfile$$
109 local tmp2=/tmp/maildirtmpfile$$
111 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
112 ls -1 "$srcdir/$i" | sort > $tmp1
113 ssh -p $destport $desthost ls -1 '$destdir/maildir/$i' | sort > $tmp2
114 for deluser in `join -v 2 $tmp1 $tmp2`; do
115 cmd="ssh -p $destport $desthost rm -vr '$destdir/maildir/$i/$deluser/'"
123 function do_rotate() {
127 seconds_weekly=604800
128 seconds_monthly=2628000
130 ssh -o PasswordAuthentication=no $desthost -l $destuser <<EOF
132 keepweekly=$keepweekly
133 keepmonthly=$keepmonthly
135 for rottype in daily weekly monthly; do
136 seconds=\`echo seconds_\${rottype}\`
138 dir="$backuproot/\$rottype"
139 if [ ! -d \$dir.1 ]; then
140 echo "Warning: \$dir.1 does not exist. This backup is missing, so we are skipping the rotation."
142 elif [ ! -f \$dir.1/created ]; then
143 echo "Warning: \$dir.1/created does not exist. This backup may be only partially completed, so we are skipping the rotation."
147 # Rotate the current list of backups, if we can.
148 oldest=\`ls -d $\dir.* | sed 's/^.*\.//' | sort -n | tail -1\`
149 for (( i=\$oldest; i > 0; i-- )); do
150 if [ -d \$dir.\$i ]; then
151 if [ -f \$dir.\$i/rotated ]; then
152 rotated=\`tail -1 \$dir.\$i/rotated\`
156 cutoff_time=\$(( now - (seconds*i) ))
157 if [ \$rotated -gt \$cutoff_time ]; then
159 echo "mv \$dir.\$i \$dir.\$next"
160 mv \$dir.\$i \$dir.\$next
161 date +%c%n%s > \$dir.\$next/rotated
163 echo "Info: skipping rotation of \$dir.\$i because it was already rotated within the last " \$((cutoff_time/86400)) " days."
169 max=\$((keepdaily+1))
170 if [ ( \$keepweekly -a -d $backuproot/daily.\$max ) -a ! -d $backuproot/weekly.1 ]; then
171 echo mv $backuproot/daily.\$max $backuproot/weekly.1
172 mv $backuproot/daily.\$max $backuproot/weekly.1
173 date +%c%n%s > $backuproot/weekly.1/rotated
176 max=\$((keepweekly+1))
177 if [ ( \$keepmonthly -a -d $backuproot/weekly.\$max ) -a ! -d $backuproot/monthly.1 ]; then
178 echo mv $backuproot/weekly.\$max $backuproot/monthly.1
179 mv $backuproot/weekly.\$max $backuproot/monthly.1
180 date +%c%n%s > $backuproot/monthly.1/rotated
183 for rottype in daily weekly monthly; do
184 max=\`echo keep\${rottype}\`
186 dir="$backuproot/\$rottype"
187 oldest=\`ls -d $\dir.* | sed 's/^.*\.//' | sort -n | tail -1\`
189 # if we've rotated the last backup off the stack, remove it.
190 for (( i=\$oldest; i >= \$max; i-- )); do
191 if [ -d \$dir.\$i ]; then
192 echo "Info: removing \$dir.\$i"
202 ##################################################################
204 ### ROTATE BACKUPS ###
206 if [ "$rotate" == "yes" ]; then
210 ### REMOVE OLD MAILDIRS ###
212 if [ "$remove" == "yes" ]; then
216 ### ROTATE BACKUPS ###
218 if [ "$letter" != "" ]; then
222 if [ "$user" != "" ]; then