systemd 服务:权限被拒绝

Blo*_*och 11 linux services permissions systemd

我有一个新的 systemd 服务,它无法以“权限被拒绝”错误启动。我买了一台 Thinkpad L480。不幸的是,内核似乎存在未检测到触摸板的问题。这是解决here可以解决

sudo sh -c 'echo -n "elantech" > /sys/bus/serio/devices/serio1/protocol'
Run Code Online (Sandbox Code Playgroud)

因为我不想在每次启动时都这样做,所以我做了一个 systemd 服务,但它没有按预期工作。

我的 touchpad_enabler.service 是

[Unit]
Description=FooBar

[Service]
Type=oneshot
ExecStart=/usr/local/bin/enable_touchpad.sh

[Install]
WantedBy=default.target
Run Code Online (Sandbox Code Playgroud)

脚本文件很简单

#!/bin/bash

echo -n "elantech" > /sys/bus/serio/devices/serio1/protocol
Run Code Online (Sandbox Code Playgroud)

但我也用sh -c版本试过了。我通过调整权限

sudo chmod 744 /usr/local/bin/enable_touchpad.sh
sudo chmod 644 /etc/systemd/system/touchpad_enabler.service
Run Code Online (Sandbox Code Playgroud)

所以这两个文件都归root所有。然后我通过

systemctl enable enable_touchpad.sh
Run Code Online (Sandbox Code Playgroud)

当我通过 手动启动服务时systemctl start touchpad_enabler.service,它完全正常工作,触摸板也能正常工作。但是,在启动时,服务失败并在 中被列为“失败” systemctl list-units

的输出journalctl -b -u touchpad_enabler.service是:

systemd[1]: Starting Solves bug that Thinkpad L480 Touchpad is not correctly detected...
enable_touchpad.sh[516]: sh: /sys/bus/serio/devices/serio1/protocol: permission denied
systemd[1]: touchpad_enabler.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: touchpad_enabler.service: Failed with result 'exit-code'.
systemd[1]: Failed to start FooBar
Run Code Online (Sandbox Code Playgroud)

看起来问题是写入文件本身的权限。但是手动启动服务工作正常,据我所知,systemd 无论如何都应该以 root 身份执行命令,对吗?

从阅读中man systemctl.service我得到了在文件路径前面加上“+”的想法,以便它读取

ExecStart=+/usr/local/bin/enable_touchpad.sh
Run Code Online (Sandbox Code Playgroud)

没有效果。

我真的不明白这个protocol文件来自哪里。看起来它是由内核在启动时创建的?所以我也试验了这个After=参数,但是systemd应该是内核满载后才启动服务吧?该文件也归 root 所有,所以我不希望那里有任何问题。

我希望有一个人可以帮助我。提前致谢。

nit*_*ram 5

似乎您对服务和脚本文件有些困惑。文件的内容似乎应该可以工作。

Systemd 需要一个服务文件。把这个文件放在这里

/etc/systemd/system/touchpad_enabler.service
Run Code Online (Sandbox Code Playgroud)

内容如下:

[Unit]
Description=FooBar

[Service]
Type=oneshot
ExecStart=/usr/local/bin/enable_touchpad.sh

[Install]
WantedBy=default.target
Run Code Online (Sandbox Code Playgroud)

然后你的脚本在这里(我更改了名称以使服务文件和脚本文件之间的分离更清晰。也是/usr/local/bin一个更好的地方,因为它通常用于本地脚本/程序)

/usr/local/bin/enable_touchpad.sh
Run Code Online (Sandbox Code Playgroud)

它将具有内容(不变):

#!/bin/bash
echo -n "elantech" > /sys/bus/serio/devices/serio1/protocol
Run Code Online (Sandbox Code Playgroud)

确保脚本和服务文件的权限正确。它们应该由 root 拥有并且脚本应该是可执行的。

sudo chmod 744 /usr/local/bin/enable_touchpad.sh
sudo chmod 644 /etc/systemd/system/touchpad_enabler.service
Run Code Online (Sandbox Code Playgroud)

然后启用 systemd 服务。

sudo systemctl enable touchpad_enabler.service
Run Code Online (Sandbox Code Playgroud)

这将启用该服务,使其在启动时运行。它也可以手动运行:

sudo systemctl start touchpad_enabler.service
Run Code Online (Sandbox Code Playgroud)

或者你可以直接运行脚本,绕过 systemd 服务:

sudo /usr/local/bin/enable_touchpad.sh
Run Code Online (Sandbox Code Playgroud)

我无法真正谈论错误或创建协议文件的时间,但该服务应该可以工作。

编辑:
您可以将After=参数添加到[Unit]服务的部分以确保它在特定目标之后运行,例如default.targetmulti-user.target。默认情况下,每个服务都依赖于sysinit.target,因此我不确定这对您的情况有多大影响。

如果你看这里,/sf/ask/1925779761/,还有其他方法可以在没有定制服务的情况下完成你想要的. 也许你可以试试 udev 规则。