The Problem
Recently, Arch Linux (my distribution of choice) switch to the systemd system initialization and service manager, and the change broke one specific piece of functionality on a few of my systems. Namely, running a script when the power button is pressed, and not doing anything until my script has finished running.
On both of my systems affected by this, the script would play an audio file and then possible do something else.
After a few days/weeks of trying to write a systemd service file that would do what I wanted to do, and swearing up a storm of frustration, I finally found a solution.
What is Systemd?
Systemd is a daemon startup manager for Linux that starts and stops daemons in parallel. For each daemon on a system, there is a systemd .service file that describes which daemons depend upon which other daemons.
It is the relationship between daemons that, to me, is what makes systemd so powerful. Instead of starting one daemon after another over a period of time, systemd will use the .service files to determine which daemons can be started at the same time. In theory this should reduce startup time, but I haven't seen much improvement yet.
Similarly, systemd shuts down daemons in parallel. And it was this parallel shutdown that was causing me problems. I couldn't have a shutdown script make a network request because the network shutdown so fast, and if the audio subsystem shutdown before my file played, I would hear nothing.
My Solution
DON'T LET SYSTEMD HANDLE THE POWERBUTTON PRESS! LET ACPI HANDLE IT. Sorry for yelling, but I wish someone had yelled that at me a few weeks ago.
Here is what I did (as root):
- enabled the community repo for pacman
- install acpi and acpid:
pacman -S acpi acpid
- skip step 3
- enable the acpid service:
systemctl enable acpid.service
- start the acpid service:
systemctl start acpid.service
- edit /etc/systemd/logind.conf and replace
#HandlePowerKey=poweroff
withHandlePowerKey=ignore
Goody gum drops; the system is now configured to let acpi handle the powerbutton press. Now I need to configure acpi to run my script.
To do this, I edited the file /etc/acpi/handler.sh which is the handler for acpi events. The line logger 'PowerButton pressed'
was replaced with logger 'PowerButton pressed' && PATH_TO_MY_SHUTDOWN_SCRIPT
In my case, PATH_TO_MY_SHUTDOWN_SCRIPT is /usr/local/sbin/myshutdown
and the file looks like:
#!/bin/sh gst-launch-0.10 playbin uri=file:///storage/opt/shutdown.ogg volume=0.7 shutdown -h now &
Now, when I press the power button, my script runs and it plays my shutdown file and then initiates the systemd parallel shutdown. BOOYAH!
What a relief that was. Now I can focus on my next systemd quest: running a script after the network manager has connected to the network.
From https://wiki.archlinux.org/index.php/Power_management#Hooks_in_.2Fusr.2Flib.2Fsystemd.2Fsystem-sleep you should be able to run custom scripts by placing them in /usr/lib/systemd/system-sleep
(logind should give argument 1 as post or pre for post or pre suspend), but for some reason I have not been able to make this trick work.