1. Overview
The systemd software suite is well known for managing a Linux system. It can handle system resources, like services, sockets, and mount points. In addition, it’s used to initialize a Linux system.
In this tutorial, we’ll discuss systemd targets and particularly the multi-user target.
2. Systemd Units
The resources that systemd manages are called units. We can get a listing of the managed units with the systemctl command:
$ systemctl list-units
This command echoes all types of units like services, sockets, targets, etc. We can narrow down the output of the command with the –type option:
$ systemctl list-units --type=target
Here, we filter the list to display only target units. We do this by setting the –type value to target.
Furthermore, units are described in special configuration files that we call unit files. The systemd manager scans many directories to load unit files:
- /usr/lib/systemd/system, for system units
- /etc/systemd/system, for user-defined units
For a full list of unit paths on our system, we can run the systemd-analyze command:
$ systemd-analyze unit-paths
A valid unit file name consists of two parts:
- unit name
- unit type, preceded by a dot
For example, the unit file of the multi-user target is multi-user.target.
3. Dependencies Between Units
We can set dependencies between units in their unit files. Let’s check the dependencies of the multi-user target with the systemctl command:
$ systemctl show -p "Requires" multi-user.target
Requires=basic.target
Here, we use the systemctl show command together with the -p option, to output the Requires property. We can see that this property is set to the basic.target. This makes systemd start the basic unit in its effort to start the multi-user unit.
Next, let’s output the After property again using the systemctl command:
$ systemctl show -p "After" multi-user.target
After = basic.target ...
In this case, the After property denotes the starting sequence for the two units. In particular, the multi-user target will start after the listed basic target.
4. Targets
Targets are groupings of resources that represent a state the Linux system has reached during startup. In this sense, they’re equivalent to SysV runlevels. Furthermore, targets mostly correspond to runlevels:
- poweroff
- rescue
- multi-user
- graphical
- reboot
Moreover, there are dependencies between these targets. In the previous section, we saw that the multi-user target depends on the basic target.
Another key point of the whole procedure is the default target since the system will try to activate this target during the startup process. Usually, it’s a link to one of the targets listed above. We can locate this link in the filesystem:
$ ls -l /usr/lib/systemd/system | grep default
lrwxrwxrwx 1 root root 16 Aug 31 18:27 default.target -> graphical.target
Here, the default target points to the graphical target. The system can display a user log-on screen to accept user sessions in this target. This is the final step that the system will try to reach during startup.
5. The multi-user Target
The multi-user target is the state where the system can accept multiple non-graphical user sessions. It’s equivalent to SysV runlevels 2, 3, and 4.
In addition, the graphical target depends on the multi-user target according to its unit file:
$ systemctl show -p "Requires" graphical.target
Requires = multi-user.target
The multi-user target is often the default in Linux systems that are built without a user interface. Besides that, it’s common to use this target when we create a custom service. In such cases, we can use properties like RequiredBy or WantedBy. Both of them define when our service should start. For example, let’s print the WantedBy property of the Docker service:
$ systemctl show -p "WantedBy" docker.service
WantedBy = multi-user.target
As we can see, the multi-user target is in the WantedBy list. The WantedBy property is the opposite of the Wants property. As a result, the system will activate the Docker service as part of the multi-user target.
The Wants property is similar to Requires, but less strict. It’s the recommended way to declare a dependency because the system tries to start the service even if one of its wanted resources fails. This leads to a more fault-tolerant setup.
6. Conclusion
In this article, we learned about the multi-user target. Firstly, we looked at systemd units and the dependencies between them. Then, we discussed target units. Finally, we focused on the multi-user target, which is very common for starting services.