Mon, 19 Jan 2009
automatic backups on a removable device
These scripts allow automatically running rsnapshot when the right USB hard disk is plugged in.
If you do not want so much automation then just let gnome-volume-manager do its work and then run the last script from the command line.
/etc/udev/rules.d/68-automount.rules
:
ACTION=="add", SUBSYSTEM=="block", \ ENV{ID_FS_USAGE}=="filesystem", ENV{ID_FS_LABEL}=="red", \ RUN+="backup.agent $env{ID_FS_LABEL}"
/lib/udev/backup.agent
:
#!/bin/sh -e ############################################################################## wait_for_fs() { local fs_path="$1" local count="$2" if [ -z "$count" ]; then count=60; fi while ! mountpoint -q $fs_path; do sleep 1 count=$(($count - 1)) if [ $count -eq 0 ]; then echo "$fs_path has not been mounted after $count seconds!" 1>&2 return 1 fi done return 0 } ############################################################################## do_stuff() { if [ -e /tmp/nobackup ]; then exit 0; fi wait_for_fs $FSPATH || exit 1 nice -n 19 ionice -c 3 sh $FSPATH/doit rsnapshot -v diff daily.0 daily.1 | mail -s "rsnapshot diff" md if [ -e /tmp/noumount ]; then exit 0; fi pumount $FSPATH } ############################################################################## if [ ! -t 0 ]; then exec >> /var/log/backup.log 2>&1 fi if [ "$1" ]; then FSNAME="$1" else echo "Usage: $0 name" exit 1 fi FSPATH="/media/$FSNAME" # the script may be called multiple times due to multiple change events # being fired by the kernel if mountpoint -q $FSPATH; then exit 0; fi # daemonize do_stuff &
A while loop which waits for the file system to appear is not elegant, but you cannot do this the right way™ with only a shell script because it requires watching /proc/mounts
using inotify(3)
.
/media/red/doit
:
#!/bin/sh -e ############################################################################## file_older_than_days() { local filename="$1" local days="$2" # consider a day passed if it will end in at most 6 hours local more=$((60 * 60 * 6)) local now=$(date +%s) local filetime=$(stat --format=%Y "$filename" 2> /dev/null || echo 0) local age=$(($now - $filetime)) if [ "$age" -gt $((60 * 60 * 24 * $days - $more)) ]; then return 0 else return 1 fi } ############################################################################## RSNAPSHOT_ROOT=$(awk '/^snapshot_root[\t ]/ { print $2 }' /etc/rsnapshot.conf) if [ -z "$RSNAPSHOT_ROOT" ]; then echo "Cannot determine snapshot_root!" exit 1 elif [ ! -d "$RSNAPSHOT_ROOT" ]; then echo "snapshot_root is not a directory: $RSNAPSHOT_ROOT" exit 1 fi if file_older_than_days "$RSNAPSHOT_ROOT/daily.0/" 1; then if file_older_than_days "$RSNAPSHOT_ROOT/weekly.0/" 14; then if file_older_than_days "$RSNAPSHOT_ROOT/monthly.0/" 60; then /usr/bin/rsnapshot monthly fi /usr/bin/rsnapshot weekly fi /usr/bin/rsnapshot daily fi