ACPI: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
 
(не показано 12 промежуточных версий этого же участника)
Строка 1: Строка 1:
[[Ктаегория:Linux]]
+
[[Категория:Linux]]
[[Ктаегория:ACPI]]
+
[[Категория:ACPI]]
  +
=Зачем это=
  +
При выключении сервера с виртуальными машинами очень хочется понимать что ВМки "поймали" сигнал от хоста и завершили работу максимально корректно (ну в пределах тех минут на сколько зватит УПСа)<BR>
  +
За настройку выключения отвечает либвирт и в современных системах по-умолчанию это "виртуальная кнопка питания", событие от которой обрабатывается внутри ВМ
  +
<BR>
  +
<BR>
  +
[[https://noname.com.ua/mediawiki/index.php/Linux_ups_nut_snmp|Подробнее о настройке выключения при работе от UPS]] - дополнительная информация
  +
<BR>
  +
<BR>
 
=События ACPI в Linux=
 
=События ACPI в Linux=
   
Строка 8: Строка 16:
   
 
* В современых системах события ACPI обрабатывает <code>systemd-logind</code>
 
* В современых системах события ACPI обрабатывает <code>systemd-logind</code>
* Более сложнве сценарии можно реализовать через  <code>acpid service</code>
+
* Более сложные сценарии можно реализовать через  <code>acpid service</code>
  +
* В этой доке только совсем базовый пример - то что было нужно мне на сейчас
   
  +
=События <code>ACPI</code> обрабатываемые <code>systemd-logind</code>=
  +
  +
Часть событий обрабатывает сервис <code>systemd-logind</code>
  +
<BR>
  +
Какие именно события обрабатываются и как описано в файле <code>/etc/systemd/logind.conf</code>
  +
<BR>
  +
(сокращенный пример)
 
<PRE>
 
<PRE>
ACPI events handled by systemd-logind
 
 
In recent years, systemd has become the standard init system on Linux. After some controversies, practically all major distribution adopted it, except some that explicitly exist for the sake of avoiding it, such as Devuan, a Debian derivative. One of the major critics that is moved against Systemd is that it doesn’t respect the Unix philosophy of “doing one thing, and doing it well”. In time, indeed, Systemd was extended to perform other tasks than simply handling the system init, such as managing user logins: this is done via the systemd-logind service.
 
 
The systemd-logind service, among the other things, is responsible for creating and managing sessions IDs, providing polkit access to system-level operations such as shutdown or suspend, and handling ACPI events such as the behavior of the power button. What actions should be performed when such events occur, can be configured by editing the /etc/systemd/logind.conf file. Let’s take a look at its content:
 
 
[Login]
 
[Login]
 
[...]
 
[...]
Строка 26: Строка 37:
 
#HandleRebootKey=reboot
 
#HandleRebootKey=reboot
 
[...]
 
[...]
  +
</PRE>
We truncated the output of the file for convenience, in order to show the most relevant lines. By default all the lines in the file are commented, and are reported with the default values. The reported directives control how systemd-logind handles the power, suspend, hibernate keys and the lid switch on machines when this event can occur, such as notebooks. Some of the values which can be assigned to the directives are:
 
  +
Значения по-умолчанию закоментированы, и нужны только для того что бы понимать, например не смотря на комментарий: <code>#HandlePowerKey=poweroff</code> означает что при нажатии кнопки питания (или в случае виртуальной машины - получении соответвующего события) произойдет выключение
 
  +
<BR>
ignore
 
  +
Возможные значения:
poweroff
 
  +
* ignore
reboot
 
  +
* poweroff
suspend
 
  +
* reboot
hibernate
 
  +
* suspend
hybrid-sleep
 
  +
* hibernate
The syntax to be used in the file is pretty self-explanatory: with the HandlePowerKey=poweroff line, for example, we instruct systemd-logind to poweroff the machine when the power button is pressed, and to suspend the system to ram when the suspend key is pressed (HandleSuspendKey=suspend). In the same way, we can make so that a specific event is ignored by using ignore as the value of the corresponding line, as by default is done for HandleLidSwitchDocked.
 
  +
* hybrid-sleep
 
Some of the actions which can be handled by systemd-logind, in the most used desktop environments, are managed by graphical power managers. To avoid conflicts or redundant actions, such as the system being suspended two times when the suspend button is pressed, such applications inhibits systemd-logind handling of said events.
 
   
  +
Синтаксис файла очевиден - <code>событие</code>=<code>действие из списка</code>
 
If we need to manage acpi events not covered by systemd-logind, with more complex or custom actions, we need to change strategy, install and run the acpid daemon. Let’s see how to proceed.
 
If we need to manage acpi events not covered by systemd-logind, with more complex or custom actions, we need to change strategy, install and run the acpid daemon. Let’s see how to proceed.
   
  +
<BR>
Installing the acpid daemon
 
  +
Однако если ни одно из действий не подходит, то нужно использовать <code>ACPID</code>
   
Installing the acpid daemon is very easy, since the related package is included in the repositories of the major Linux distributions. To install the package on Fedora, for example, we run the following command:
 
 
$ sudo dnf install acpid
 
To install the same package on Archlinux, instead, we run:
 
 
$ sudo pacman -Sy acpid
 
Finally, on Debian and Debian-based distributions, to install the acpid package we use the apt wrapper:
 
   
  +
=Сервис <code>acpid</code>=
  +
Установка:
  +
<PRE>
 
$ sudo apt install acpid
 
$ sudo apt install acpid
After the installation is complete, we need to start the acpid service and enable it at boot, so it is started automatically each time we start our system. We can perform both actions with one single command:
 
 
 
$ sudo systemctl enable --now acpid
 
$ sudo systemctl enable --now acpid
  +
</PRE>
Handling ACPI events
 
   
  +
(тут немного забегаю вперед, 2 rules loaded пока не созданы еще)
With the acpid service running, when we need to configure an action to be performed on a specific event, the very first thing we need to do is to check how said event is recognized by the system (the same event can be recognized in
 
  +
<PRE>
different ways on different machines: this depends on how ACPI is implemented). The acpi_listen utility is designed for this specific purpose and is installed as part of the acpid package, so it is ready to use.
 
  +
systemctl status acpid
  +
● acpid.service - ACPI event daemon
  +
Loaded: loaded (/lib/systemd/system/acpid.service; disabled; vendor preset: enabled)
  +
Active: active (running) since Thu 2024-05-02 19:30:12 UTC; 3 days ago
  +
TriggeredBy: ● acpid.socket
  +
● acpid.path
  +
Docs: man:acpid(8)
  +
Main PID: 499 (acpid)
  +
Tasks: 1 (limit: 44705)
  +
Memory: 284.0K
  +
CGroup: /system.slice/acpid.service
  +
└─499 /usr/sbin/acpid --logevents
   
  +
May 02 19:30:12 mgmt-1 systemd[1]: Started ACPI event daemon.
To identify an event we need to launch the utility in a terminal emulator, trigger the event, and see how it is read by ACPI. Let’s see a practical example. Suppose we want to perform an action on a laptop when the Fn key is pressed together with the F3 key. First, we invoke acpi_listen:
 
  +
May 02 19:30:12 mgmt-1 acpid[499]: starting up with netlink and the input layer
$ acpi_listen
 
  +
May 02 19:30:12 mgmt-1 acpid[499]: 2 rules loaded
We should obtain a blinking cursor; this means that system is waiting and ready to display how events are read. Now we can press the key combination. Immediately, the information are printed onscreen. In this case, on the machine I am using, I obtain the following result:
 
  +
May 02 19:30:12 mgmt-1 acpid[499]: waiting for events: event logging is on
  +
</PRE>
   
  +
=Обработака событий <code>ACPI</code>=
hotkey ATK0100:00 00000050 00000001
 
  +
==Мониторинг событий==
In the output, we can see four columns: the first one represents the device class, the second one is the kernel name for the “device”, as it appears under the /sys/bus/acpi/devices directory. The third column reports the event code. Finally, the fourth column value assume a different meaning depending on the type of event. Once we know an event code, we can associate an action to it.
 
  +
* Для тесторивания можно воспользоваться утилитой <code> acpi_listen</code> которая покажет какие события происходят
  +
* Для виртуальной машины (а это именно мой случай) можно использовать команду <code>virsh shutdown guest1 --mode acpi</code>, естественно сначала отключив обработку этого события в <code>sustemd</code>
  +
(В logind изменить HandlePowerKey на ignore)
  +
<BR>
  +
Например
  +
<PRE>
  +
button/power PBTN 00000080 00000000
  +
button/power LNXPWRBN:00 00000080 00000004
  +
</PRE>
  +
Тут 4 столбца
  +
* device class
  +
* kernel name for the device (по этому имени можно смотреть в /sys/bus/acpi/devices)
  +
Например
  +
<PRE>
  +
cat /sys/bus/acpi/devices/LNXPWRBN\:00/input/input0/name
  +
Power Button
  +
</PRE>
  +
* код события
  +
* последнее значение контекстно-зависимо,и имеет различное значение в зависимости от события
   
  +
==Создание обработчика событий==
Associating an event with an action
 
  +
В случае Убунты
 
  +
* <code>/etc/acpi/events/010_power_button</code> - обработчик на определенное событие
Associating an ACPI event with an action it’s quite easy. It basically involves two files: the first is the one parsed by the acpid service (by default it must be created inside the /etc/acpi/events directory) and is where we specify the code of the event to be handled and the path of the script which contains the commands that should be executed; the second is the script itself. Where the scripts are placed in the fileystem varies depending on the distribution. In Fedora, for example, we have the following directories by default:
 
  +
<PRE>
 
  +
event=button/power
├── actions
 
  +
action=/etc/acpi/acpi_power_button.sh %e
│ └── power.sh
 
  +
</PRE>
└── events
 
  +
* <code>/etc/acpi/events/999_all</code> - на все
├── powerconf
 
  +
<PRE>
└── videoconf
 
As we already said, the /etc/acpi/events directory contains the files which handles the events. The /etc/acpi/actions directory, instead, contains the scripts associated with the events. By default, as you can see, the powerconf and power.sh scripts are installed, and they manage the handling of the power button.
 
 
On Debian, files are arranged differently. The /etc/acpi/actions directory doesn’t exist:
 
 
/etc/acpi
 
├── events
 
│ └── powerbtn-acpi-support
 
└── powerbtn-acpi-support.sh
 
On Archlinux things are handled differently: there is only one file by default, in which all events are handled: /etc/acpi/events/anything:
 
 
# Pass all events to our one handler script
 
 
event=.*
 
event=.*
 
action=/etc/acpi/handler.sh %e
 
action=/etc/acpi/handler.sh %e
  +
</PRE>
What makes the file handle all events is the .* regular expression. The code of the events are than passed as argument to the /etc/acpi/handler.sh file (the %e string will be replaced by the event code). In the script, the actions to be executed are selected depending on the latter, in a case statement.
 
  +
<BR>
  +
%e будет заменен кодом события)
  +
</BR>
  +
Далее добавить собственно скрипты-обработчики
  +
<BR>
  +
<code>/etc/acpi/acpi_power_button.sh</code>
  +
<PRE>
  +
#!/bin/bash
   
  +
echo "[$(date)][$@][$(id)] /sbin/shutdown -h now Power button pressed" | logger -t "acpi_power_button"
How files are arranged, however, doesn’t matter that much. It doesn’t change how things work. Let’s manage the event we talked about previously: since an hibernate key doesn’t exist on the machine I am using, I will make so that when the Fn+f3key combination is pressed, the system is put into hibernation. As a first thing let’s create the event file, we will call it hibernateconf; it will contain only two lines:
 
  +
echo "[$(date)][$@][$(id)] /sbin/shutdown -h now Power button pressed" > /etc/acpi_powerloss
   
  +
/sbin/shutdown -h now "Power button pressed"
event=hotkey ATK0100:00 00000050
 
  +
</PRE>
action=/etc/acpi/actions/hibernate.sh
 
In the first line we specify the event code as value of event: in this case we simply used the literal code we discovered by using the acpi_listen utility. In the second line we specify the path of the script which should be executed: /etc/acpi/actions/hibernate.sh.
 
 
One important thing to remember is that if using SELinux (on Fedora it is active by default), we must make sure the “event” file has the appropriate context associated to it, otherwise the event will not be handled. To know what context should be applied to the file, we can take a look at the existing files in the /etc/acpi/events directory as reference. All we have to do is to run ls with the -Z option:
 
$ ls -lZ /etc/acpi/events
 
-rw-r--r--. 1 root root system_u:object_r:etc_t:s0 168 Oct 5 21:27 powerconf
 
-rw-r--r--. 1 root root system_u:object_r:etc_t:s0 236 Oct 5 21:27 videoconf
 
As we can see, on Fedora, the two existing files in the /etc/acpi/events directory have the system_u:object_r:etc_t context. To apply the same context to our hibernateconf file, we can use them as reference with the chcon command:
 
 
$ sudo chcon --reference /etc/acpi/events/powerconf /etc/acpi/events/hibernateconf
 
The script invoked by the event file will contain the following lines:
 
   
  +
Результат можно смотреть в логах
  +
<code>zcat /var/log/syslog*gz | grep 'acpi_power_button'</code>
  +
<PRE>
  +
May 2 14:48:48 mgmt-1 acpid: executing action "/etc/acpi/acpi_power_button.sh button/power PBTN 00000080 00000000"
  +
May 2 14:48:48 mgmt-1 acpi_power_button: [Thu May 2 14:48:48 UTC 2024][button/power PBTN 00000080 00000000][uid=0(root) gid=0(root) groups=0(root)] /sbin/shutdown -h now Power button pressed
  +
</PRE>
  +
<BR>
  +
<code>/etc/acpi/handler.sh</code>
  +
<PRE>
 
#!/bin/bash
 
#!/bin/bash
systemctl hibernate
 
In the script we simply use systemctl to hibernate the system. All that remains to do is to make the script executable:
 
   
  +
echo "[$(date)] $@" | logger -t "ACPID event handler"
$ sudo chmod +x /etc/acpi/actions/hibernate.sh
 
  +
</PRE>
For our new configurations to become effective, we need to restart the acpid daemon:
 
 
$ sudo systemctl restart acpid.service
 
When we press Fn+F3, the system should now be hibernated.
 
 
Conclusions
 
 
In this article we saw how ACPI events can be handled on Linux. We saw how basic events like the press of the power button, the suspend key and the closing of a laptop lid are managed by systemd-logind and can be configured via the /etc/systemd/logind.conf file. We also saw how to handle custom events by installing the acpid daemon on some of the most used Linux distributions.
 
 
Related Linux Tutorials:
 
 
How to increase the security of systemd services
 
How to export repositories with the git-daemon
 
Understanding UEFI and BIOS in Relation to Linux…
 
How to manage power profiles over D-Bus with…
 
How to Set NVIDIA Power Limit on Ubuntu
 
Advanced Logging and Auditing on Linux
 
An Introduction to Linux Automation, Tools and Techniques
 
Bash Scripting: Read input from command line
 
How to optimize laptop battery life with TLP on Linux
 
How to keep files and directories synchronized…
 
   
  +
<PRE>
  +
zcat /var/log/syslog*gz | grep 'ACPID event handler'
  +
May 2 14:48:48 mgmt-1 ACPID event handler: [Thu May 2 14:48:48 UTC 2024] button/power PBTN 00000080 00000000
 
</PRE>
 
</PRE>

Текущая версия на 16:18, 6 мая 2024

Зачем это

При выключении сервера с виртуальными машинами очень хочется понимать что ВМки "поймали" сигнал от хоста и завершили работу максимально корректно (ну в пределах тех минут на сколько зватит УПСа)
За настройку выключения отвечает либвирт и в современных системах по-умолчанию это "виртуальная кнопка питания", событие от которой обрабатывается внутри ВМ

[о настройке выключения при работе от UPS] - дополнительная информация

События ACPI в Linux

ACPI(Advanced Configuration and Power Interface) это стандарт (с 1996?) для управления питанием (но не только?)

  • В современых системах события ACPI обрабатывает systemd-logind
  • Более сложные сценарии можно реализовать через  acpid service
  • В этой доке только совсем базовый пример - то что было нужно мне на сейчас

События ACPI обрабатываемые systemd-logind

Часть событий обрабатывает сервис systemd-logind
Какие именно события обрабатываются и как описано в файле /etc/systemd/logind.conf
(сокращенный пример)

[Login]
[...]
#HandlePowerKey=poweroff
#HandleSuspendKey=suspend
#HandleHibernateKey=hibernate
#HandleLidSwitch=suspend
#HandleLidSwitchExternalPower=suspend
#HandleLidSwitchDocked=ignore
#HandleRebootKey=reboot
[...]

Значения по-умолчанию закоментированы, и нужны только для того что бы понимать, например не смотря на комментарий: #HandlePowerKey=poweroff означает что при нажатии кнопки питания (или в случае виртуальной машины - получении соответвующего события) произойдет выключение
Возможные значения:

  • ignore
  • poweroff
  • reboot
  • suspend
  • hibernate
  • hybrid-sleep

Синтаксис файла очевиден - событие=действие из списка If we need to manage acpi events not covered by systemd-logind, with more complex or custom actions, we need to change strategy, install and run the acpid daemon. Let’s see how to proceed.


Однако если ни одно из действий не подходит, то нужно использовать ACPID


Сервис acpid

Установка:

$ sudo apt install acpid
$ sudo systemctl enable --now acpid

(тут немного забегаю вперед, 2 rules loaded пока не созданы еще)

systemctl status acpid
● acpid.service - ACPI event daemon
     Loaded: loaded (/lib/systemd/system/acpid.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2024-05-02 19:30:12 UTC; 3 days ago
TriggeredBy: ● acpid.socket
             ● acpid.path
       Docs: man:acpid(8)
   Main PID: 499 (acpid)
      Tasks: 1 (limit: 44705)
     Memory: 284.0K
     CGroup: /system.slice/acpid.service
             └─499 /usr/sbin/acpid --logevents

May 02 19:30:12 mgmt-1 systemd[1]: Started ACPI event daemon.
May 02 19:30:12 mgmt-1 acpid[499]: starting up with netlink and the input layer
May 02 19:30:12 mgmt-1 acpid[499]: 2 rules loaded
May 02 19:30:12 mgmt-1 acpid[499]: waiting for events: event logging is on

Обработака событий ACPI

Мониторинг событий

  • Для тесторивания можно воспользоваться утилитой acpi_listen которая покажет какие события происходят
  • Для виртуальной машины (а это именно мой случай) можно использовать команду virsh shutdown guest1 --mode acpi, естественно сначала отключив обработку этого события в sustemd

(В logind изменить HandlePowerKey на ignore)
Например

button/power PBTN 00000080 00000000
button/power LNXPWRBN:00 00000080 00000004

Тут 4 столбца

  • device class
  • kernel name for the device (по этому имени можно смотреть в /sys/bus/acpi/devices)

Например

cat  /sys/bus/acpi/devices/LNXPWRBN\:00/input/input0/name
Power Button
  • код события
  • последнее значение контекстно-зависимо,и имеет различное значение в зависимости от события

Создание обработчика событий

В случае Убунты

  • /etc/acpi/events/010_power_button - обработчик на определенное событие
event=button/power
action=/etc/acpi/acpi_power_button.sh %e
  • /etc/acpi/events/999_all - на все
event=.*
action=/etc/acpi/handler.sh %e


%e будет заменен кодом события)
Далее добавить собственно скрипты-обработчики
/etc/acpi/acpi_power_button.sh

#!/bin/bash

echo "[$(date)][$@][$(id)] /sbin/shutdown -h now Power button pressed" | logger -t "acpi_power_button"
echo "[$(date)][$@][$(id)] /sbin/shutdown -h now Power button pressed" > /etc/acpi_powerloss

/sbin/shutdown -h now "Power button pressed"

Результат можно смотреть в логах zcat /var/log/syslog*gz | grep 'acpi_power_button'

May  2 14:48:48 mgmt-1 acpid: executing action "/etc/acpi/acpi_power_button.sh button/power PBTN 00000080 00000000"
May  2 14:48:48 mgmt-1 acpi_power_button: [Thu May  2 14:48:48 UTC 2024][button/power PBTN 00000080 00000000][uid=0(root) gid=0(root) groups=0(root)] /sbin/shutdown -h now Power button pressed


/etc/acpi/handler.sh

#!/bin/bash

echo "[$(date)] $@" | logger -t "ACPID event handler"
zcat /var/log/syslog*gz | grep 'ACPID event handler'
May  2 14:48:48 mgmt-1 ACPID event handler: [Thu May  2 14:48:48 UTC 2024] button/power PBTN 00000080 00000000