54

I've got a problem with this (shortened) systemd service file:

[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

Let FOOd be the user name and FOO the group name, which already exist for my daemon /usr/local/bin/FOOd.

I need to create the directory /var/run/FOOd/ before starting the daemon process /usr/local/bin/FOOd via # systemctl start FOOd.service. This fails, because mkdir can't create the directory due to permissions:

...
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
...

Why does mkdir fail at ExecStartPre and how can I fix it? (And no, I can't use sudo for mkdir...)

4
  • FYI: I'm using Debian 8
    – Matt
    Jun 4, 2015 at 8:50
  • Can you please translate the error message to English?
    – Thushi
    Jun 4, 2015 at 8:51
  • 1
    ... Jun 03 16:18:49 PC0515546 mkdir[2469]: /bin/mkdir: the directory /var/run/FOOd/ can't be created: no permission Jun 03 16:18:49 PC0515546 systemd[1]: FOOd.service: control process exited, code=exited status=1 ...
    – Matt
    Jun 4, 2015 at 9:34
  • 1
    Another tip: use ExecStartPre=/usr/bin/install -o FOOd -g FOO -d /var/run/FOOd could do the same work in one command.
    – ttimasdf
    Feb 11, 2020 at 10:14

3 Answers 3

78

You need to add

PermissionsStartOnly=true

to [Service]. Your user FOOd is of course not authorized to create a directory in /var/run. To cite the man page:

Takes a boolean argument. If true, the permission-related execution options, as configured with User= and similar options (see systemd.exec(5) for more information), are only applied to the process started with ExecStart=, and not to the various other ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop=, and ExecStopPost= commands. If false, the setting is applied to all configured commands the same way. Defaults to false.

6
  • 1
    Wonderful, exactly what I was looking for.
    – robert
    May 6, 2016 at 22:34
  • 2
    This option makes commands in ExecReload= run in root privilege. This may not be what you want.
    – Rockallite
    Mar 16, 2017 at 8:47
  • @Rockallite that's what the documentation I cited literally says, yes.
    – embik
    Mar 18, 2017 at 12:42
  • 3
    PermissionsStartOnly was deprecated. Reference: github.com/NixOS/nixpkgs/issues/53852 How to do that now?
    – adrelanos
    Apr 7, 2019 at 6:11
  • 5
    @adrelanos Now, add a + immediately after ExecStartPre=. For example ExecStartPre=+/bin/mkdir test May 29, 2019 at 21:07
30

This is not an answer that explains or fixes the permission problem, but I think you should just use systemds RuntimeDirectory option. Quoting the man page:

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).

So all you would have to do is change your service file to:

[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
1
  • Thank you thank you. Sadly missing from the OpenVPN Ubuntu package!!
    – BaseZen
    Apr 10, 2018 at 1:46
16

Add + before the command that you want to run with full privileges.

For example:

ExecStartPre=+/bin/mkdir test

See the section on "Special executable prefixes" at https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=

1
  • That works only with newest systemd, not with Centos 7 systemd for instance, see @embik answer
    – aryndin
    May 20, 2020 at 12:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .