One of the most satisfying aspects of running free and open source software is the ability to be able to continually tinker with your setup, limited only by your imagination and ability. The more you do tinker, the smaller the gap between the former and the latter, as each small project inevitably leads you into a deeper understanding of various aspects of your system1 and how you can customize that system to suit your exact requirements.
Over the last couple of days, I have been playing with udev, the kernel device manager, as I was attempting to run a script once a specific USB drive was plugged in. It turns out, as is so often the case, that udev is only part of the picture…
As both my work and personal laptops have relatively small
SSDs, I carry around
on a 1TB external drive. As the drive only contains .flac
files, I wanted to automate the process of
rsync’ing music from my desktop to
the drive and, for the laptops, repopulating the symlinks to
~/Music/ when the drive was plugged in.
My first thought was a rule in /etc/udev/rules.d/,
RUN+=. There are any number of blog posts espousing this approach and,
as I quickly discovered, they are all wrong. The problem with using this key is
that, as the
man page makes clear, it is not designed for long running
This can only be used for very short-running foreground tasks. Running an event process for a long period of time may block all further events for this or a dependent device.
Starting daemons or other long running processes is not appropriate for udev; the forked processes, detached or not, will be unconditionally killed after the event handling has finished.
The problem, as it manifest for me, was the drive would be blocked from
mounting until after the script had run, meaning
rsync or my symlinks would
have no target. There are various “workarounds” on the web for this, including
using two scripts, one to trigger the other2. Even for me, this
seemed like a
The correct way to do this, as I found once I uncovered
on the Arch boards where WonderWoofy and 65kid helpfully pieced it together, is
SYSTEMD_WANTS. As it is described in the manual:
THE UDEV DATABASE
The settings of device units may either be configured via unit files, or directly from the udev database (which is recommended). The following udev properties are understood by systemd:
Adds dependencies of type Wants from this unit to all listed units. This may be used to activate arbitrary units, when a specific device becomes available. Note that this and the other tags are not taken into account unless the device is tagged with the "systemd" string in the udev database, because otherwise the device is not exposed as systemd unit.
So, I edited /etc/udev/rules.d/90-usb-music.rules to
RUN+= key, using a systemd service file instead, like so3:
And then wrote the corresponding service file to have systemd hand off to the bash script:
1 2 3 4 5 6 7 8 9 10
As I mentioned in my post on my
simple unmounting script,
I use a naming convention for all my USB drives. In this case, my music is stored on Apollo, and
it is auto-mounted with
udiskie. In the
service file, systemd uses a hyphen instead of a forward slash, so the correct
Then it is just a matter of enabling the service with
systemctl enable upmusic and,
whenever Apollo is plugged in to either my desktop of laptop, the appropriate
script will run and either update the files on Apollo or the symlinks on one of the
- This shouldn’t be taken as any sort of claim of expertise or deep understanding of this, or any other, part of my system. See below.
- Which is why you should never trust anything written by bloggers…
- The definitive reference for udev rules remains Writing udev rules
Creative Commons image on Flickr by Jacob Garcia.