systemd:mkdir 和 ExecStartPre 的权限问题

Mat*_*att 50 permissions systemd

这个(缩短的)systemd 服务文件有问题:

[Unit]
Description=control FOO daemon
After=syslog.target network.target

[Service]
Type=forking
User=FOOd
Group=FOO
ExecStartPre=/bin/mkdir -p /var/run/FOOd/
ExecStartPre=/bin/chown -R FOOd:FOO /var/run/FOOd/
ExecStart=/usr/local/bin/FOOd -P /var/run/FOOd/FOOd.pid
PIDFile=/var/run/FOOd/FOOd.pid

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

FOOd为用户名,FOO为组名,我的 daemon 已经存在/usr/local/bin/FOOd

我需要/var/run/FOOd//usr/local/bin/FOOd通过# systemctl start FOOd.service. 这失败了,因为 mkdir 由于权限无法创建目录:

...
Jun 03 16:18:49 PC0515546 mkdir[2469]: /bin/mkdir: cannot create directory /var/run/FOOd/: permission denied
Jun 03 16:18:49 PC0515546 systemd[1]: FOOd.service: control  process exited, code=exited status=1
...
Run Code Online (Sandbox Code Playgroud)

为什么 mkdir 在 ExecStartPre 失败,我该如何解决?(不,我不能对 mkdir 使用 sudo ......)

小智 73

你需要添加

PermissionsStartOnly=true
Run Code Online (Sandbox Code Playgroud)

[Service]。您的用户FOOd当然无权在/var/run. 引用手册页:

接受一个布尔参数。如果为 true,则与 User= 和类似选项配置的权限相关的执行选项(有关更多信息,请参阅 systemd.exec(5))仅适用于以 ExecStart= 启动的进程,而不适用于其他各种 ExecStartPre= 、ExecStartPost=、ExecReload=、ExecStop= 和 ExecStopPost= 命令。如果为 false,则该设置以相同的方式应用于所有配置的命令。默认为假。

  • 此选项使 `ExecReload=` 中的命令以 root 权限运行。这可能不是您想要的。 (2认同)
  • `PermissionsStartOnly` 已弃用。参考:https://github.com/NixOS/nixpkgs/issues/53852 现在怎么做? (2认同)
  • @adrelanos 现在,在 `ExecStartPre=` 后立即添加一个 `+`。例如`ExecStartPre=+/bin/mkdir test` (2认同)

Wie*_*and 30

这不是解释或修复权限问题的答案,但我认为您应该只使用 systemds RuntimeDirectory 选项。引用手册页

RuntimeDirectory=, RuntimeDirectoryMode=
       Takes a list of directory names. If set, one or more directories by
       the specified names will be created below /run (for system
       services) or below $XDG_RUNTIME_DIR (for user services) when the
       unit is started, and removed when the unit is stopped. The
       directories will have the access mode specified in
       RuntimeDirectoryMode=, and will be owned by the user and group
       specified in User= and Group=. Use this to manage one or more
       runtime directories of the unit and bind their lifetime to the
       daemon runtime. The specified directory names must be relative, and
       may not include a "/", i.e. must refer to simple directories to
       create or remove. This is particularly useful for unprivileged
       daemons that cannot create runtime directories in /run due to lack
       of privileges, and to make sure the runtime directory is cleaned up
       automatically after use. For runtime directories that require more
       complex or different configuration or lifetime guarantees, please
       consider using tmpfiles.d(5).
Run Code Online (Sandbox Code Playgroud)

所以你所要做的就是将你的服务文件更改为:

[Unit]
Description=control FOO daemon
After=syslog.target network.target

[Service]
Type=forking
User=FOOd
Group=FOO
RuntimeDirectory=FOOd
RuntimeDirectoryMode=$some-mode
ExecStart=/usr/local/bin/FOOd -P /run/FOOd/FOOd.pid
PIDFile=/run/FOOd/FOOd.pid

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)


小智 12

+在要以完全权限运行的命令之前添加。

例如:

ExecStartPre=+/bin/mkdir test
Run Code Online (Sandbox Code Playgroud)

请参阅https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=上的“特殊可执行前缀”部分