Ubuntu: backup to USB drive on mount

Hi everyone,

I always was sloppy with my backups and I really needed to do something about it. I bought a new Freecom HDD 500GB and what I wanted to do is quickly backup my files every time I plug the device in, and it should give me a proper notice when the backup is done.

Doesn’t sound that hard, or does it?

It became clear that I needed a little thingy called “udev”. And with big help from unutbu from ubuntuforums.org I managed to get a very nice script up and running.

First thing you have to do is to know how your system recognizes your USB drive.

I followed this great tutorial here. (Don’t bother the fstab!)

My rules look like these.

1
2
 
SUBSYSTEMS=="usb", KERNEL=="sd?1", ATTRS{product}=="Freecom Network Drive", NAME="freecomHD", RUN+="/usr/bin/usb_backup.sh"

Note that I have saved them under “/etc/udev/rules.d/81-local.rules”, because /etc/udev/rules.d/README says. It would also be safer I you select your device using UUID.

Files should be named xx-descriptive-name.rules, the xx should be
chosen first according to the following sequence points:

80 rules that run programs (but do not load modules)

After adding your rule, you need to restart udev.

$ sudo /etc/init.d/udev restart

Next install libnotify-bin through synaptic. This will make it possible for us to show notifies as if it were GNOME itself ;)

Next we’ll need to hack the script a little bit:


Place this in “/usr/local/bin/alt-notify-send”

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
#!/bin/sh
user=`whoami`
pids=`pgrep -u $user gnome-panel`
title=$1
text=$2
timeout=$3
 
if [ -z "$title" ]; then
        echo You need to give me a title >&2
        exit 1
fi
if [ -z "$text" ]; then
        text=$title
fi
if [ -z "$timeout" ]; then
        timeout=60000
fi
 
for pid in $pids; do
        # find DBUS session bus for this session
        DBUS_SESSION_BUS_ADDRESS=`grep -z DBUS_SESSION_BUS_ADDRESS \
                /proc/$pid/environ | sed -e 's/DBUS_SESSION_BUS_ADDRESS=//'`
        # use it
        DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS \
        notify-send -u low -t $timeout "$title" "$text"
done

This is because

The reason why notify-send was not working was because notify-send uses the DBUS_SESSION_BUS_ADDRESS environment variable and that variable was not set in the shell that runs your script. This environment variable is set when you start a gnome session, but is not set when root runs a udev rule.

Moreover, one user can not send messages to another user using notify-send. So we use “su” to change root to your normal user, and we use the alt-notify-send script to find and set the DBUS_SESSION_BUS_ADDRESS before launching notify-send.

(unutbu)

Then I created a file /usr/bin/usb_backup.sh.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
{
mount_point=$(grep freecomHD /etc/mtab)
attempts=1
while [ -z "$mount_point" ] && [ "$attempts" -le 50 ]; do
    # $mount_point has not been found
    # quit if this fails more than 50 times. 
    # This should not be necessary, but it better to be safe
    # than have the script trapped in this loop forever for
    # some unforeseen reason.
    sleep 1
    mount_point=$(grep freecomHD /etc/mtab)
    attempts=$(($attempts+1))
done
 
if [ -n "$mount_point" ]; then
    su ruben alt-notify-send "Backup Message" "USB Backup device detected" 0
 
    rsync -a /home/ruben/ /media/FREECOM\ HDD/
 
    su ruben alt-notify-send "Backup Message" "Your USB Backup has completed" 0
fi
} &

Note that my user is named “ruben” and that you should replace it by your own. Also replace the the name in mount_point to the name you have given in your udev-rules.

Also note that the whole process is run in a new process (due to the “&” character). Otherwise ubuntu will try to do the backup before the mount. But it needs to be mounted before backup. This requires the little hack on top of the script ;)

Don’t forget to make the scripts executable!

1
2
$ sudo chmod 755 /usr/bin/usb_backup.sh
$ sudo chmod 755 /usr/local/bin/alt-notify-send

It may be a good thing to tweak your rsync a little bit, so you don’t lose too much time every time you plug in.

And that’s it! This was a little harder than I thought. But then again, it shows that you’re absolutely free to do whatever you want on ubuntu. This is why we all love our tux.

Hope this helped somebody. And stick around to read more about all sorts of stuff!

Happy coding!

Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks

10 comments on “Ubuntu: backup to USB drive on mount

  1. mihai says:

    Hi. Can you tell me why your script fires 14 times? Not exactly what I hoped for.

  2. ruben says:

    How do you mean ‘fires 14 times’?

    Never noticed something like that happening.. Maybe you have several udev rules?

  3. mihai says:

    I only have one rule. Udev just does this, fires more instances of the script.

    It happened to others too. Some attempted solutions such as writing to a text file to make only one instance survive and do the rsync but it doesn’t work perfectly.

    I’m running Ubuntu 9.04 BTW.

  4. ruben says:

    Also running on Ubuntu 9.04. I did not notice anything like that happening, but I did not check processes either. I’m not able to check this now, as I’m not at home for a couple of days.

    If this is udev running the script more than once, this may be a bug in udev. Maybe some sort of check in the beginning of the script you can check:
    “ps -e | grep usb_backup”, if not empty, then exit.

    Or the solution you pointed out, using some sort of lock-file should work. creating a temp file in /tmp using “touch /tmp/usb_backup_lock” and then delete it after the backup. Otherwise if file already exists, exit.

    I hope this helps you.

  5. mihai says:

    Yes, this is what I’m using, a lock file. But two scripts still get fired sometimes. I think they get fired two fast for the first to finish writing the file.

  6. ruben says:

    I got the chance to check it out. No extra processes running here, sorry.

    It might be interesting to file a bug report about this on launchpad.

  7. whoami says:

    Hi, should udev work on ubuntu 9.04? I can’t get it working. The udev rule doesn’t run the script and in /dev/ no folder is created.

  8. ruben says:

    I’m afraid I can’t help you with that. It seems that your description in your udev-rule doesn’t match your drive.

    You should check out the link provided to write your own udev rule to match your drive.

  9. adario says:

    Hello

    I need to do the same, but with ANY usb device that is connected to the computer (automatically). I don’t know how to get in one variable the mount point of the lastest usb drive pluged, which I think is what I need in order to use the code you posted here.

    Any suggestions?

  10. john says:

    Hello,
    I just stumbled across this post after hours of searching for a solution to exactly the problem it describes! This site should be higher in the google search results ;-)
    A couple of things I’ve had to change:
    1) Since Ubuntu no longer uses gnome-panel, line 4 in alt-notify-send should be pids=`pgrep -u $user compiz`. That seems to have done the trick for me.
    2) I’ve had to increase the timeout value passed to alt-notify-send from 0 to about 10. When set to 0, a confirmation box appeared instead of the notification.
    Thanks!

Comments are closed.