1

I have been struggling for two days to write something that should be simple: a one-shot systemd service that runs just before the computer shuts down and interacts with a mounted filesystem.

(I've mounted the "~/.mozilla" directory in RAM, and I'm trying to save the changes to my hard drive when the computer shuts down.)

I have tried everything under the sun, and nothing works. Here's my best attempt:

[Unit]
Description=Save Firefox and Thunderbird to the hard drive
DefaultDependencies=no
BindsTo=home-andy-.mozilla.mount
After=home-andy-.mozilla.mount
Before=halt.target poweroff.target reboot.target shutdown.target
Conflicts=umount.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/mozilla-save
TimeoutStartSec=infinity

[Install]
WantedBy=halt.target poweroff.target reboot.target shutdown.target

Here's an explanation of why I've added each of my declarations:

[Unit]
Before=halt.target poweroff.target reboot.target shutdown.target

[Install]
WantedBy=halt.target poweroff.target reboot.target shutdown.target

I added this because my script should run when the computer shuts down. I'm not clear whether any one of these would have implied all of the others, or whether they must all be specified. I'm also not clear on whether the "Before" declaration is strictly necessary, since the "[Install]" section already appears to contain that information.

I've also tried variations of this involving "umount.target"

[Unit]
DefaultDependencies=no

[Service]
TimeoutStartSec=infinity

This is supposed to prevent my potentially long-running process from being killed after a few moments by the aggressive shutdown process.

[Unit]
BindsTo=home-andy-.mozilla.mount
After=home-andy-.mozilla.mount
Conflicts=umount.target

I added this because my process depends on a tmpfs filesystem (mounted at "/home/andy/.mozilla"). That filesystem must be mounted when my process starts and must remain mounted until my process is complete. The shutdown process runs a lot of actions in parallel, including the unmounting of filesystems.

For the sake of others: If you declare a mount point in your "/etc/fstab" file, then it will automatically be available to systemd. Here's how to list the various mount points you might need:

systemctl list-units --type=mount

And that's where I am currently. I have spent literally days on this and I am utterly exhausted. I'm sick and tired of systemd and need help. Anything, even a crumb, would be appreciated.

For the record: Installing the script at "/lib/systemd/system-shutdown/mozilla-save" won't work, because the filesystem is already remounted as read-only at that point.

And this won't work either:

Unit]
Description=Save Firefox and Thunderbird to the hard drive
BindsTo=home-andy-.mozilla.mount home.mount
After=home-andy-.mozilla.mount home.mount
Conflicts=umount.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=/usr/local/sbin/mozilla-stop

[Install]
WantedBy=multi-user.target

...although I don't know why.

1 Answer 1

4

Here's a service that DOES work:

[Unit]
Description=Save Firefox and Thunderbird to the hard drive
RequiresMountsFor=/home /home/andy/.mozilla

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=/usr/local/sbin/mozilla-save
TimeoutSec=infinity

[Install]
WantedBy=multi-user.target

To check for race conditions, I added a 300 second sleep to the beginning of the backup script. The shutdown process was delayed for 300 seconds, and then the backup script ran successfully.

This is a working configuration--at last. I hope this solution will be helpful to others.

Here's my guess as to why this works:

I believe that

[Service]
Type=oneshot
ExecStart=/bin/true

[Install]
WantedBy=multi-user.target

...causes "/bin/true" to be executed at the very beginning of the multi-user run level.

This, on its own, does nothing. But the declaration:

[Service]
RemainAfterExit=true

...causes systemd to consider "/bin/true" to be still running at the end of the multi-user run level (i.e. just before shutdown dismantles everything).

At that point, systemd invokes ExecStop to kill the "/bin/true" process:

ExecStop=/usr/local/sbin/mozilla-save

...which runs my backup script instead.

Now, ordinarily, systemd would kill a long-running ExecStop process, so this is necessary to give the backup script enough time to finish:

TimeoutSec=infinity

And systemd aggressive shuts everything else down, in parallel, so this is necessary to keep the filesystems mounted and writable during the backup process:

[Unit]
RequiresMountsFor=/home /home/andy/.mozilla

Here's a concise and readable description of systemd and unit files on DigitalOcean. And here's the full technical documentation in case you need it.

Please be aware: If you make changes to the "[Install]" section of your service, you must inform systemctl of the changes. This is how I did it:

systemctl disable mozilla-save
systemctl enable mozilla-save

...where "/lib/systemd/system/mozilla-save.service" is the name of my service.

These commands will result in symlinks being added or removed. If you don't call these commands, your testing is moot.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .