Configure acpid From BusyBox in a Custom initrd
I have a setup with a Linux Kernel and a custom initrd, hence, no full Linux distribution. The initrd is meant to be as minimal as it can be. As a consequence, even basic things such as power-off on power-button pressed must be configured manually. There is no init system available – instead, I have to provide the init system.
The initrd contains utilities from busybox. In this blog post, I show you how to configure acpid
from busybox in a minimal initrd to power-off the system when the power-button-pressed event was recognized via ACPI.
A quick background information: busybox provides certain tools:
BusyBox combines tiny versions of many common UNIX utilities into a single
busybox’s README
small executable. It provides minimalist replacements for most of the
utilities you usually find in bzip2, coreutils, dhcp, diffutils, e2fsprogs,
file, findutils, gawk, grep, inetutils, less, modutils, net-tools, procps,
sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim.
It also contains acpid
, an ACPI daemon. The ACPI daemon is used to define a policy in userland on how certain ACPI events, such as the power button or if the lid got closed, are handled. In order for this to work, the Linux kernel needs the ACPI_BUTTON
kernel module. It’s description says:
This driver handles events on the power, sleep, and lid buttons.
<linux>/drivers/acpi/Kconfig
A daemon reads events from input devices or via netlink and
performs user-defined actions such as shutting down the system.
This is necessary for software-controlled poweroff.
Note that if you use the ACPI_TINY_POWER_BUTTON
kernel module instead of ACPI_BUTTON
, the mechanism to inform the userland over ACPI events does not exist.
It took me a few hours to figure out how all parts interact with each other and to configure acpid
properly. In the end it is relatively easy, but there is not much good documentation – the code is mostly the documentation. Here is what I’ve found:
For better understanding, at first, I show the output of acpid -h
:
BusyBox v1.35.0 () multi-call binary.
Usage: acpid [-df] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]
Listen to ACPI events and spawn specific helpers on event arrival
-d Log to stderr, not log file (implies -f)
-f Run in foreground
-c DIR Config directory [/etc/acpi]
-e FILE /proc event file [/proc/acpi/event]
-l FILE Log file [/var/log/acpid.log]
-p FILE Pid file [/var/run/acpid.pid]
-a FILE Action file [/etc/acpid.conf]
-M FILE Map file [/etc/acpi.map]
Accept and ignore compatibility options -g -m -s -S -
acpid
needs /etc/acpi
as it’s working directory. When it receives an event from /dev/input/*
, acpid
executes the file in /etc/acpi/<action>
. All supported events are either defined via the optional map file that is by default in /etc/acpi.map
or via the built-in configuration given as:
static const struct acpi_event f_evt_tab[] = { { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" }, { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" }, { "EV_SW", 0x05, "SW_LID", 0x00, 1, "button/lid LID0 00000080" }, };
Snippet taken from the source code. The source code can be found on GitHub.
This file maps the KEY_POWER
event to the PWRF
action. I’m not sure what the difference is between PWRF and PWRB. In my setup, the power button is recognized as PWRF
action.
After acpid
mapped the event to an action, it looks into the optional action file that is by default in /etc/acpi/
or uses its built-in action configuration:
static const struct acpi_action f_act_tab[] = { { "PWRF", "PWRF/00000080" }, { "LID0", "LID/00000080" }, };
As a consequence, a power button event will instruct acpid
to execute the file /etc/acpi/PWRF/00000080
. The file 00000080
can either be an executable or link to one or contain a shell script with a shebang.
To test and prototype I suggest running acpid
in foreground with logging enabled. This requires that you have terminal access to the initrd. Simply run acpid -d
. If you run acpid
in the background (just invoke acpid
), make sure that /var/log/acpid.log
exists and is writeable.
As /etc/acpi/PWRF/00000080
has large what-the-fuck potential, we can also configure acpid
to use /etc/acpi/power
. For this, we create a /etc/acpid.conf
with the following content: PWRF power
– that’s it! The action files lists pairs of action name to executable. The key and the value are separated by spaces. Each line defines one configuration.
Now, acpid
will execute /etc/acpi/power
if the power button is pressed, which is mapped to the PWRF
action.
For completeness, I show you the content of my /etc/acpi/power
script:
#!/bin/sh # As this runs in the background, we need to write the message directly to the terminal device. echo "acpid found the power-off event. Executing \"poweroff -f\" now" > /dev/ttyS0 poweroff -f
I hope I could help you to understand the usage of acpid
from busybox. Please note that acpid
from the https://sourceforge.net/projects/acpid2/ is configured different in an incompatible way.
0 Comments