Linux Boot Principles

After the Linux kernel loads and starts, the first process in user space is the initialization process. This program is conventionally located at /sbin/init, though the kernel can also be instructed to start a specified program through kernel parameters. This process is characterized by having a process ID of 1, representing the first user space process to run. Different distributions adopt different startup programs, with the following main choices:

  1. Linux distributions represented by Ubuntu use Upstart.
  2. System V Init, represented by CentOS versions before 7.0.
  3. Systemd, used in CentOS 7.0 and later.

Systemd

Systemd is a collection of system initialization (init) programs and basic components for Linux, developed by a team led by Lennart Poettering and released as open source under the LGPL 2.1 and later licenses. Systemd provides a system and service manager that runs as PID 1 and is responsible for starting other programs. Its development goal is to provide a superior framework to represent dependencies between system services, thereby enabling parallel service startup during system initialization while reducing the system overhead of Shell, ultimately replacing the commonly used System V and BSD-style Init programs.

Systemd uses sockets and D-Bus to start services, provides on-demand startup strategies based on daemons, retains Linux Cgroups process tracking capabilities, supports snapshots and system state restoration, maintains mount and auto-mount points, implements more refined logical control between services based on dependency relationships, and has advanced parallel performance. Systemd can replace System V Init without requiring any modifications. Systemd has been incorporated into the software repositories of many Linux distributions, with Fedora 15 and later versions adopting Systemd as the default Init program for Linux.

Features include:

  • Support for parallel tasks;
  • Service activation via both socket and D-Bus bus methods;
  • On-demand startup of daemons;
  • Process monitoring using Linux Cgroups;
  • Support for snapshots and system restoration;
  • Maintenance of mount points and auto-mount points;
  • Precise control between services based on dependency relationships.

From System V Init to Systemd

The System V Init daemon is a runlevel-based system that uses runlevels (single-user, multi-user, and other levels) and links (located in the /etc/rc?.d directories, which link to Init scripts in /etc/init.d) to start and stop system services. The Upstart Init daemon, on the other hand, is an event-based system that uses events to start and stop system services.

In recent years, the Init process of Linux systems has undergone two major evolutions. Traditional System V Init has faded from the historical stage, while new Init systems like UpStart and Systemd each have their own characteristics, with more and more Linux distributions adopting Systemd.

Design Philosophy

Start as Few Processes as Possible

When the SysV-init program initializes the system, it must start all potentially needed background service processes. Users must wait until the system has started all services before they can log in. This approach brings two problems: excessive system startup time and waste of system resources.

Systemd provides the ability to start services on demand, ensuring that specific services are only started when they are actually requested. This is especially true for hardware-related services, such as Bluetooth services that only need to run when a Bluetooth adapter is inserted, printing services that only need to run when a printer is connected or a program needs to print, and even sshd services that only need to start when a user connects to the server via SSH. This capability is built on Systemd’s feature of monitoring the DBus bus or specific Socket ports, a design that represents a revolutionary advancement compared to traditional startup programs.

Start Processes in Parallel Whenever Possible

In the SysV-init era, startup scripts were executed sequentially according to numbered service items. Later, Ubuntu’s UPstart solved the problem of parallel startup between non-directly dependent startup items. Systemd further resolved dependencies between startup processes through methods such as Socket caching, DBus caching, and establishing temporary mount points, achieving concurrent startup of all system services. This design is also a unique innovation of Systemd. For user-defined services, Systemd allows configuration of startup dependencies, ensuring that services run in the necessary order.

Track and Manage Process Lifecycles

Before Systemd, mainstream application management services used “process trees” to track application inheritance relationships, but parent-child relationships between processes could easily be detached using the “double fork” method.

Systemd proposed tracking process relationships through CGroups to address this gap. Through CGroups, not only can access isolation between services be achieved and anti-counterfeiting quotas for system resources by specific applications be limited, but the lifecycle of services can also be managed more precisely.

Unified Service Log Management

Systemd is a collection of tools, including a dedicated system log management service: Journald. The design intent of this service is to overcome the shortcomings of existing Syslog services, such as easily forged log content and non-uniform log formats, and it has now been incorporated into Systemd’s standard sister services. Journald saves all log information in binary format, making it difficult to manually forge log content. Journald also provides a journalctl command to view log information, which gives logs output by different services the same formatting, facilitating secondary processing of data.

