TIL
Back

systemd

systemd is a suite of Linux system components. Its central component is the system and service manager, also named systemd. The kernel starts it as PID 1 during boot. It then brings up user space and remains responsible for starting, stopping, and supervising services. Separate, unprivileged manager instances can run services for logged-in users.1

Calling systemd an “init system” is accurate but incomplete. The project also includes the journal, login management, device management, network configuration, time synchronization, DNS resolution, and many command-line tools. A distribution may use some or all of these. The PID 1 service manager does not perform every job itself.2

Units

The manager works with units, named resources that it knows how to activate and track. A unit's suffix identifies its type:

Suffix Represents
.service One service and the processes that belong to it
.socket A listening IPC or network socket
.target A group of units or a synchronization point
.timer A time-based or monotonic trigger
.path A trigger based on a filesystem path
.mount A filesystem mount point
.automount An on-demand mount point
.device A kernel device exposed to systemd
.swap A swap device or file
.slice A resource-management group in the cgroup hierarchy
.scope Processes created outside systemd but managed by it

A unit can be inactive, activating, active, deactivating, failed, or in another unit-specific state. “Active” has a different concrete meaning for a mounted filesystem, a listening socket, and a long-running service.1

Units usually come from INI-style unit files. Packages install system units below /usr/lib/systemd/system/, administrators place local units and overrides below /etc/systemd/system/, and software can create runtime units below /run/systemd/system/. The exact vendor directory can vary by distribution. Files in /etc take precedence over files in /run, which take precedence over vendor files.3

Do not edit a package's vendor unit to customize it. An upgrade can replace that file. Use systemctl edit name.service to create a drop-in such as /etc/systemd/system/name.service.d/override.conf. An empty unit file, or a unit symlinked to /dev/null, is masked and cannot be started, even manually.3

Dependencies and ordering

systemd builds a dependency graph and submits requested changes as jobs. It can start unrelated units in parallel because requirement and ordering are separate relationships:

  • Requires=database.service pulls in the database and normally stops the requiring unit if the required unit cannot be activated.
  • Wants=database.service pulls it in but treats failure more weakly.
  • After=database.service says that, when both units are scheduled, this unit's start happens after the database's start. It does not pull the database in.
  • Before= is the inverse ordering relation, while Conflicts= prevents two units from being active together.

A unit that needs another one commonly declares both a requirement and an order:

[Unit]
Requires=database.service
After=database.service

After= does not mean “wait until the application is usable.” It orders systemd's start jobs according to each service's declared startup protocol. A service that needs to announce readiness should use socket or D-Bus activation, or Type=notify and send READY=1, rather than relying on sleeps.14

At boot, systemd activates default.target and recursively pulls in its dependencies. default.target is commonly an alias for multi-user.target on a server or graphical.target on a desktop. Targets replace the fixed sequence of numbered SysV runlevel scripts with named graph nodes. The dependency graph still imposes required ordering, but independent work can proceed concurrently.5

Service units

A service unit describes how systemd starts and supervises a process. A small system service might look like this:

# /etc/systemd/system/example.service
[Unit]
Description=Example HTTP service
After=network.target

[Service]
Type=exec
ExecStart=/usr/local/bin/example --listen 127.0.0.1:8080
User=example
Restart=on-failure

[Install]
WantedBy=multi-user.target

The sections have distinct roles:

  • [Unit] contains description, dependencies, ordering, and activation conditions.
  • [Service] defines the process, startup protocol, restart policy, environment, identity, sandboxing, and resource controls.
  • [Install] tells systemctl enable which symlinks to create. The manager does not read this section to decide what to do during ordinary runtime activation.3

Type= says when startup counts as complete. Type=exec waits until systemd has successfully executed the configured binary, so setup errors such as a missing executable are reported. Type=notify waits for an explicit readiness notification. Type=oneshot waits for a finite command to exit. Type=forking supports traditional self-daemonizing programs but is discouraged for new services. Type=simple considers startup initiated after the process is forked, before execve() is known to have succeeded.4

A service launched by systemd normally should not double-fork, write a PID file, or detach from its standard streams. Running in the foreground lets systemd identify the main process and capture its output directly.

systemd places spawned processes in Linux control groups named after their units. A daemon cannot escape supervision merely by forking, because its descendants stay in the unit's cgroup unless deliberately moved. The same hierarchy supplies CPU, memory, I/O, and task accounting and controls.1

Activation

Starting every daemon eagerly is unnecessary. Other units can activate work when it is needed:

  • A .socket unit opens the listening socket first. Incoming traffic activates the matching service, which inherits the open file descriptor.
  • A .timer activates another unit according to calendar or monotonic time.
  • A .path responds to a path appearing or changing.
  • Device, mount, automount, and D-Bus events can also trigger units.

Socket activation removes a startup race: clients can connect as soon as the socket unit is active, even while the service process is still starting. The kernel queues traffic on the listening socket. It also allows mutually dependent services to start in parallel if their communication endpoints already exist.12

systemctl and the journal

systemctl sends requests to the service manager. The most useful distinction is between unit state and unit-file installation:

systemctl start example.service       # activate now
systemctl stop example.service        # deactivate now
systemctl restart example.service
systemctl reload example.service      # ask it to reload, if supported

systemctl enable example.service      # arrange activation through dependencies at boot
systemctl disable example.service     # remove those installation symlinks
systemctl enable --now example.service
systemctl mask example.service        # make all activation impossible

systemctl status example.service
systemctl show example.service
systemctl list-units --type=service
systemctl list-unit-files --type=service
systemctl cat example.service         # show the unit and its drop-ins
systemctl list-dependencies example.service

start does not imply enable, and enable without --now does not start the unit. Enabling usually creates symlinks such as a target's .wants/ entry; it does not mean that the daemon runs continuously.36

After creating or changing unit files, run systemctl daemon-reload so the manager rebuilds its in-memory unit definitions. A service's own configuration generally needs reload or restart instead. These commands solve different problems.

Services connected to the journal can be inspected with:

journalctl -u example.service
journalctl -u example.service -b       # current boot
journalctl -u example.service -f       # follow new records
journalctl -p warning..alert           # priority range

The journal attaches structured metadata such as the unit, PID, executable, boot ID, and priority to records. Whether records survive reboot depends on journald's storage configuration. systemctl status shows only a recent excerpt, so journalctl -u is the better place to investigate a service's history.

For a per-user manager, add --user to commands and put units below ~/.config/systemd/user/. A user manager has its own default.target, environment, and unit search path. It cannot manage system units merely because their names match.13

References

  1. systemd, systemd(1) manual page. 2 3 4 5 6

  2. systemd, System and Service Manager overview. 2

  3. systemd, systemd.unit(5) manual page. 2 3 4 5

  4. systemd, systemd.service(5) manual page. 2

  5. systemd, bootup(7) manual page.

  6. systemd, systemctl(1) manual page.