Understanding systemd units
On the Unit
Systemd units use files to control resources that Systemd manages.
Whether you like it or not: Systemd has become ubiquitous. Linux distributions that rely on other init systems are becoming increasingly rare. If you run one of the mainstream distributions, you need to familiarize yourself with the concepts and working methods of systemd.
Systemd units and their corresponding configuration files require close attention. The term "unit" means any type of resource that cooperates with Systemd – which includes timers, mountpoints, network resources, sockets, partitions, and devices on top of services.
Configuration units, known as unit files, let you define how and when a service starts, which resources it is allowed to access, and which dependencies need to be met. Unit files are similar in function to the init scripts in SysVinit or Upstart (Figure 1), but they are usually easier to create and easier to maintain. They follow the conventions of simple INI files (Figure 2).
The naming convention for unit files follows the pattern Name.type
. Table 1 shows a selection of the most frequently encountered types. As you can see, Systemd manages many different unit types.
Table 1
Unit Types
Type | Function |
---|---|
.service |
Start, monitor and stop services |
.device |
Create device files |
.mount |
Mount and unmount mountpoints |
.automount |
Automatically mount and unmount mountpoints |
.target |
Define a group of units |
.timer |
Define recurring tasks (like Cron) |
.socket |
Establish connections between processes |
.network |
Configure networks |
.path |
Execute service units as a function of changes |
Many of the unit types work together to extend functionality. Some units are used to trigger other units and activate services and targets. Each type has its own man page – named according to the pattern systemd.type
.
Distributed
Units are found in several places on the system. Under /lib/systemd/system/
are files pre-installed by the system. Units you created yourself, or units you edited, are found in /etc/systemd/system/
. If you want to change an existing unit, it is best to copy it there first and edit it there. Finally, certain units relevant for the runtime are located below /run/system/system/
. The order of parsing is /etc/
, /run/
, /lib/
.
When you look at the unit files gathered in /lib/systemd/system/
, you will see files with different extensions that represent the different types. Extensions like .network
, .timer
, .mount
, or .device
are self-explanatory. However, the service units that determine the behavior of the services on the computer are the most common type (Figure 3).
Tripartite
An example helps to explain the structure of the files. This example is based on the autofs.service
service shown in Figure 2. autofs.service
is a service for starting external drives or network shares, and it uses a reasonably clear unit file.
A unit is divided into three sections [Unit]
, [Type]
, and [Install]
; the unit type varies. In this case, it says [Service]
because it is a unit for controlling a service. Often several unit types belong together, such as a service and a timer. The service file defines the service itself, and the timer controls its recurring execution (Figure 4).
In the example from Listing 1, the directives used with the unit take the form of key-value pairs. This section is typically used to define metadata for the unit and to configure the relationship of the unit to other units.
Listing 1
Unit Section
[Unit] Description=Automounts filesystems on demand After=network.target ypbind.service sssd.service network-online.target remote-fs.target Wants=network-online.target
The Description
key describes the service. You are free to choose the value, but it should clearly state the purpose of the service. The After
key contains the services and targets that this service expects. Targets are groups of services (Figure 5).
The last key you see is Wants
, which you use to denote optional dependencies. You indicate a hard dependency with Require
. If the service registered there does not start, the service to which this unit belongs fails. If you specify Wants
, it will still start. Now, if you're wondering what the extra After
is for: Its absence would mean that both units would start in parallel, which would not make sense in this case.
In the Unit
section, you can use further keywords like Description
, Documentation
, BindsTo
, Conflicts
, Condition
, Assert
and others. For more information, see the systemd.units
man page.
The [Service]
section plays a central role (Listing 2). First, you need to define the service type. The default is Type=simple
. The simple
type means that the service does not fork after startup.
Listing 2
Service Section
[Service] Type=forking PIDFile=/var/run/autofs.pid EnvironmentFile=-/etc/default/autofs ExecStart=/usr/sbin/automount ExecReload=/bin/kill -HUP $MAINPID TimeoutSec=180
The example in Listing 2 is a forking
type service. Systemd considers the service to have started as soon as the process disappears into the background and the higher-level system terminates. This type is often used for legacy daemons. You need to specify the key-value pair PIDFile=File
, so that the system can continue to follow the main process.
You might encounter a few other service types when you look at the unit files on your computer. Type=oneshot
is used for scripts that do a single job and then exit. Type=notify
is similar to Type=simple
, with the difference that the daemon sends a signal to Systemd when it is ready. In the case of Type=dbus
, the service is considered ready if the specified BusName
appears on the D-bus system bus. In the case of Type=idle
, Systemd delays the execution of the service until it has completed all other pending jobs.
Another key from this example, EnvironmentFile=
, appears in the [Service]
section. This value refers to a file from which the service loads environmental variables if required. ExecStart=
contains the command that the system executes when the unit starts, and ExecReload=
reloads the configuration of the service if necessary.
Finally, TimeoutSec=
specifies the maximum time the service will run. All service types and keys for the [Service]
section are explained in detail in the systemd.service
man page.
The [Install]
section in this example has only a single entry (Listing 3). The key-value pair used here is present in almost every service file. The WantedBy
key determines when the unit starts. The multi-user.target
value is the default for a multi-user system. These targets correspond to the run levels in SysVinit, where multi-user.target
stands for run level 3.
Listing 3
Install Section
[Install] WantedBy=multi-user.target
You can determine the run level in Systemd using systemctl get-default
in the terminal. In a graphical environment, it goes by the name of graphical.target
(SysVinit: Run-Level 5). All available run levels (or, more correctly, targets) are displayed by the command
ls -al /lib/systemd/system/runlevel*
See Figure 6.
Author It Yourself?
You may have wondered what practical reason (besides pure curiosity) would make you want to create a Systemd unit.
Suppose you install some software that runs a service that only has an init file, but not a unit file: It makes sense to create a unit for it yourself. A good starting point is the simple template in Listing 4.
Listing 4
A Template
[Unit] Description=My_Unit Documentation=man:optional reference to man files<I> After=<I>starts after XY<I> Wants=optional <I>dependencies<I> [Service] <I>Key-value pairs for the unit type in question<I> [Install] WantedBy=multi-user.target
A useful way to fill the [Service]
section is to look at similar existing unit files. The systemctl list-unit-files
command creates a list of all unit files on the system with their current statuses. You can restrict this list to services by specifying systemctl list-unit-files --type service
.
However, the first command can return other interesting unit types of the same name. These could be target units, for example: They are used to link and group other units to describe a desired state of the system. Some of these units would then be services, others perhaps additional targets with their own groups of units.
Users who rely on KDE Plasma enjoy greater convenience: This desktop lists all units and their statuses clearly in the system settings below the System item. You can also use a combo box to filter by unit type or use a search function (Figure 7).
To learn more about a unit similar to the one you are creating, use the systemctl status service_name
command in addition to the unit file. This command provides information about runtime, memory usage, process ID (PID), and possible error messages since the last start of the service (Figure 8).
Once you have finished the unit file and put it in the right place, use systemctl status service_name
to check the status. Additional information may be provided by the journalctl --unit=service_name
command.
To enable and start the service, use the systemctl start service_name
command. The systemctl
man page provides additional commands and options.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
New Slimbook EVO with Raw AMD Ryzen Power
If you're looking for serious power in a 14" ultrabook that is powered by Linux, Slimbook has just the thing for you.
-
The Gnome Foundation Struggling to Stay Afloat
The foundation behind the Gnome desktop environment is having to go through some serious belt-tightening due to continued financial problems.
-
Thousands of Linux Servers Infected with Stealth Malware Since 2021
Perfctl is capable of remaining undetected, which makes it dangerous and hard to mitigate.
-
Halcyon Creates Anti-Ransomware Protection for Linux
As more Linux systems are targeted by ransomware, Halcyon is stepping up its protection.
-
Valve and Arch Linux Announce Collaboration
Valve and Arch have come together for two projects that will have a serious impact on the Linux distribution.
-
Hacker Successfully Runs Linux on a CPU from the Early ‘70s
From the office of "Look what I can do," Dmitry Grinberg was able to get Linux running on a processor that was created in 1971.
-
OSI and LPI Form Strategic Alliance
With a goal of strengthening Linux and open source communities, this new alliance aims to nurture the growth of more highly skilled professionals.
-
Fedora 41 Beta Available with Some Interesting Additions
If you're a Fedora fan, you'll be excited to hear the beta version of the latest release is now available for testing and includes plenty of updates.
-
AlmaLinux Unveils New Hardware Certification Process
The AlmaLinux Hardware Certification Program run by the Certification Special Interest Group (SIG) aims to ensure seamless compatibility between AlmaLinux and a wide range of hardware configurations.
-
Wind River Introduces eLxr Pro Linux Solution
eLxr Pro offers an end-to-end Linux solution backed by expert commercial support.