User:Unhammer/backup

From ArchWiki
Jump to navigation Jump to search

http://www.jwz.org/blog/2007/09/psa-backups/ is a great post on how to deal with backup. I used to be among the Option 1 group, keeping projects in online version control and reinstalling if necessary. But now I have (1) an SSD that is expected to crash within 1-2 years and (2) a lot of photos that need backing up (and online storage is always too slow and/or costly).

I follow the simple jwz rsync+cron strategy on my desktop, but the laptop of course doesn't have an external drive constantly connected to it. I wanted a user-friendly "autorun" backup that opens when you plug a certain drive in, and asks whether to do a backup.

My solution requires consolekit and udev, and uses zenity to send messages (could probably be changed to dialog/kdialog/gdialog/… if you want).


I have one file /root/backup.sh that simply runs the rsync on my two partitions:

#!/bin/sh
if mount | grep -q '/media/paddebackup'; then
	rsync -vaxAX --delete --ignore-errors --exclude-from=/root/backup-excludes-home /home/ /media/paddebackup/home/
	rsync -vaxAX --delete --ignore-errors --exclude-from=/root/backup-excludes-root / /media/paddebackup/
else
	echo "Can't find the drive paddebackup" 1>&2
	exit 1
fi
sleep 2
sync
# Optional: spin down the drive:
# sdparm --flexible --command=stop /dev/paddebackup
umount /media/paddebackup

In my excludes I have e.g. the .gvfs files (they always give errors), and /dev, /proc, /media, /mnt, /cdrom, /tmp.


Then I have a file /etc/udev/rules.d/paddebackup-usb.rules which which runs a script on plugging in the drive:

ACTION=="add", ATTRS{idVendor}=="1058", ATTRS{product}=="External HDD    ", SUBSYSTEM=="usb", SYMLINK="paddebackup", RUN+="/root/backup-ask-current-user.sh"

If you want to use this, you'll have to change the idVendor and product fields. Type lsusb to show your connected usb drives, now:

  • The first number after the word "ID" will be idVendor.
  • The second number after "ID" (after the colon) will be idProduct, which you can use instead of the string product.
    • If you want to use product instead of idProduct: type udevadm info -a --name /dev/sdb1|grep product (if it's mounted at /dev/sdb1).

The SYMLINK field creates a second device node at /dev/paddebackup, just a convenience in case it is ever placed somewhere instead of /dev/sdb1, while the RUN field runs my user-interaction script.

Unfortunately I can't get this to run after automounting (using SUBSYSTEM=="block" just made the script run twice), so instead the below script forks and sleeps a bit.


The file /root/backup-ask-current-user.sh, run by udev, finds the currently active user and asks them whether to take a backup (ie. whether to run /root/backup.sh) or not:

#!/bin/bash
ACTIVE=$(ck-list-sessions | awk -F' = ' 'function f(){if(A=="TRUE"){P=U"\t"D;gsub("'"'"'","",P);print P}}
$1=="\tunix-user"{U=$2} 
$1=="\tx11-display"{D=$2} 
$1=="\tactive"{A=$2} 
END{f()} /^[^\t]/{f()}')
USERID=${ACTIVE%	*} # tab
USERNAME=$(getent passwd $USERID|cut -f1 -d':')
DISPLAY=${ACTIVE#*	} # tab

odus () { # inverse sudo =P
	C=''
	for i in "$@";do 
		# quote each parameter and escape quotes:
		C="$C \"${i//\"/\\\"}\""
	done
	DISPLAY="$DISPLAY" su $USERNAME -c "$C";
}

backup () {
    echo "Sleeping while waiting for USB to automount ..."; sleep 10
    odus zenity --question --text "Take backup?" --title "Backup" &&
    (
	set -o pipefail		# since we pipe through zenity
	if /root/backup.sh 2> /tmp/backup.err | tee /tmp/backup.log | odus zenity --progress --auto-close --pulsate --title "Backing up" --text "Backup progress" ; then
	    odus zenity --text-info --title "Backup successful" --cancel-label "Sure" --ok-label "Yeah" < /tmp/backup.log;
	else
	    odus zenity --text-info --window-icon warning --title "Backup had errors" --cancel-label "Oh?" --ok-label "That sucks" < /tmp/backup.err;
	    exit 1
	fi
    )
}

test -n "$USERNAME" && test -n "$DISPLAY" && backup &

ConsoleKit (ck-list-sessions) is necessary to show who is currently using the physical computer (guess I should check for local=TRUE too), not sure if there are ConsoleKit-less ways of doing this in a non-hacky way. We need to know the username and display number in order to send the dialog messages. So this just runs the backup if the user presses ok, then lists the standard log if it was ok, or the error log if it wasn't.


Very simple to use, and lets a non-geek use the laptop and run backups too :)