home |  electronics |  toolbox |  science club |  tuxtalk |  photos |  e-cards |  online-shop



Linux: systemd in a nutshell

I have been very skeptic about systemd and why one would need to replace the existing init scripts. It was easy to add or change things in those init scripts and they did the job. However when you change from a system with init scripts to one based on systemd you notice immediately a big difference: startup time. Systemd boots a lot faster. My Thinkpad boots in under 10s with systemd. Even an optimized init script based system will need more than 20s on the same machine.

OK, now I have systemd but how do I use it? You can find a lot of general documentation about using systemd at https://www.freedesktop.org/wiki/Software/systemd/ and Arch linux has a very nice tutorial https://wiki.archlinux.org/index.php/systemd. Your basic command for managing systemd is systemctl:

systemctl list-units systemctl status NAME_OF_SERVICE systemctl stop NAME_OF_SERVICE systemctl start NAME_OF_SERVICE systemctl disable NAME_OF_SERVICE systemctl enable NAME_OF_SERVICE systemctl mask NAME_OF_SERVICE (permanently disable service) systemctl unmask NAME_OF_SERVICE systemctl list-unit-files systemctl daemon-reload (to read modified .service files)
systemctl can not only reboot the computer but put it to sleep or power it off:
systemctl reboot systemctl suspend systemctl poweroff

Linux: how to write your own systemd scripts (unit files)

Case 1: You want to start your own server processes via systemd.

These processes are simply started as:
your_cmd 1 & your_cmd 2 & your_cmd 3 &

There is no overall daemon that supervises everything.

To stop this process you would run
killall your_cmd
To integrate this very primitive service to systemd you write two scripts. One script for startup and one to stop the processes:
#!/bin/bash # This is /usr/bin/your_cmd-start.sh # start script for your_cmd your_cmd 1 & your_cmd 2 & your_cmd 3 &
and
#!/bin/bash # This is /usr/bin/your_cmd-stop.sh # stop script for your_cmd killall -w your_cmd
This is the basic framework of our process and it could be any simple script based server process. It does not really matter what it exactly does. The important part is that there is a script to start it and after having executed that script the process is running. There is as well a script to stop the whole thing.

To integrate this into systemd you write a short text file called unit file and you copy this file to /usr/lib/systemd/system/ (on some systems such as ubuntu this is in /lib/systemd/system). The file name must end in .service:
vi /usr/lib/systemd/system/your_cmd.service or dependent on your distribution flavor: vi /lib/systemd/system/your_cmd.service
The content of this file must look like this:
# this is /usr/lib/systemd/system/your_cmd.service
# (or /lib/systemd/system/your_cmd.service dependent on 
#  your linux distribution flavor )
[Unit]
Description=your_cmd server daemon
Documentation=http://tuxgraphics.org/npa/
After=network.target syslog.target

[Service]
# see man systemd.service 
Type=oneshot
ExecStart=/usr/bin/your_cmd-start.sh
RemainAfterExit=true
ExecStop=/usr/bin/your_cmd-stop.sh
StandardOutput=journal

[Install]
WantedBy=multi-user.target 

You can syntax check it with:
systemd-analyze verify /usr/lib/systemd/system/your_cmd.service

There are two important keywords in the unit file: Type=oneshot means that this is a script which just runs and then exits and RemainAfterExit=true means that although the script has finished the service is still running.

Now enable it:
systemctl list-unit-files | grep your_cmd systemctl enable your_cmd systemctl start your_cmd systemctl status your_cmd

To stop it:
systemctl list-units | grep your_cmd systemctl stop your_cmd


Case 2: You want to do some configuration tasks and execute those commands at startup.

This is very similar to the first case but there is no server process. You want to change some settings before a given service starts. In this example we want to run a script before httpd starts.
#!/bin/bash # This is /usr/bin/your_config-start.sh # # do all your commands here... script terminates when all is done.

You would write the following unit file and activate that service in the same way as in the above case. There is just no stop command.
# this is /usr/lib/systemd/system/your_config.service
# enable with command: systemctl enable your_config
[Unit]
# man systemd.unit
Description=your_config
Documentation=http://tuxgraphics.org/npa/
After=network.target syslog.target
Before=httpd.service
Wants=httpd.service

[Service]
# see man systemd.service, systemd.exec
Type=oneshot
ExecStart=/usr/bin/your_config-start.sh
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target 


I hated systemd for a few days but after I figured out how to use it and how to add my own customizations it was not too bad. It works actually quite well. You just have to learn how to use it.

Use case: Prevent hanging shutdown due to NFS server down

The Linux kernel has now for a long time already features to allow the unmounting of network filesystems even when the server is down. Normal local disk based filesystems have to be unmounted cleanly at shutdown to prevent corruption. NFS filesystems are very different in this respect. The NFS server makes sure that the filesystem is consistent. Thus if you shutdown your PC there is little point to try forever to unmount a NFS mount. The NFS server may already have disappeared (because it was shutdown first or because you changed network connectivity, ...).

Yet in most Linux distributions you will see that they will not be able to shutdown and just hang forever in a failed shutdown state.

My use case: I have all my pictures stored on the desktop PC and when I am on my laptop then I just mount the pictures folder from the desktop via NFS. The folder is called dimage, named after my first digital camera. Occasionally it happens that the desktop PC is shutdown in the evening before I shutdown the laptop. The laptop is running ubuntu 16.04 and it is then able to shutdown. It just hangs forever. One has to hard reset the laptop to get out of this. The following is a systemd service script that prevents this. It has to be installed on the laptop. It checks if there is an nfs mount (I might not always work with my photos) on the mount point called dimage. If so then it runs "umount -f -l ...." on that mount. The "-f -l" stand for force and lazy unmount and they clean up all local references and disconnect.

This is the "umount-nfs-dimage.service" systemd script which you need to copy to /lib/systemd/system/umount-nfs-dimage.service (ubuntu):
# syntax check this with: 
#   systemd-analyze verify /lib/systemd/system/umount-nfs-dimage.service
# installation:
#   systemctl list-unit-files | grep umount-nfs-dimage.service
#   systemctl enable umount-nfs-dimage.service
#   systemctl start umount-nfs-dimage.service
[Unit]
Description=NFS lazy unmount dimage
After=syslog.target
Wants=multi-user.target

[Service]
# see man systemd.service 
Type=oneshot
RemainAfterExit=true
ExecStop=/usr/bin/umount-lazy-nfs-stop.sh
# write to log
StandardOutput=syslog+console

[Install]
WantedBy=multi-user.target 
This systemd service does nothing at startup and it executes /usr/bin/umount-lazy-nfs-stop.sh at shutdown. It does it while syslog is still running so we can easily debug things in case of a typo. The /usr/bin/umount-lazy-nfs-stop.sh looks like this:
#!/bin/sh
# This umount-lazy-nfs-stop.sh script is used by the following systemd services:
#  redhat: /usr/lib/systemd/system/umount-nfs-dimage.service
#  ubuntu: /lib/systemd/system/umount-nfs-dimage.service
# This script should be executed on shutdown only
# and while syslog is still running (makes it easier).
# Written by guido socher
if [ -n "$1" -a "$1" = "-h" ];then
	echo "run umount -l -f /mnt/nfs/dimage if mounted"
	exit 0
fi
if mount -t nfs | grep -q  dimage; then
	echo "dimage directory mounted, lazy unmount"
	umount -l -f /mnt/nfs/dimage
else
	echo "dimage directory NOT mounted, nothing to do"
fi 


Save this script and then make it executable with "chmod 755 /usr/bin/umount-lazy-nfs-stop.sh".

You might need to adapt this script a bit. My mount point for the NFS filesystem is /mnt/nfs/dimage and yours may be different.

It works very well and it is the right thing to do. There is little purpose in trying to execute a normal unmount when it will just prevent the laptop from shutting down. NFS filesystems can not get corrupted if you just disconnect. The NFS server takes care of filesystem consistency.

Back to: "No preservatives added"



© 2004-2024 Guido Socher