Previously, I wrote about backing up files to Dropbox with rsync. I automated the process with cron the ancient UNIX “time-based job scheduler”. While OS X ships with cron, newer versions of the operating system favor launchd. launchd is much more than a cron replacement, on OS X it also fills the rolls of init, init.d/rc.d scripts, and inetd. It can be told to watch for changes in directories or drives to be mounted and run processes when those events happen.
launchd is powerful, but it’s use of XML config files makes it overkill for simple tasks that can be handled by cron. However, if the task isn’t so simple…
The rsync/cron setup I described works well if the files you want to backup are always available, but what if they aren’t? I have a external drive attached to my Mac that I use for storing files I don’t want cluttering up my internal SDD drive. Because this is an external drive, it’s only attached to my computer when I’m sitting at my desk. The cron job:
will fail (and generate a warning email).
It’s easy enough to wrap the rsync in a script that tests if the drive is mounted:
1 2 3 4 5 6 7 8 9
and run that from cron.
However, lets try a different approach using launchd. I’m not particularly worried about these backups, if I was I’d use a full blown system like Time Machine. I do want some backups, however. What I’m going to do is watch for a drive to be mounted and run the backup when one is.
launchd is configured using XML plist like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
After the initial boilerplate,
<dict> contains the settings in the
form of key/value pairs. The first being the Label, the name of the
launchd job, which used in logs and display by
launchctl list. As
you can see, Label uses
reverse domain name notation. Since
you’re not going to distribute this it really doesn’t matter what you
call it. If you don’t have a domain, you should be safe with
ProgramArguments is the command we are going to run. It’s an
array because you can pass multiple arguments:
1 2 3 4 5
Finally, we need to define the conditions under which the script is
run. For this backup we want
StartOnMount, which we set to
StartOnMount causes the program to run anytime a drive is mounted.
man launchd.plist will give you a long list of other keys. The
details are beyond that post, but for example:
would run every 60 seconds.
To use this script, install it (you’ll need “sudo”) as:
Now whenever you mount a drive, your script will be run. Pretty cool, eh?
If you wish to disabled the script, run:
This strategy is a bit odd, it would make more sense to backup the disk before it’s ejected (which you can’t actually detect) as that’s when it’s most likely to have changes. Also, the if the drive is already mounted then another drive is connected, the backup will run. Despite this, this isn’t a contrived example, I actually use it. And it points the way to other interesting uses, drive based location detection anyone?