Protecting My Home Server's Power Button with molly-guard and acpid
A while ago I took one of the old desktop computers in the house and turned it into a basic home server. Right now its main functions are printing and file storage, and most of the time it can be turned off. To make this easy, I’ve kept the default behavior for the power button to shut down the system.
But just shutting down a server like this is risky. What if someone is still logged in and working on something? That work would be lost if the server was shut down unexpectedly.
Guarding Shutdown Commands with molly-guard
The molly-guard package is available in Debian (and derivative distributions such as Ubuntu). It offers some protection against accidental shutdown by replacing the
poweroff, and similar commands with “guarded” versions. The “guards” are a series of scripts located in
/etc/molly-guard/run.d/, and if one of them fails (exits with a nonzero exit code), the operation is canceled.
By default, there are only two basic scripts:
10-print-messagescript displays a customizable message.
30-query-hostnamescript tries to detect an SSH session and prompts for the hostname as confirmation.
Note that the numeric prefixes control execution order. The scripts are run in order of filename, and if one fails the rest are not run. I wanted my guards to run after the message is displayed but before the hostname prompt, so I named my scripts starting with
First, I wrote a script to check for active terminal sessions:
#!/bin/sh ACTIVE_TERMINALS=$(who | wc -l) CURRENT_TERMINALS=$(who -m | wc -l) # 1 if run from a terminal, 0 otherwise if [ $ACTIVE_TERMINALS -gt $CURRENT_TERMINALS ]; then echo 'W: there are other active terminal sessions.' >&2 exit 1 fi
Then, I wrote a script to check for active print jobs:
#!/bin/sh # lpstat -u without a user argument lists jobs from all users # (although this does not appear to be documented) ACTIVE_PRINT_JOBS=$(lpstat -u | wc -l) if [ $ACTIVE_PRINT_JOBS -gt 0 ]; then echo 'W: there are active print jobs.' >&2 exit 1 fi
I placed these into
/etc/molly-guard/run.d/, making sure to set execute permissions so they would actually run.
Guarding the Power Button with acpid
There’s a problem, though: While
molly-guard guards the shutdown commands, it doesn’t do anything with the power button, which was my original goal. This is because the power button is handled (at least on this system) by
systemd-logind, which is a separate service.
Fixing this involves two steps:
systemd-logindfrom handling the power button
- Set up acpid to handle the power button by running the (guarded)
First, to stop
systemd-logind from handling the power button, I edited
/etc/systemd/logind.conf. It had some lines that look like this:
... #HandlePowerKey=poweroff #HandleSuspendKey=suspend #HandleHibernateKey=hibernate ...
These commented-out lines show the default behavior. As you might expect, the default behavior for the power button (or “power key” as it’s called here) is to power off the computer.
I uncommented the line and changed the behavior to “ignore”:
Then, to set up
acpid, I first installed the package:
apt install --no-install-recommends acpid
I included the
--no-install-recommends option to prevent the
acpi-support-base package from being installed. That package includes some default configuration for handling the power button, but the problem with that configuration is that it will defer to
systemd-logind if it detects that it’s running. It’s the exact opposite of what I’m trying to do: I specifically want to bypass
systemd-logind and have
acpid handle it instead.
acpid isn’t configured to do anything. Fortunately, the example configuration does exactly what I need. I simply copied two files from
cp /usr/share/doc/acpid/examples/powerbtn /etc/acpi/events/powerbtn cp /usr/share/doc/acpid/examples/powerbtn.sh /etc/acpi/powerbtn.sh chmod a+x /etc/acpid/powerbtn.sh # Make the handler script executable
After this, the power button is now guarded.
There are a few other things I haven’t been able to guard yet:
- File transfers using Samba (I’m not sure how to check open connections to Samba)
- ZFS scrubs and resilvers (The
zpool statuscommand doesn’t offer a machine-readable output option, and it seems I’m not the only one struggling with this)