#!/bin/sh
# snapshot
# make a snapshot from directories
# an create hourly/daily/monthly/yearly archieves
# ---------
# neobiker (2006)
# originally based on mirror Version 3.11 By Stu Sheldon stu@actusa.net
# ...
# ...
# The directories are named 'snapshot-<year>-<month>-<day>-<hour>'
#
# Each time snapshot runs, it date stamps a file in the <snapshot> directory called
# 'lastrun.time'. This file's date when listing it using ls -laF shows the last
# date and time snapshot ran on that host.
#
# The last thing you need to do is add snapshot in your crontab with the proper
# times and switches.
#
# If you are going for hourly sync's, add the following to your crontab:
# 0 * * * * /usr/local/sbin/snapshot
#
# Every four hours would be:
# 0 0,4,8,12,16,20 * * * /usr/local/sbin/snapshot
#
# you get the idea
# ...
#########################################################################
# Start User Config Stuff
snapshot="srv1-data"
snaphost="" # localhost
# This is the local root of the backup directories. (where to backup to)
backuproot=/backup
# You need to set the newdayhour to 00-23 depending on what hour you run
# the script in cron.
# 1 4,16,19 * * * /usr/local/sbin/snapshot-srv1
newdayhour=04
# number of snapshots to save
savehours=3
savedays=7
saveweeks=4
savemonths=12
saveyears=10
# list directories to backup
allsrcdir="
/home/
/srv/
/var/lib/cyrus/
/var/spool/
/var/www/
"
# list directories to skip during in backup
# or leave blank
# EXCLUDES=""
EXCLUDES="--filter=. /tmp/excludes-${snapshot}"
cat > /tmp/excludes-${snapshot} << EOF
- lost+found
- /backup/
- /snapshot/
- /var/spool/squid/
- /var/spool/samba/
+ *
EOF
# Mount and Dismount commands for all reasons are in the following functions
# you can also mount windows-shares via smbclient e.g.
# here: mount for writing during backup, and mount readonly afterwards
mounting ()
{
precom=0
mount -o remount,rw ${backuproot} || mountfail
}
umounting ()
{
postcom=0
mount -o remount,ro ${backuproot} || umountfail
}
# Typical Unix saving localhost
if [ -n "snaphost" ]; then
rsync="rsync -a -R -q --delete --numeric-ids -e ssh"
else
rsync="rsync -a -R -q --delete"
fi
# Typical Unix using ssh and public keys
# rsync="rsync -aR -q --numeric-ids -e ssh --delete"
# This has settings for windows and expects to use a mounted share.
# rsync="rsync -a -R -q --delete --modify-window=10"
# End User Config Stuff
############################################################################
# Start Static Code
cmdline=$1
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
cmonth=`date +'%m'`
doweek=`date +'%w'`
cday=`date +'%d'`
chour=`date +'%H'`
yeardir=${backuproot}/${snapshot}/yearly
monthdir=${backuproot}/${snapshot}/monthly
weekdir=${backuproot}/${snapshot}/weekly
daydir=${backuproot}/${snapshot}/daily
hourdir=${backuproot}/${snapshot}/hourly
snapshotdir=`date +'snapshot-%Y-%m-%d-%H'`
lockfile=${backuproot}/${snapshot}/syncing-now
lsync=`/bin/ls -1r ${hourdir} | head -1`
lday=`date +'snapshot-%Y-%m-%d-%H' -d '1 day ago'`
lweek=`date +'snapshot-%Y-%m-%d-%H' -d '1 week ago'`
makedirs ()
{
[ -d ${yeardir} ] || mkdir -p ${yeardir}
[ -d ${monthdir} ] || mkdir -p ${monthdir}
[ -d ${weekdir} ] || mkdir -p ${weekdir}
[ -d ${daydir} ] || mkdir -p ${daydir}
[ -d ${hourdir} ] || mkdir -p ${hourdir}
}
dosync ()
{
[ -d ${hourdir}/${snapshotdir} ] || mkdir -p ${hourdir}/${snapshotdir}
[ -n "${lsync}" ] && rsync="${rsync} --link-dest=${hourdir}/${lsync}"
for srcdir in ${allsrcdir}; do
if [ -n "$snaphost" ]; then
srcdir=${snaphost}:${srcdir}
fi
${rsync} "${EXCLUDES}" ${srcdir} ${hourdir}/${snapshotdir}
done
}
doyearly ()
{
[ ${saveyears} -eq 0 ] && return
if [ -d ${monthdir}/${snapshotdir} ]; then
cp -alf ${monthdir}/${snapshotdir} ${yeardir}
else
echo >&2 "I can't find snapshot ${monthdir}/${snapshotdir}..."
fi
}
domonthly ()
{
[ ${savemonths} -eq 0 ] && return
if [ -d ${hourdir}/${snapshotdir} ]; then
mv ${hourdir}/${snapshotdir} ${monthdir}
ln -s ${monthdir}/${snapshotdir} ${hourdir}/${snapshotdir}
else
echo >&2 "I can't find snapshot ${hourdir}/${snapshotdir}..."
fi
}
doweekly ()
{
[ ${saveweeks} -eq 0 ] && return
if [ -d ${daydir}/${lweek} ]; then
mv ${daydir}/${lweek} ${weekdir}
else
echo >&2 "I can't find snapshot ${daydir}/${lweek}..."
fi
}
dodaily ()
{
[ ${savedays} -eq 0 ] && return
if [ -d ${hourdir}/${lday} ]; then
mv ${hourdir}/${lday} ${daydir}
else
echo >&2 "I can't find snapshot ${hourdir}/${lday}..."
fi
}
docleanup ()
{
[ ${savehours} -lt 1 ] && savehours=1
count=0
for i in `/bin/ls -r ${hourdir}`; do
let count=count+1
if [ ${count} -gt ${savehours} ]; then
rm -Rf ${hourdir}/${i}
fi
done
[ ${saveweeks} -gt 0 -a ${savedays} -lt 7 ] && savedays=7
count=0
for i in `/bin/ls -r ${daydir}`; do
let count=count+1
if [ ${count} -gt ${savedays} ]; then
rm -Rf ${daydir}/${i}
fi
done
count=0
for i in `/bin/ls -r ${weekdir}`; do
let count=count+1
if [ ${count} -gt ${saveweeks} ]; then
rm -Rf ${weekdir}/${i}
fi
done
count=0
for i in `/bin/ls -r ${monthdir}`; do
let count=count+1
if [ ${count} -gt ${savemonths} ]; then
rm -Rf ${monthdir}/${i}
fi
done
count=0
for i in `/bin/ls -r ${yeardir}`; do
let count=count+1
if [ ${count} -gt ${saveyears} ]; then
rm -Rf ${yeardir}/${i}
fi
done
}
inuse ()
{
echo >&2 "I am already syncing snapshot ${snapshot}"
exit 1
}
mountfail ()
{
echo >&2 "I can't mount filesystem ${backuproot}"
exit 1
}
umountfail ()
{
echo >&2 "I can't unmount filesystem ${backuproot}"
exit 1
}
####
#### Programm starts here ... ###########################
####
[ -f ${lockfile} ] && inuse
mounting
makedirs
touch ${lockfile}
case ${cmdline} in
-y)
doyearly
docleanup
;;
-m)
domonthly
docleanup
;;
*)
dosync
if [ ${newdayhour} -eq ${chour} ]; then
dodaily
if [ ${doweek} -eq 0 ]; then
doweekly
fi
if [ ${cday} -eq 01 ]; then
domonthly
if [ ${cmonth} -eq 01 ]; then
doyearly
fi
fi
fi
docleanup
;;
esac
touch ${backuproot}/${snapshot}/lastrun.time
rm -f ${lockfile}
rm -f /tmp/excludes-${snapshot}
umounting
echo "Backup for ${snapshot} is complete..."