Distributions Using Systemd

Systemd has been incorporated into the software repositories of many Linux distributions, as summarized below:

Distributions with systemd as the default init program:

  • Fedora 15 and later versions
  • Mageia 2
  • Mandriva 2011
  • openSUSE 12.1 and later versions
  • Arch Linux included systemd-sysvcompat in the base software group on October 13, 2012, making Systemd the default Init program after a standard Arch Linux installation, while also providing Systemd startup script packages compatible with Arch’s built-in startup scripts for user convenience, allowing users to “use out of the box”;
  • Chakra GNU/Linux, which has been using Systemd by default since the release of its disc image in October 2012

Distributions that can use systemd:

  • Debian GNU/Linux, available in the “testing” branch repository
  • Gentoo, officially supported by Gentoo along with Openrc

In addition, Systemd has been requested by Lennart Poettering to be included in the list of external dependencies for GNOME 3.2, which means that all distributions using GNOME should use Systemd, or at the very least must have it as a configuration option.

Service Management with Systemd

Units and Targets

Unit Types

A Unit is the basic unit of service management in Systemd. Each service can be considered a Unit and is defined by a Unit file. The Unit file needs to include the description, properties, and commands needed to run the service.

For more detailed introductions to units, please click on the links below:

Targets

A Target in Systemd is used to specify how a group of services starts, equivalent to the runlevel in SysV-init. Every time the system boots, all services associated with the current system’s Target level will run. If a service does not need to start automatically with the system, the content of this Target can be completely ignored. Typically, most Linux users use the multi-user mode level, corresponding to the Target value of multi-user.target, which has an equivalent usable value of default.target.

# View all Targets in the current system
$ systemctl list-unit-files --type=target

# View all Units included in a Target
$ systemctl list-dependencies multi-user.target

# View the default Target at startup
$ systemctl get-default

# Set the default Target at startup
$ sudo systemctl set-default multi-user.target

# When switching Targets, processes started by the previous Target are not closed by default.
# The systemctl isolate command changes this behavior,
# closing all processes from the previous Target that do not belong to the next Target
$ sudo systemctl isolate multi-user.target

As mentioned earlier, Systemd uses Targets to replace the concept of runlevels in System V Init.

RunlevelSystemd TargetNotes
0runlevel0.target, poweroff.targetShut down the system
1, s, singlerunlevel1.target, rescue.targetSingle-user mode
2, 4runlevel2.target, runlevel4.target, multi-user.targetUser-defined/domain-specific runlevels. Default equivalent to 3
3runlevel3.target, multi-user.targetMulti-user, non-graphical. Users can log in via multiple consoles or network
5runlevel5.target, graphical.targetMulti-user, graphical. Usually includes all runlevel 3 services plus graphical login
6runlevel6.target, reboot.targetReboot
emergencyemergency.targetEmergency Shell

Log Management

Systemd unifies the management of startup logs for all Units. The benefit is that you can use just one command, journalctl, to view all logs (kernel logs and application logs). The configuration file for logs is /etc/systemd/journald.conf.


# View all logs (by default, only logs from the current boot are saved)
$ sudo journalctl

# View kernel logs (do not display application logs)
$ sudo journalctl -k

# View logs from the current system boot
$ sudo journalctl -b
$ sudo journalctl -b -0

# View logs from the previous boot (requires changing settings)
$ sudo journalctl -b -1

# View logs from a specific time
$ sudo journalctl --since="2012-10-30 18:17:16"
$ sudo journalctl --since "20 min ago"
$ sudo journalctl --since yesterday
$ sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"
$ sudo journalctl --since 09:00 --until "1 hour ago"

# Display the latest 10 lines of logs at the end
$ sudo journalctl -n

# Display a specified number of lines of logs at the end
$ sudo journalctl -n 20

# Real-time scrolling display of the latest logs
$ sudo journalctl -f

# View logs for a specific service
$ sudo journalctl /usr/lib/systemd/systemd

# View logs for a specific process
$ sudo journalctl _PID=1

# View logs for a script at a specific path
$ sudo journalctl /usr/bin/bash

