34

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

  • FYI: I'm using Debian 8 – Matt Jun 4 '15 at 8:50
  • Can you please translate the error message to English? – Thushi Jun 4 '15 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 '15 at 9:34
55

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.

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

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

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=

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.