sd-loginでログインセッションのStateの監視をする
loginctl
やsystemd/sd-login.h
のAPIを用いてログインセッションなどの現在状態が取得できる。加えて、monitor APIが用意されていて、各種変更の検知/通知の受け取りが可能となっている。
sd_login_monitor_new
で監視オブジェクトを生成poll
でイベントを待ち受ける
印象としてはかなり荒い単位で通知がくる。poll
が返ったら自分が監視対象としたい値を取得し、現在どんな値か、変化があったかを自分で
判別する必要がある。
環境
準備
systemdの開発用パッケージが必要なのでインストールする。
$ sudo yum install systemd-devel
ビルドするときはsystemdをリンクする。
$ g++ -Wall main.cpp -lsystemd
ログインStateの監視
sd_login_monitor_new
の第一引数で監視する値を絞れる。ここではユーザーのログイン状態を監視するのに"uid"
を渡している。
この値は他の関数群と関係していそうで、"uid"
ならsd_uid_get_***
系の関数で取れる値を監視できるんじゃなかろうかと思う(が確証なし)。
#include <systemd/sd-login.h> #include <poll.h> #include <unistd.h> #include <cstdlib> #include <iostream> int main() { // create monitor instance sd_login_monitor *mon = 0; const int ret = sd_login_monitor_new("uid", &mon); if (ret >= 0 && mon) { // set up pollfd struct pollfd pfd = {}; pfd.fd = sd_login_monitor_get_fd(mon); pfd.events = sd_login_monitor_get_events(mon); const uid_t uid = getuid(); for (;;) { // reset the wakeup state sd_login_monitor_flush(mon); // wait infinitely const int r = poll(&pfd, (nfds_t)1, -1); if (r > 0 && pfd.revents != 0) { std::cout << "poll: " << r << ", revents: " << pfd.revents << std::endl; // uid state char *state = 0; const int ret = sd_uid_get_state(uid, &state); if (ret >= 0 && state) { std::cout << "State is: " << state << std::endl; free(state); } } } sd_login_monitor_unref(mon); } }
プログラムを実行して、「ユーザースイッチ -> ユーザー切り替えを行わずに再度ログイン」したところ、以下のように出力された。監視対象の状態が多いので、(イメージよりも)不意に呼ばれたりする。
$ ./a.out poll: 1, revents: 1 State is: online poll: 1, revents: 1 State is: online poll: 1, revents: 1 State is: online poll: 1, revents: 1 State is: active poll: 1, revents: 1 State is: active
タイムアウト時間の設定値
ドキュメントを見るとsd_login_monitor_get_timeout
で返る値から計算するようになっているけど、これはイマイチ動作確認できず。試した環境だと計算上-1になって、結局無限に待つことになった。