# View logs for a specific user
$ sudo journalctl _UID=33 --since today

# View logs for a specific Unit
$ sudo journalctl -u nginx.service
$ sudo journalctl -u nginx.service --since today

# Real-time scrolling display of the latest logs for a specific Unit
$ sudo journalctl -u nginx.service -f

# Merge and display logs for multiple Units
$ journalctl -u nginx.service -u php-fpm.service --since today

# View logs of a specified priority (and above), there are 8 levels in total
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
$ sudo journalctl -p err -b

# Logs are paginated by default, --no-pager changes to normal standard output
$ sudo journalctl --no-pager

# Output in JSON format (single line)
$ sudo journalctl -b -u nginx.service -o json

# Output in JSON format (multiple lines), more readable
$ sudo journalctl -b -u nginx.serviceqq
 -o json-pretty

# Display disk space occupied by logs
$ sudo journalctl --disk-usage

# Specify the maximum space log files can occupy
$ sudo journalctl --vacuum-size=1G

# Specify how long log files are kept
$ sudo journalctl --vacuum-time=1years

Configuration and Usage

As mentioned in the introduction, if you plan to develop a new system service, you must understand how to make this service manageable by Systemd. You need to pay attention to the following points:

  • Background service process code does not need to fork twice to implement a background daemon; it only needs to implement the main loop of the service itself;
  • Do not call setsid(), leave it to Systemd to handle;
  • No longer need to maintain PID files;
  • Systemd provides logging functionality, service processes only need to output to stderr, no need to use syslog;
  • Handle the SIGTERM signal, the only correct action for this signal is to stop the current service, do not do anything else;
  • The purpose of the SIGHUP signal is to restart the service;
  • For services that need sockets, do not create sockets yourself, let Systemd pass in the socket;
  • Use the sd_notify() function to notify Systemd of changes in the service’s status. Generally, when service initialization ends and enters the service-ready state, you can call it.

Unit File Storage Paths

$ sudo systemctl show --property=UnitPath

# Display loading directories in order of priority from low to high
UnitPath=/etc/systemd/system /run/systemd/system /run/systemd/generator /usr/local/lib/systemd/system /usr/lib/systemd/system /run/systemd/generator.late
  • /usr/lib/systemd/system/: Units installed by software packages
  • /etc/systemd/system/: Units installed by system administrators

Command Summary

#Reload units
$ sudo systemctl daemon-reload

#Immediately activate a unit
$ sudo systemctl start UNIT

#Immediately stop a unit
$ sudo systemctl stop UNIT

#Immediately restart a unit
$ sudo systemctl restart UNIT

#Reload configuration
$ sudo systemctl reload UNIT

#Output unit running status
$ sudo systemctl status UNIT

#Check if a unit is configured to start automatically
$ sudo systemctl is-enabled UNIT

#Automatically activate a unit at boot, creates a symlink in /etc/systemd/system/TARGET.wants/ directory according to WantedBy set in [Install]
$ sudo systemctl enable UNIT

#Set a unit to start automatically and start it immediately
$ sudo systemctl enable --now UNIT

#Cancel automatic activation of a unit at boot
$ sudo systemctl disable UNIT

#Disable a unit (after disabling, indirect activation is also impossible)
$ sudo systemctl mask UNIT

#Cancel disabling a unit
$ sudo systemctl unmask UNIT

#Display the manual page for a unit (must be provided by the unit file)
$ sudo systemctl help UNIT

#List all dependencies of a Unit, by default not expanded. If you want to expand Targets, you need to use the --all parameter.
$ sudo systemctl list-dependencies [--all] UNIT

#List all configuration files
$ sudo systemctl list-unit-files

#List configuration files of a specified type
$ sudo systemctl list-unit-files --type=service

Power Management Commands

#Reboot
$ sudo systemctl reboot

#Exit the system and power off
$ sudo systemctl poweroff

#Standby
$ sudo systemctl suspend

#Hibernate
$ sudo systemctl hibernate

#Hybrid sleep mode (both hibernate to disk and standby)
$ sudo systemctl hybrid-sleep

The power of Systemd still needs to be experienced in practice. Future articles will also record some practical insights.

I hope this is helpful, Happy hacking…