19

I install Debian a lot. To do this I have a fully-automated preseed.cfg; at the end of the preseed, it downloads and runs a postinstall.sh script from my TFTP server, which does some additional customization.

I'm in the process of switching from GNOME to LXQTE, and using SDDM instead of GDM. However, SDDM tries to start too quickly for my hardware. To get around this, I've been using systemctl edit sddm to add the following:

[Service]
ExecStartPre=/bin/sleep 5

This works great, and I'd like to automate this process by adding it to the postinstall.sh script. However, I can't figure out how to pass the file contents to systemctl edit via a bash script. How can I do this?

5 Answers 5

15

You can override the $SYSTEMD_EDITOR environment variable to use a different command other than your editor when running systemctl edit.

For instance, using something like SYSTEMD_EDITOR='cp /path/to/source.file' seems to work OK (even though it's pretty ugly, expecting the last argument to be appended there by systemd!)

For your particular case, you could use:

$ { echo "[Service]"; 
    echo "ExecStartPre=/bin/sleep 5";
  } >~/tmp/sddm-override.conf
$ sudo env SYSTEMD_EDITOR="cp $HOME/tmp/sddm-override.conf" systemctl edit sddm

But all that systemctl edit really does is create an override file (in its case, named override.conf) under the /etc/systemd/system/<service>.service.d/ directory, which is created if it does not exist... So doing that directly is also a totally accepted approach. (See mentions of "drop-in" and "override" in the man page for systemd.unit for more details.)

So, in your case, this would be an appropriate solution:

$ sudo mkdir -p /etc/systemd/system/sddm.service.d/
$ { echo "[Service]"; 
    echo "ExecStartPre=/bin/sleep 5";
  } | sudo tee /etc/systemd/system/sddm.service.d/10-startup-delay.conf
$ sudo systemctl daemon-reload

Which drops a file with the expected contents in the "drop-in" directory for your unit, in which case you can also name it appropriately after what it tries to accomplish.

UPDATED: As @GracefulRestart points out, you need a systemctl daemon-reload after adding a drop-in directly.

3
  • 1
    Thank you for your answer, but I haven't had any luck with it. See my comment to @GracefulRestart; basically the sddm.service.d directory is not created on install, and even manually creating it and the override.conf does not work (even with daemon-reload) - there must be something special about the systemctl edit in particular. Commented Aug 2, 2018 at 18:02
  • @user5104897 If you think there's something special with systemctl edit then try the first method I suggested of setting SYSTEMD_EDITOR environment variable to a command that will create the file. I think the issue might actually be with your postinstall script. Are you running that in the root directory at the machine, or is it maybe running from install media and so you're modifying that filesystem and not the one you boot into? Can you give more details on what your postinstall script is and does? Good luck!
    – filbranden
    Commented Aug 2, 2018 at 20:31
  • 1
    Ah, I was able to get it working with a few changes to the script - I forgot to ~/tmp - we're all good now! Commented Aug 3, 2018 at 17:03
6

Since I have not found how to use systemctl edit in a script yet, best practice would be to simulate the systemctl edit sddm command and place the override in the /etc/systemd/system directory, as service units in /usr/lib/systemd/system could be changed when packages are upgraded:

UNIT='sddm.service'
DIR="/etc/systemd/system/${UNIT}.d"
mkdir $DIR
echo -e "[Service]\nExecStartPre=/bin/sleep 5" > ${DIR}/override.conf
systemctl daemon-reload

That should be roughly equivalent to what systemctl edit sddm is doing.

3
  • I've tried this solution, but I'm running into some problems. After adding this to my postinstall script, sddm still didn't start as expected. I logged in and noticed the /etc/systemd/system/sddm.service.d directory did not exist. After creating this directory and running the echo and daemon-reload myself, I rebooted and it still didn't work. Next I tried adding mkdir /etc/systemd/system/sddm.service.d to the postinstall, and this directory still isn't being created! Regardless, doing it manually doesn't seem to work either. Commented Aug 2, 2018 at 17:41
  • When you use systemctl edit sddm, where does systemd put the override.conf? I am not sure why you would not be able to create the directory, check permissions or if selinux is stopping you. Commented Aug 2, 2018 at 19:57
  • I'm able to create the directory and file manually, but they have no effect even after daemon-reload - it's only when I use systemctl edit sddm that the changes actually take effect. Using systemctl opens a buffer named /etc/systemd/system/sddm.service.d/.#override.conf52ea69f0b57f34f9, but it does ultimately create sddm.service.d/override.conf anyway. Commented Aug 2, 2018 at 20:45
6

You can change what editor systemctl(8) uses for its edit subcommand with the SYSTEMD_EDITOR variable. This essentially constructs a command whose final argument is always a systemctl(8) created temporary file that, once written to, is then moved to override.conf.

Because of this, we can use tee(1) as the SYSTEMD_EDITOR and then redirect any text we want from the shell to the entire systemctl(8) command on stdin. For example, redirecting a Here-Document:

SYSTEMD_EDITOR=tee systemctl edit sddm <<EOF
[Service]
ExecStartPre=/bin/sleep 5
EOF

This creates the drop-in file /etc/systemd/system/sddm.service.d/override.conf with the contents between the "words" EOF.

Under-the-hood the edit subcommand looks something like this:

# Create drop-in directory for service
mkdir -p /etc/systemd/system/sddm.service.d

# Create empty temporary file
touch /etc/systemd/system/sddm.service.d/.

# Pass temporary file as last argument of SYSTEMD_EDITOR
tee /etc/systemd/system/sddm.service.d/.\#override.conf846580011dbe64db/.\#override.conf846580011dbe64db<<EOF
[Service]
ExecStartPre=/bin/sleep 5
EOF

# Rename temporary file
mv /etc/systemd/system/sddm.service.d/{.\#override.conf846580011dbe64db,override.conf}

After the unit has been edited, the systemd configuration is reloaded automatically (in a way that is equivalent to daemon-reload).

1

I want to second the answer given in 3 but I do it this way using tee

env SYSTEMD_EDITOR=tee  sudo -E systemctl edit --system [your_unit_name] < [your_content_file]

When doing it this way you can feed the content via stdin rather than from a file, which can be useful when invoking systemctl from a script.

1
  • If you move SYSTEMD_EDITOR=tee after sudo you can remove env and -E. Commented Feb 14, 2019 at 23:39
-2

I'd attack the file directly:

sed -i 's/\[Service]/ a\
ExecStartPre=/bin/sleep 5' /usr/lib/systemd/system/sddm.service
2
  • 1
    editing files managed by a package is generally unreliable. An override would probably be a better option.
    – smokes2345
    Commented Aug 1, 2018 at 22:36
  • This is incorrect. You shouldn't edit units from /usr/lib directly, since the modifications are probably going to get clobbered next time the package is upgraded. Furthermore, what you suggest is likely to cause syntax errors, since the unit probably already has a [Service] section and shouldn't really get another. Drop-ins are the correct way to deal with this kind of overrides. See the other answers for more details.
    – filbranden
    Commented Aug 1, 2018 at 22:37

You must log in to answer this question.

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