Trigger systemd Unit on Suspend Before Networking Shutdown – How to

networkmanagersuspendsystemd

(On Stock Debian testing aka stretch aka 9, so I have a regular systemd+logind+NetworkManager+GNOME stack)

I have a pair of script that I want to run on startup/shutdown and resume/suspend. This script requires networking to be present when it runs. I have attempt this with the following script:

[Unit]
Description=Yamaha Reciever power
Requires=network-online.target
After=network-online.target
Before=sleep.target
Conflicts=sleep.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/av-up
ExecStop=/usr/local/bin/av-down
RemainAfterExit=yes

[Install]
WantedBy=graphical.target

This works correctly on startup/shutdown, however during suspend it runs after the network has shutdown and therefore fails.

I have determined that the reason for this is how suspend proceeds under systemd:

  1. Suspend is initiated by a program (e.g. systemctl suspend) sending a dbus call to logind.
  2. Logind then sends a PrepareToShutdown dbus signal to anyone listening.
  3. Logind then sends a StartUnit dbus call to systemd to run the suspend.target unit.

NetworkManager listens to PrepareToShutdown, so removes the network at (2), while my unit is triggered when systemd actually starts suspending at (3). NetworkManager keeps an "inhibit" lock with logind to ensure it shuts the network down before (3). (Side note: it seems crazy to have something like systemd control ordering of suspend/resume, only to subvert it with logind making stuff circumvent this)

What is the right way to trigger a program to run on suspend/resume while networking is still running?

Should I use NetworkManager pre-down scripts? If so how do I stop it triggering if the network goes down but I'm not suspending?

Is there a way to hook into the suspend process earlier?

Is there a way to make NetworkManager keep the network up longer?

NB: this is distinct from How to write a Systemd unit that will fire before networking goes down as I am talking about suspend/resume.

Best Answer

Inspired by https://unix.stackexchange.com/a/139664/160746 I upgraded my start/stop scripts to a full blown daemon and made it listen for PrepareToShutdown signal. This is a race against NetworkManager every start/stop, but it seems to work reliably on my system.

I have uploaded my code and systemd unit at https://github.com/davidn/av.

Related Question