7

I try to create a DEB file that installs a systemd user service with a postinst script that enables this service after installation. This is my postinst script:

#!/bin/bash

set -e
systemctl --user enable myservice.service

When I install the DEB (dpkg --install mypackage.deb) it runs the postinst script and returns with the following error message:

Failed to connect to bus: No such file or directory

I can also not use a system service and the package will not be published so I don't care about any packaging standards. Is there anything I can do to make this work?

If it's not possible I'll add it to my init script so it will be enabled after each boot, but I'd like to avoid that if possible.

1
  • Hey, systemctl --global enable myservice.service should be the command that run in priviledged mode (the installation itself) should install the service to all users, through the D-Bus. I am trying to do exactly that and I am very close, yet I face an issue with the D-Bus connection.
    – Rolice
    Mar 23, 2021 at 10:22

2 Answers 2

8

What you're trying to do doesn't work. Installing a systemd service for the user executing the installation is not very useful since that user would always be root. So instead you should probably follow the convention of installing the service as a system-wide service for all users. Here is the standard approach for doing so:


Nowadays most packages use debhelper - it simplifies the process considerably. The following steps should get you started. Refer to the Debian Wiki's systemd packaging guide for further information.

Enable dh_systemd

With debhelper compat level 10 (check Build-Depends section in debian/control and debian/compat) dh-systemd is automatically enabled and you can skip this section. For older debhelper compat levels you have to follow the following steps to enable it:

  • Add dh-systemd (>=1.5) to Build-Depends in debian/control.
  • Append --with systemd to your dh $@ line in debian/rules.

Using dh_systemd

Drop your systemd unit files into debian/ so they get installed. Debhelper will automatically detect and enable them during package installation.

Note: There is no need to add anything to the postinst and postrm scripts, debhelper will automatically take care of that for you. Also keep in mind that your manual approach relies on the systemctl executable and thus only works on machines that already have systemd installed when the user installs the package. The debhelper approach will enable the systemd service even if systemd isn't installed. If the user switches to systemd later the service is already enabled. The debhelper approach also works nicely if your package ships both an old Sys-V-style init script and a systemd unit file.

Advance use

In case you have special needs (e.g. install multiple unit files but only enable a subset of them) you can override the dh_systemd_enable and dh_systemd_start targets in debian/rules and specify additional parameters. See the man page of dh_systemd_enable and dh_systemd_start for details.

1
  • 1
    Thanks for the answer, I can not use debhelper because I want to be able to also build the package on OS X so I have to use dpkg --build, but I could spin up a Debian VM and check what debhelper does and use the result in my postinst script by adding some calls to deb-systemd-helper which now installs and enables the service.
    – tbraun89
    May 19, 2020 at 14:02
0

As mentioned by Martin Konrad, the --user used as is attempts to install the service for the root user, which is probably not what you want.

On my end, I had that issue but I really needed to install the service for a user because it had to access the audio system and that really only works when the system is setup for a specific end user (and that end user is logged in—which is the case in my embedded system).

Here are the few lines of code I use to setup a user specific service:

# Manually enable "service-name" for USER_NAME
USER_NAME=nobody
mkdir -p /home/${USER_NAME}/.config/systemd/user/default.target.wants
chown -R ${USER_NAME}:${USER_NAME} /home/${USER_NAME}/.config/systemd
rm -f /home/${USER_NAME}/.config/systemd/user/default.target.wants/service-name.service
sudo -H -u ${USER_NAME} sh -c "ln -s /usr/lib/systemd/user/service-name.service /home/${USER_NAME}/.config/systemd/user/default.target.wants/service-name.service"

Make sure to edit the name of the user you want to enable the service for (USER_NAME=...).

Replace service-name with the name of your user service. For example, if it manages sounds, you could call it sound-manager.


Note 1: This scripts assumes that the users are created under /home/<username>. You'll want to adapt that to your situation if you are working with a different user (i.e. the root account appears under /root, the Apache2 account on Debian/Ubuntu appears under /var/www, etc.)

Note 2: How do you all of this?! I actually did not invent that script per se. When you are logged in as $USER_NAME, you can enable the service using a command such as:

systemctl enable --user service-name

This creates the directories and link as shown above. If things change or are saved in a different directory for you, then you may need to tweak the commands to replicate what systemctl does.

Note 3: You could install this for all users. Add a loop over the /home/* names and repeat the commands with each name. There is also a set of scripts that run whenever a new user is created. Hopefully, you do not need such services. I think it is better to let each user enable such a service on their own.

You must log in to answer this question.

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