Linux 脚本以特定用户运行 systemctl --user 命令

Linux 脚本以特定用户运行 systemctl --user 命令

我正在创建一个 bash 脚本,尝试将一个程序安装为用户服务,但无法systemctl --user在脚本中运行命令。

这就是我所拥有的:

#!/bin/bash

(...)

useradd -M -g user -d "$3" user 

(...)

[I create the unit file and move it to ~/.config/systemd/user/]


runuser -l user -c "systemctl --user list-units"

su user << 'EOF'

export XDG_RUNTIME_DIR=/run/user/$(id -u user)
export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u user)/bus

systemctl --user daemon-reload

EOF

exit 0

因此,runuser 和此处的文档都会导致错误。

runuser 输出:

无法连接到总线:没有该文件或目录

此处的文档输出:

无法连接到总线:连接被拒绝

我一直在寻找解决方案,但尚未找到针对此特定情况的任何具体方法。

有谁遇到过类似的事情吗?

答案1

回答我自己的问题感觉很奇怪,但我通过执行以下操作设法找到了解决方案:

(...)
mkdir -p "/home/user/.config/systemd/user/multi-user.target.wants/"
chown user:user -R "/home/user/.config/"

loginctl enable-linger user

su user << 'EOF'

export XDG_RUNTIME_DIR=/run/user/$(id -u user)
export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u user)/bus

systemctl --user daemon-reload
systemctl --user enable my-service.service
systemctl --user start my-service.service

EOF
(...)

启用 linger 足以进行 daemon-reload,但在那之后,启用会失败,因为文件夹/home/user/.config/systemd/user/multi-user.target.wants/尚不存在。

奇怪的是,即使启用了 linger,并且我可以看到/lib/systemd/systemd --user该用户正在运行的进程,但是当我执行su user并登录到它的 shell 时,我仍然无法运行,systemctl --user因为它输出:

无法连接到总线:没有此文件或目录只有在该 su 会话内再次设置环境变量后,我才能systemctl --user再次运行命令。

答案2

通常,此错误意味着 D-Bus 会话总线套接字不存在,或者它存在但是一个“过时”的套接字,没有进程再监听它。对于 systemctl,这还意味着私有的“直接到 systemd 的通道”套接字也不存在(因为 systemctl 会自动将其用作后备)。

总之,这意味着用户的systemd --user服务经理根本没跑,因此此时“daemon-reload”是没有意义的——一开始就没有加载任何内容。

一般而言,surunuser并非用于启动用户服务管理器;它们不会通过 pam_systemd 注册完整的“登录会话”。您只能使用它们来访问已运行的用户服务管理器。

(但即使它正在运行,在安装新单元后使用“daemon-reload”也很少有用;它只需要让 systemd 注意到自启动以来已经加载的现有单元的更改。)

您可能应该安装服务单元,/etc/systemd/user以便所有用户都可以自动使用它,而无需您的 shell 脚本。

答案3

Systemd 248引入了一个-M选项,使您能够更轻松地连接到其他用户的守护进程。

此外,正如@u1686_grawity 提到的,您可能希望安装此类全局单元文件/etc/systemd/user。如果您想默认启用这些单元(据我所知,这就是您想要的),您也可以为所有用户这样做。因此在这种情况下,您可以这样做:

sudo cp your-unit.service /etc/systemd/user/
# I don't think `multi-user.target` exists for user daemons
# You can verify this with `systemctl --user list-unit-files -t target`
# You should use `default.target` instead
sudo systemctl --global enable your-unit.service


for USER in user0 user1 user2; do
  # these two may not be necessary
  sudo systemctl -M "$USER@" --user daemon-reload
  sudo systemctl -M "$USER@" --user enable your-unit.service

  sudo systemctl -M "$USER@" --user start your-unit.service
done

相关内容