LinuxでACPIイベントを処理する方法
ACPIは、Advanced Configuration and Power Interfaceの略です。標準として1996年に最初に導入され、APM(Advanced Power Management)の後継となりました。主な機能として、BIOSで処理されていた電源管理をオペレーティングシステムレベルで扱う能力をもたらしました。LinuxにおけるいくつかのACPIイベントは、デフォルトではsystemd-logindを介して処理されますが、より複雑な設定はacpidサービスをインストールして実行することで実現できます。
この記事では、systemd-logindの設定方法と、acpidデーモンを介してより具体的なACPIイベントを処理する方法について説明します。
このチュートリアルでは、次のことを学びます。
- systemd-logindによって処理されるいくつかのACPIイベント
- acpidサービスのインストールと起動方法
- ACPIイベントの処理方法
systemd-logindによって処理されるACPIイベント
近年、systemdはLinuxの標準initシステムとなりました。一部の論争の後、事実上すべての主要なディストリビューションがこれを採用しましたが、Devuanのようにそれを避けるために明示的に存在するものは除きます。Systemdに対する主要な批判の一つは、「1つのことを行い、それをうまく行う」というUnixの哲学を尊重していないという点です。実際、Systemdはシステムの初期化を処理するだけでなく、ユーザーログインの管理など他のタスクを実行するように拡張されました:これは systemd-loginサービスを通じて行われます。
systemd-logindサービスは、他の多くのことの中で、セッションIDを作成および管理し、シャットダウンやサスペンドなどのシステムレベルの操作へのpolkitアクセスを提供し、電源ボタンの動作などのACPIイベントを処理します。このようなイベントが発生したときに実行すべきアクションは、/etc/systemd/logind.confファイルを編集することで設定できます。その内容を見てみましょう:
[Login]
[...]
#HandlePowerKey=poweroff
#HandleSuspendKey=suspend
#HandleHibernateKey=hibernate
#HandleLidSwitch=suspend
#HandleLidSwitchExternalPower=suspend
#HandleLidSwitchDocked=ignore
#HandleRebootKey=reboot
[...]
便宜上、最も関連性の高い行を示すために、ファイルの出力を切り詰めました。デフォルトでは、ファイル内のすべての行はコメントアウトされており、デフォルト値で報告されます。報告されたディレクティブは、システムd-logindが、このイベントが発生する可能性のあるマシン(ノートパソコンなど)で、電源、サスペンド、休止キーや蓋スイッチをどのように処理するかを制御します。ディレクティブに割り当て可能な値のいくつかは次の通りです。
- 無視する
- 電源を切る
- 再起動
- 一時停止する
- ハイバーネート
- ハイブリッドスリープ
ファイルで使用される構文は非常に明白です:例えば、HandlePowerKey=poweroff行を使用して、電源ボタンが押されたときにsystemd-logindにマシンをシャットダウンするよう指示し、サスペンドキーが押されたときにシステムをRAMにサスペンドするよう指示します(HandleSuspendKey=suspend)。同様に、特定のイベントを無視させるために、対応する行の値としてignoreを使用することができます。これはデフォルトでHandleLidSwitchDockedに対して行われます。
一般的に使用されるデスクトップ環境では、systemd-logindによって処理されるいくつかのアクションが、グラフィカルな電源管理ツールによって管理されています。サスペンドボタンが押された際にシステムが2回サスペンドされるといった競合や冗長なアクションを避けるため、これらのアプリケーションはsystemd-logindによるこれらのイベントの処理を抑制します。
systemd-logind ではカバーされていない ACPI イベントを、より複雑またはカスタムのアクションで管理する必要がある場合、戦略を変更し、acpid デーモンをインストールして実行する必要があります。次に、どのように進めるか見てみましょう。
acpidデーモンのインストール
acpidデーモンのインストールは非常に簡単です。関連パッケージは主要なLinuxディストリビューションのリポジトリに含まれているためです。たとえば、Fedoraにパッケージをインストールするには、次のコマンドを実行します:
sudo dnf install acpid同じパッケージをArchlinuxにインストールするには、代わりに次のコマンドを実行します:
sudo pacman -Sy acpid最後に、DebianおよびDebianベースのディストリビューションでは、acpidパッケージをインストールするためにaptラッパーを使用します:
sudo apt install acpidインストールが完了したら、acpidサービスを開始し、ブート時に有効にする必要があります。そうすれば、システムを起動するたびに自動的に開始されます。これらの2つの操作を1つのコマンドで実行できます。
sudo systemctl enable --now acpidACPIイベントの処理
acpidサービスが動作している場合、特定のイベントに対して実行するアクションを設定する必要があるとき、最初に行うべきことは、そのイベントがシステムによってどのように認識されているかを確認することです(同じイベントでも、異なるマシンでは異なる方法で認識される場合があります:これはACPIの実装方法に依存します)。acpi_listenユーティリティはこの特定の目的のために設計されており、acpidパッケージの一部としてインストールされるため、すぐに使用可能です。
イベントを特定するには、端末エミュレータでユーティリティを起動し、イベントをトリガーし、それがACPIによってどう読み取られるかを見る必要があります。実際の例を見てみましょう。F3キーと一緒にFnキーが押されたときに、ノートパソコンでアクションを実行したいとしましょう。まず、acpi_listenを呼び出します:
acpi_listen点滅するカーソルを取得する必要があります。これは、システムが待機中であり、イベントがどのように読み取られるかを表示する準備が整っていることを意味します。今、キーの組み合わせを押すことができます。すぐに、情報が画面に表示されます。この場合、私が使用している機械では、次の結果が得られます:
hotkey ATK0100:00 00000050 00000001出力には4つの列が表示されます。最初の列はデバイスクラスを表し、2番目の列はデバイスのためのカーネル名で、これは/sys/bus/acpi/devicesディレクトリの下に表示されます。3番目の列はイベントコードを報告し、最後に4番目の列の値はイベントの種類に応じて異なる意味を持ちます。イベントコードがわかれば、それにアクションを関連付けることができます。
イベントをアクションに関連付けること
ACPIイベントをアクションに関連付けるのは非常に簡単です。基本的には2つのファイルが関与します。1つ目はacpidサービスによって解析されるファイルで(デフォルトでは/etc/acpi/eventsディレクトリの中に作成する必要があります)、ここで処理すべきイベントのコードと実行すべきコマンドを含むスクリプトのパスを指定します。2つ目はスクリプトそのものです。スクリプトがファイルシステムに配置される場所は、ディストリビューションによって異なります。例えばFedoraでは、デフォルトで以下のディレクトリがあります:
├── actions
│ └── power.sh
└── events
├── powerconf
└── videoconf
既に述べたように、/etc/acpi/eventsディレクトリにはイベントを処理するファイルが含まれています。一方、/etc/acpi/actionsディレクトリにはイベントに関連するスクリプトが含まれています。デフォルトでは、powerconfとpower.shスクリプトがインストールされており、これらは電源ボタンの処理を管理します。
Debianでは、ファイルの配置が異なります。/etc/acpi/actionsディレクトリは存在しません。
/etc/acpi
├── events
│ └── powerbtn-acpi-support
└── powerbtn-acpi-support.sh
Archlinuxでは、物事は異なって処理されます。デフォルトでは、すべてのイベントが処理される1つのファイルのみがあります:/etc/acpi/events/anything:
Pass all events to our one handler script
event=.*
action=/etc/acpi/handler.sh %e
ファイルがすべてのイベントを処理する理由は、.*正規表現です。イベントのコードは次に/etc/acpi/handler.shファイルに引数として渡されます(%e文字列はイベントコードに置き換えられます)。スクリプト内では、アクションがケースステートメントに基づいて選択されます。
ファイルの配置はそれほど重要ではありません。それは物事の動作に影響を与えません。以前に話したイベントを管理しましょう:私が使用しているマシンにはハイバーネートキーが存在しないので、Fn+f3キーの組み合わせが押されたときにシステムをハイバーネート状態にするように設定します。まず、イベントファイルを作成しましょう。それをhibernateconfと呼びます。このファイルには2行だけが含まれます。
event=hotkey ATK0100:00 00000050
action=/etc/acpi/actions/hibernate.sh
最初の行では、eventの値としてイベントコードを指定します。この場合、acpi_listenユーティリティを使用して発見したリテラルコードを単純に使用しました。2行目では、実行されるべきスクリプトのパスを指定します:/etc/acpi/actions/hibernate.sh。
重要なことは、SELinuxを使用している場合(Fedoraではデフォルトで有効)、“event”ファイルに適切なコンテキストが関連付けられていることを確認しなければならないということです。そうでないと、イベントは処理されません。ファイルに適用するべきコンテキストを知るためには、/etc/acpi/eventsディレクトリ内の既存のファイルを参照することができます。必要なことは、lsコマンドを-Zオプション付きで実行することだけです。
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ご覧の通り、Fedoraでは、/etc/acpi/eventsディレクトリにある2つの既存ファイルにはsystem_u:object_r:etc_tコンテキストがあります。同じコンテキストを私たちのhibernateconfファイルに適用するために、chconコマンドを使用してそれらを参照することができます:
sudo chcon --reference /etc/acpi/events/powerconf /etc/acpi/events/hibernateconfイベントファイルによって呼び出されるスクリプトには、以下の行が含まれます。
#!/bin/bash
systemctl hibernateスクリプトでは、単に systemctl を使用してシステムをハイバネートします。残るのは、スクリプトを実行可能にすることだけです。
sudo chmod +x /etc/acpi/actions/hibernate.sh新しい設定を有効にするためには、acpidデーモンを再起動する必要があります。
sudo systemctl restart acpid.serviceFn + F3を押すと、システムは休止状態になります。
結論
この記事では、ACPIイベントがLinuxでどのように処理されるかを見てきました。電源ボタンの押下、サスペンドキー、ノートパソコンの蓋を閉じるといった基本的なイベントがsystemd-logindによって管理され、/etc/systemd/logind.confファイルを通じて設定できることを確認しました。また、最も使用されているLinuxディストリビューションのいくつかにacpidデーモンをインストールすることにより、カスタムイベントを処理する方法も見てきました。
