systemd is the newer init system used in most Linux distributions since 2015. The first widely used init system was the System V init process, sysvinit. Ubuntu introduced the Upstart init system with Ubuntu 6.10 in 2006. Ubuntu fully migrated to systemd with Ubuntu 15.04 in 2015. Indeed, we can see that /sbin/init is symbolically linked to /lib/systemd/systemd.
$ ps -f 1 UID PID PPID C STIME TTY STAT TIME CMD root 1 0 0 10:49 ? Ss 0:01 /sbin/init splash $ ls -ls /sbin/init 0 lrwxrwxrwx 1 root root 20 Nov 25 18:27 /sbin/init -> /lib/systemd/systemd $ ls -ls /lib/systemd/systemd 1544 -rwxr-xr-x 1 root root 1577232 Nov 25 18:27 /lib/systemd/systemd
init is the first process, with the process id 1, that comes into existence during the system bootstrapping procedure. init creates other processes that are necessary to run the system. init is the ancestor of all processes in any Unix-like system.
systemd is not just an init system; it is a suite of daemons. It has systemd-journald for event logging, systemd-logind for managing user logins, systemd-timesyncd for synchronizing system clock with an NTP server and systemd-udevd for managing devices. Rest of this tutorial looks at the init functionality of systemd.
systemd is described as the system and service manager for Linux based systems. It manages the system based on directives in the configuration files. systemd does the important work of managing daemons by starting, stopping, restarting them. It also reports status of the daemons.
A major objective in the design of systemd was to do things in parallel and minimize the system boot time. systemd uses the concept of socket activation for services. The interprocess communication between a service and its clients takes place via sockets. The creation of sockets is done right upfront, before spawning of services. The socket file descriptor is passed to a service at the time of spawning of the service process. After creation, a service can start listening for messages on its socket. One major advantage of this approach is that listening sockets are available right in the beginning and clients can send messages to them even when the corresponding service is yet to get started. The service, after start, can process all the earlier messages in its listening socket. Also, if a service terminates, its socket is still there and clients can log messages to it. The messages will get processed once the service comes up again.
Apart from socket activation, there can be DBus based activation, device based activation or path based activation of services. In case of Dbus based activation, a service is started when a client tries to communicate with it over the Dbus the first time. Similarly, a service supporting device-based activation is started when a device is plugged in. Also, a service supporting path based activation is started when there is some change in the concerned directory or file.
Units are the entities managed by systemd. The most common type of unit is a service. A unit file for a service has a .service extension. There are other unit types, and the list is,
|Unit type||File extension||Description|
|service||.service||A system service|
|socket||.socket||An IPC socket|
|device||.device||A device file|
|mount||.mount||A mount point in the filesystem|
|automount||.automount||An automount point in the filesystem|
|swap||.swap||A swap device or file|
|target||.target||A group of units|
|path||.path||A path (file or directory) monitored by systemd|
|timer||.timer||A timer controlled by systemd|
|snapshot||.snapshot||A saved state of systemd|
|slice||.slice||A group of units, hierarchically organized in a tree, for managing processes|
|scope||.scope||A scope unit for managing externally created processes|
A service file has systemd directives for the concerned service. For services that are activated via a socket, there are two unit files - one, the service unit file with
.service extension, and two, a socket file, with a
.socket extension. systemd uses device and path unit files for device and path based activation respectively. For DBus-based activation, systemd uses the DBus service files.
The unit files are located in /lib/systemd/system and /etc/systemd/system directories. The latter takes precedence over the earlier. The unit files from packages are placed in /lib/systemd/system, whereas the unit files written by system administrators are placed in the /etc/systemd/system directory.
A unit file for a hypothetical service, sample, is given below. The file is named sample.service.
[Unit] Description=The SAMPLE server After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/run/sample.pid ExecStartPre=/usr/sbin/sample -t ExecStart=/usr/sbin/sample ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
A unit file has systemd directives. The directive Type tells the start up type of the service unit. The type could be simple, forking, oneshot, dbus, notify or idle. In case of the type simple, the process started with the command next to the ExecStart directive. It is expected that the communication channels have been set up before the start of the daemon process and systemd proceeds with starting of follow-up units right away. If the type is forking, the process specified with ExecStart is expected to fork. The parent process is expected to exit after the communication channels and other initialization work is over and the child process continues as the main daemon process. It is important to use the PIDFile= directive so that systemd can identify the process for the service. The type oneshot is similar to the type simple except that this process has to exit before follow-up units can be started by systemd. The type dbus is similar to the type simple except that the daemon is expected to acquire a name on the D-Bus, as configured with the BusName= directive. Once the name is acquired on the D-Bus, systemd will proceed with starting of the follow-up units. The type notify is similar to the type simple, except that the daemon is expected to send a notification message with sd_notify after its initialization work is over and, then, systemd goes ahead with starting the follow-up units. The type idle is, again, similar to the type simple except that there the service start is delayed till all active jobs are dispatched. This is to ensure that the output on console is not mixed up. However there is a timeout of 5 seconds. after which the service is anyway started.
4.0 Target Units
A target unit is a collection of other units. Target units help in expressing dependencies of units and also the sequence in which units are to be started. Consider the After= and WantedBy= directives in the unit file listed above. The After= directive specifies that this unit should be started after the units specified with the After= directive. Similarly, the WantedBy= directive specifies that this unit needs to be started for the given target. So when this unit is enabled with the systemctl command, a symbolic link to this unit file is created in that target's wants directory (/etc/systemd/system/multi-user.target.wants/).
A special target is the default target, default.target. systemd tries to start services for this target. default.target is often a link to the graphical.target. graphical.target requires multi-user.target and should be started after multi-user.target, rescue.service, rescue.target and the display-manager.service. At any time, multiple targets might be active. We can see the dependencies of a unit with the command,
$ systemctl list-dependencies <unit>
And, we can see the list of all the currently active targets with the command,
$ systemctl list-units --type=target
The systemctl command is used for controlling the systemd system and service manager. Some of the commonly used variations of the systemctl command are,
$ # List running units $ systemctl $ # Or, $ systemctl list-units $ $ # List all installed unit files $ systemctl list-unit-files $ $ # Show systemd status $ systemctl status $ $ # Status for a unit $ systemctl status <unit-name> $ # For example, $ systemctl status nginx.service $ # If we skip extension in unit-name,.serviceis assumed. $ systemctl status nginx $ $ # List all failed units $ systemctl --failed $ $ # Check whether a unit is enabled $ systemctl is-enabled <unit-name> $ # For example, $ systemctl is-enabled nginx $ $ # Enable a unit to be started at boot $ sudo systemctl enable <unit-name> $ $ # Disable a unit $ sudo systemctl disable <unit-name> $ $ # Mask a unit so that it becomes impossible to start it $ sudo systemctl mask <unit-name> $ $ # Unmask a unit $ sudo systemctl unmask <unit-name> $ $ # Start a unit $ sudo systemctl start <unit-name> $ $ # stop a unit $ sudo systemctl stop <unit-name> $ $ # Restart a unit $ sudo systemctl restart <unit-name> $ $ # Reload the configuration for a unit $ sudo systemctl reload <unit-name>