Md at debian.org

tales of a debian maintainer

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

About

This is the blog of Marco d'Itri.

S M T W T F S
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

See also:

My blogroll:


W3C HTML 4.01
W3C CSS 2.0     

Powered by Bryar.pm.