Skip to content

Instantly share code, notes, and snippets.

@jiphex
Last active January 27, 2023 12:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jiphex/4c56a120bc2f1564a114e97e4157b9e8 to your computer and use it in GitHub Desktop.
Save jiphex/4c56a120bc2f1564a114e97e4157b9e8 to your computer and use it in GitHub Desktop.

Running a script/service when a filesystem is mounted

I recently discovered how to do this for a JASMIN thing, and figured it may be useful.

Scenario

I would like this script/binary to be run automatically whenever a certain filesystem is mounted.

Use cases:

  • You want a quotacheck to be run to create the aquota.user file every time a tmpfs is mounted
  • You want to do something to a block device before it is mounted (e.g mkfs, fsck, unlock with some encryption key)
  • ...?

How would you have done this previously

I'm not sure how this would be done without Systemd, perhaps with a very frequent periodic Cron to test if the filesystem is mounted and then execute a thing?

How do you do this in systemd?

  1. Configure your mount as normal in fstab, trust that systemd will turn it into an implicit .mount unit via systemd-fstab-generator (it just happens with all mounts)
  2. Add the script wherever, probably /usr/local/sbin or bin.
  3. Add a systemd unit like do-test-mount.service, see the attached file - this should be installed in /etc/systemd/system
  4. Run systemctl enable do-test-mount.service to have the service linked in the right place (no need to "start" it, because this will be done when the filesystem is mounted)

What's this about escaping?

When you refer to a path/mountpoint in a systemd unit, you have to "escape" it, because you can't have a service named e.g "/var/testmount.service". In that case, you want to use systemd-escape:

  1. To escape a "path" (like a mountpoint), run systemd-escape -p /var/testmount, and you will get var-testmount- this is what you should use in the systemd service unit
  2. To escape something else, drop the -p (that isn't needed here).

Note that when you refer to var-testmount.mount in the systemd service shown here, the path will always match the mountpoint, it's non-negotiable.

What if it fails?

It is possible (albeit optional) to have the filesystem unmounted if the service fails, this relationship is referred to in systemd terms as the mount being "bound by" the the service.

Due to the way systemd ordering works, it is not possible to configure the "bound by" relationship from the mount unit to the service inside the service unit (as you can with the RequiredBy relationship), but you can easily configure it in the .mount unit by creating a file at /etc/systemd/system/var-testmount.mount.d/override.conf using the contents of override.conf in this gist.

[Unit]
# The name below is significant, it must match the escaped mountpoint path.
# This is here because I am assuming that you want the script to run *after*
# the filesystem is mounted (for example to set a quota on it). It is also
# possible to set this as Before=, or to not specify ordering if it is not
# important.
#
# For example, if the script was going to unlock an encrypted block device,
# you may want it to run before the mount, but to do something like install
# a quota, you would want it afterwards. If it is just logging the fact that
# the filesystem mount was attempted, then the ordering is insignificant.
After=var-testmount.mount
[Service]
# Whatever you want here, in this case we are using the mount name in the parameter
ExecStart=/usr/bin/touch /var/testmount/hello.txt
[Install]
# This must match the escaped mountpoint path again
RequiredBy=var-testmount.mount
# ... (other mounts, root etc)
# The mount we care about, in this case it is a tmpfs but it could be a "proper" disk mount
none /var/testmount tmpfs defaults,size=1G
# Configures the mount unit to be "bound by" the service unit
# This means that if the service fails before/after the mount
# is mounted, then the mount will be reverted/unmounted.
[Unit]
BindsTo=do-thing-on-touch.service
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment