systemd service: permission denied
I have a new systemd service that fails to start with a "permission denied" error. I bought a Thinkpad L480. Unfortunately, there seems to be an issue with the kernel not detecting the touchpad. This is addressed here can be solved by
sudo sh -c 'echo -n "elantech" > /sys/bus/serio/devices/serio1/protocol'
As I do not want to do this on every single startup, I made a systemd service, which does not work as expected.
My touchpad_enabler.service is
[Unit]
Description=FooBar
[Service]
Type=oneshot
ExecStart=/usr/local/bin/enable_touchpad.sh
[Install]
WantedBy=default.target
The script file is simply
#!/bin/bash
echo -n "elantech" > /sys/bus/serio/devices/serio1/protocol
But I also tried it with the sh -c
version. I adjusted the permissions via
sudo chmod 744 /usr/local/bin/enable_touchpad.sh
sudo chmod 644 /etc/systemd/system/touchpad_enabler.service
so both files are owned by root. I then enabled it via
systemctl enable enable_touchpad.sh
When I manually start the service via systemctl start touchpad_enabler.service
, it works totally fine and the touchpad works as it should. However, on startup , the service fails and is listet as 'failed' in systemctl list-units
.
The output of journalctl -b -u touchpad_enabler.service
is:
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
It looks like the problem is the permission to write to the file itself. But manually starting the service works fine and to my understanding systemd should execute the command as root anyway, right?
From reading man systemctl.service
I got the idea to prepend '+' to the filepath so that it read
ExecStart=+/usr/local/bin/enable_touchpad.sh
With no effect.
I do not really understand where this protocol
file comes from. It looks like it gets created by the kernel on startup? So I also experimented with the After=
parameter, but systemd should start the services after the kernel is fully loaded, right? The file is also owned by root so I would not expect any problems there.
I hope someone can help me. Thanks in advance.
Solution 1:
It seems like you have the service and script files a little confused. The contents of the files seem like they should work though.
Systemd needs a service file. Put this file here
/etc/systemd/system/touchpad_enabler.service
With the contents:
[Unit]
Description=FooBar
[Service]
Type=oneshot
ExecStart=/usr/local/bin/enable_touchpad.sh
[Install]
WantedBy=default.target
Then your script here (I changed the name to make the separation between service file and script file clearer. Also /usr/local/bin
is a better place because it's generally meant for local scripts/programs)
/usr/local/bin/enable_touchpad.sh
And it will have the contents (unchanged):
#!/bin/bash
echo -n "elantech" > /sys/bus/serio/devices/serio1/protocol
Make sure the permissions on the script and the service file are correct. They should be owned by root and the script should be executable.
sudo chmod 744 /usr/local/bin/enable_touchpad.sh
sudo chmod 644 /etc/systemd/system/touchpad_enabler.service
Then you enable the systemd service.
sudo systemctl enable touchpad_enabler.service
This enables the service so it will run at boot. It can also be run manually with:
sudo systemctl start touchpad_enabler.service
or you can directly run the script, bypassing the systemd service:
sudo /usr/local/bin/enable_touchpad.sh
I can't really speak to the bug or when the protocol file is created, but the service should work.
EDIT:
You can add the After=
parameter to the [Unit]
section of the service to make sure it runs after a specific target, like default.target
or multi-user.target
. By default, every service has a dependency on sysinit.target
, so I'm not sure how much that would matter in your case.
If you look here, https://stackoverflow.com/questions/27511139/how-to-make-sysfs-changes-persistent-in-centos-7-systemd, there are other ways to accomplish what you want without a custom service. Maybe you can try a udev rule.