Ole*_*olf 14 linux headless dbus systemd
我需要帮助在无头 Linux 系统上启动通过会话(不是系统)D-Bus 进行通信的服务。关键是没有人会登录无头系统。
到目前为止,我已经能够在三个不同的终端中代表未登录的用户(“其他用户”)启动 D-Bus 守护程序并测试 D-Bus 通信:
在第一个终端中,我为“otheruser”启动了一个 D-Bus 守护进程:
$ sudo -u otheruser dbus-daemon --session --print-address 1
unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48
Run Code Online (Sandbox Code Playgroud)
在第二个终端中,我使用上述 DBUS_SESSION_BUS_ADDRESS 响应启动 D-Bus 服务器应用程序:
$ sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" /usr/bin/my-dbus-service
Run Code Online (Sandbox Code Playgroud)
然后,在第三个终端中,我可以测试连接:
$ sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" gdbus introspect --session --dest com.mycompany.myappname --object-path /com/mycompany/interface
Run Code Online (Sandbox Code Playgroud)
但是,我想通过 systemd 启动 D-Bus 服务器应用程序以及一些客户端 D-Bus 服务。如何通过 systemd 启动 D-Bus 会话,以便将其 DBUS_SESSION_BUS_ADDRESS 环境变量传播到“otheruser”的 D-Bus 服务器和客户端服务?
一种可能的解决方案可能是将 dbus-daemon 的输出通过管道传输到“somefile”,然后在启动 D-Bus 服务器和客户端之前设置 DBUS_SESSION_BUS_ADDRESS=$(cat somefile)。这对我来说似乎有点太尴尬了;特别是因为我知道系统D-Bus 连接的 systemd 服务文件中的“Busname”指令有一些神奇之处。如何为“其他用户”正确启动 systemd 服务,以便这些 systemd 服务可以与会话 D-Bus 接口进行通信?
Kei*_*hel 21
您需要做几件事才能完成这项工作。
my-dbus-client.service文件属于Type=dbus或依赖于该dbus.socket单元,以确保它们分配 dbus 会话总线套接字并启动 dbus 会话服务(如果尚未启动)。首先,要让给定用户的 Systemd 服务在引导时启动而无需登录,您需要启用 systemd 用户延迟 - 在配置为用户启用它时,这只需要以 root 身份完成一次:
# loginctl enable-linger otheruser
Run Code Online (Sandbox Code Playgroud)
接下来,如果您使用的是基于 Debian 的系统,对于接下来的两个步骤,您只需安装包 dbus-user-session 包:
# apt-get install dbus-user-session
Run Code Online (Sandbox Code Playgroud)
如果您正在使用其他发行版,想要手动执行此操作,或者只是想了解它是如何工作的,请继续。否则跳过的创建dbus.service和dbus.socket。
使用以下内容创建文件/usr/lib/systemd/user/dbus.socket(注意,在某些发行版中,用户目录可能位于/lib而不是 下/usr/lib):
[Unit]
Description=D-Bus User Message Bus Socket
[Socket]
ListenStream=%t/bus
ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
[Install]
WantedBy=sockets.target
Also=dbus.service
Run Code Online (Sandbox Code Playgroud)
传播DBUS_SESSION_BUS_ADDRESS到所有服务,这是您的主要关注点,由ExecPostStart下面的行解决- 所有后续服务都将具有该设置。
%t被替换为XDG_RUNTIME_DIR-/run由 systemd 创建的临时目录,特定于用户会话,您可以填充文件。如果你想在其他地方创建这个套接字,你没有理由不能。只要确保它在某个地方是暂时的,或者在重新启动/会话拆卸时被清理干净。
我确实在尝试使 dbus unix 套接字成为抽象套接字时遇到了一些问题——由于某种原因,systemd 似乎不喜欢这种形式unix:abstract=或@前缀。
现在创建/usr/lib/systemd/user/dbus.service具有以下内容的文件:
[Unit]
Description=D-Bus User Message Bus
Requires=dbus.socket
[Service]
ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
[Install]
Also=dbus.socket
Run Code Online (Sandbox Code Playgroud)
systemd 在幕后进行了一些魔法,将已经创建的 unix 套接字传递给 dbus-daemon。Systemd 使用来自的信息dbus.socket来创建套接字,并且它的文件描述符在环境变量中设置,该变量LISTEN_FDS被传递到dbus-daemon. 上面列出的特殊选项使 dbus-daemon 使用传入的文件描述符而不是创建新的文件描述符。这允许 dbus 客户端与 dbus-daemon 并行启动,而不必担心套接字不存在。
最后,创建您自己的 systemd 用户服务,确保您将 type 设置为Type=dbus,设置BusName=为将由该服务注册的 dbus 服务名称之一的名称,或者确保Requires=dbus.socket在 Unit 部分中指定。下面是一个例子:
[Unit]
Description=Config Server Startup
[Service]
Type=dbus
BusName=com.example.app.configuree
ExecStart=/opt/example/app/configuration_server
Restart=on-failure
[Install]
WantedBy=default.target
Run Code Online (Sandbox Code Playgroud)
您可以将它们放在以下几个位置之一:- $HOME/.config/systemd/user
-/usr/lib/systemd/user
启用您的服务systemctl --user enable <service name>并重新启动,一切都应该正常工作。
参考:
man loginctl 逗留man pam_systemd XDG_RUNTIME_DIR 信息man systemd.service 对于 Type=dbus、BusName= 和对 dbus.socket 的隐式依赖man sd_listen_fds 有关 LISTEN_FDS 环境变量的信息| 归档时间: |
|
| 查看次数: |
18359 次 |
| 最近记录: |