色々試行錯誤したのでメモ。
dbus crate を使う。
開発中の libspecinfra で、systemd 配下の service の状態を取得できるようにするための provider を書こうと思い、色々調べたりコード書いて試したりした。
まずは目的に合う crates がないか crates.io で検索。ざっと以下のようなものが見つかる。
systemd crate は libsystemd の Rust インターフェースで、sd-daemon、sd-id128、sd-journal、sd-login に対応している。が sd-bus は まだ実装が不完全 なようなので、目的には合わなさそう、と判断。
systemd-dbus crate は2年半以上更新がなく、rust 1.19.0 でコンパイルが通らなかったので断念。
他に systemd を直接扱える、目的に適いそうな crate が見当たらなかったので、D-Bus が扱える crate ってことで、dbus crate と dbus-bytestream create を試してみることにした。
dbus crate にしても dbus-bytestream crate にしても、ざっとドキュメントやコードを読んだ感じ、D-Bus でどういった形でメッセージのやりとりがなされているのかを理解しないと、使うのは無理だなこれは、と思ったので、まずは dbus-send コマンドで必要な情報が得られるかどうかトライしてみた。
libspecinfra でやりたいことのひとつは、サービスが動いているかどうかを調べること。dbus-send では以下のような形で実行すれば、この情報が得られることがわかった。
まずはユニット名(ssh.service)からオブジェクトパス(/org/freedesktop/systemd1/unit/ssh_2eservice)を取得。
$ dbus-send --system \
--dest=org.freedesktop.systemd1 \
--type=method_call \
--print-reply \
/org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager.GetUnit \
string:ssh.service
method return time=1507693363.257785 sender=:1.10 -> destination=:1.220 serial=3078 reply_serial=2
object path "/org/freedesktop/systemd1/unit/ssh_2eservice"
--dest=org.freedesktop.systemd1
で接続先のバス名を指定。/org/freedesktop/systemd1
が操作対象のオブジェクトパス、org.freedesktop.systemd1.Manager
がインターフェースで、それに続く GetUnit
が呼び出すメソッド、string:ssh.service
がメソッドに渡す引数、という形式になっている。
このオブジェクトパスの ActiveState プロパティを取得。
$ dbus-send --system \
--dest=org.freedesktop.systemd1 \
--type=method_call \
--print-reply \
/org/freedesktop/systemd1/unit/ssh_2eservice \
org.freedesktop.DBus.Properties.Get \
string:org.freedesktop.systemd1.Unit \
string:ActiveState
method return time=1507693392.955268 sender=:1.10 -> destination=:1.221 serial=3079 reply_serial=2
variant string "active"
これでサービスの状態を得ることができた。
どのようなメソッドやプロパティがあるかは The D-Bus API of systemd/PID 1 に載っている。
dbus crate を使って以下のようなコードを書けば良い。
試したコードは Cargo.toml 等も含めて GitHub に置いてある。
dbus crate は サンプルコード もあるし、ドキュメント もあるので、ドキュメントがほとんどない dbus-bytestream crate と比べると、比較的扱いやすいように思える(といっても、ドキュメント読めばすべてわかる、というわけではなく、コードも読んで色々試行錯誤したけど)。
dbus-bytestream も同時に試したけど、取得した ActiveState の情報をデコードする方法がよくわからないまま、dbus crate の方が動いたので、途中で断念した。なので、GitHub 上にある dbus-bytestream を使ったコードはエラーで動かない。