Page Body

GNU/Linux System Initialization

An init system is the system used to start and stop a system, and to manage the services it offers. It can handle other functions, as well (e.g., management of logins, devices, and network connections). In the past, the System V init system was prevalent. Now, GNU/Linux systems usually use systemd.

Note: If you are not familiar with the GNU/Linux command line interface, review the Conventions page before proceeding.

systemd

The systemd daemon is located at /lib/systemd/systemd. /sbin/init points to this daemon.

In the systemd init system, a service is a program that runs as a background process.

Explicit Versus Implicit Dependencies

System V init used explicit dependencies to describe the relationship between services, while systemd uses implicit dependencies. For example, in systemd, a service requiring the system log service does not wait to send messages to the system log until the system log service is running because the system log service needs to be running, but because it wants to send messages to the system log itself.

The service that wants to send messages to the system log must access the communication channel that the system log service provides. It is sufficient if systemd itself creates this communication channel and passes it to the system log service once it becomes available. The service that wants to send messages to the system log service will wait until its messages are capable of being received before sending them.

systemd has the capability to create all communication channels first, and then simultaneously start all services, without regard to any dependencies. The dependencies will sort themselves out without an explicit configuration, i.e., implicit dependencies.

Also, this approach works with systems that are already running. If a service is accessed that is not currently running, systemd can start it on-demand. The same approach can also work for file systems, i.e., if a service wants to open a file on a file system that is currently unavailable, the service is suspended until the file system can be accessed.

Units and Targets

System V init used init scripts as a representation of parts of the system to be managed (e.g., services, communication channels, devices). The systemd equivalent is units.

System V init used runlevels to collect related services and define a system state. The systemd equivalent is targets.

systemd Properties

systemd has unique properties:

  • It supports on-demand service activation, not just for hardware dependence, but also via network connections, Desktop Bus (D-Bus) requests, and the availability of specific paths within a file system.
  • It supports fine-grained control of services it launches (e.g., concerning the process environment, resource limits). This includes security enhancements (e.g., providing a limited view of the file system for certain services, or providing services with a private /tmp directory or networking environment).
  • It uses the Linux kernel's cgroups mechanism to ensure that stopping a service stops all related processes.
  • It can be configured to handle services' logging output (the service only needs to be able to write to the standard output).
  • It makes configuration maintenance easier by cleanly separating GNU/Linux distribution default and local customizations.
  • It contains a number of tools built in C that handle system initialization and the tasks that System V init scripts would do. Often, this speeds up the boot process and improves cross-distribution standardization.

systemd is designed to be backwards compatible with System V init. For example, if no native configuration file is available for a service, systemd supports the init scripts of System V init. Also, it takes the file systems to be mounted on startup from the /etc/fstab file.

Jobs and Transactions

systemd calls system state change requests jobs and puts them into a queue. systemd calls status change requests transactions.

If a unit is being started or stopped, it (and any units depending on it) is put into a temporary transaction. Then, systemd checks that the transaction is consistent (specifically, that no circular dependencies exist). If this is the case, systemd tries to repair the transaction by removing non-essential jobs (including those that lead to running services being stopped) in order to break the cycle.

Next, systemd checks if the jobs within the transaction conflict with other jobs that are already in the queue. If that is the case, the transaction is refused. Only if the transaction is consistent and the minimization of its impact on the system is complete, will the transaction proceed and its associated jobs be entered into the queue.

Unit Files

systemd uses a unified file format for its unit files. Only the details of the possible configuration settings differ. The basic file format is always the same.

systemd unit files are declarative, i.e., they describe what the desired configuration looks like, unlike System V init's init scripts, which contain executable code that tries to implement the desired configuration. Unit files may contain shell commands (e.g., to describe how a service should be started/stopped), but these are fairly self-explanatory.

Unit files are stored in three locations:

  1. /lib/systemd/system or /usr/lib/systemd/system The default unit files for distribution packages. These unit files have the lowest priority.
  2. /run/systemd/system The dynamically generated runtime unit files.
  3. /etc/systemd/system The local configuration system administrator units. These unit files have the highest priority.

Unit File Structure

You can view the outline for the basic syntax of a unit file by running man 5 systemd.unit.

Here is a sample unit file:

## This file is part of systemd.
#
## systemd is free software; you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as
## published by the Free Software Foundation; either version 2.1
## of the License, or (at your option) any later version.

[Unit]
Description=Console Getty
Documentation=man:agetty(8)
After=systemd-user-sessions.service plymouth-quit-wait.service
After=rc-local.service
Before=getty.target

[Service]
ExecStart=-/sbin/agetty --noclear --keep-baud console
 115200,38400,9600 $TERM
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=cons
TTYPath=/dev/console
TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes

[Install]
WantedBy=getty.target

A systemd unit file is generally subdivided into sections that start with a title in square brackets ([]), e.g., [Service]. All unit files include [Unit] and [Install] sections (some until files may not directly have an [Install] section, but are tied to a unit file that does). The [Unit] section contains general information about the unit, and the [Install] section provides details for its installation. Also, there are sections that are specific to the purpose of the unit.

These are some of the important directives that are used in the [Unit] section of a unit file:

Description=
A human readable name for the unit. This is used by systemd as the label for the unit, so the string should identify the unit, rather than describe it. This name will be used in status messages, so it should be capitalized and should not be a full sentence or phrase with a continuous verb.
ConditionPathExists=
Before starting a unit, verify that the specified condition is true. Checks whether there is a file (or directory) under the given absolute pathname. If not, the starting of the unit will be (mostly silently) skipped. However, all ordering dependencies of it are still respected. If there is a ! in front of the pathname, then a file (or directory) with that name must not exist. There are many other condition tests. Run man 5 systemd.unit for more information.
Documentation=
A space-separated list of URIs containing documentation for the unit or its configuration. The allowed protocol schemes include http:, https:, file:, info:, and man: (the latter three refer to locally-installed documentation). An empty value resets the list and all prior assignments will have no effect.
OnFailure=
A space-separated list of other units that will be activated if this unit transitions into the failed state. A service unit using Restart= enters the failed state only after the start limits are reached.
SourcePath=
The pathname of a configuration file from which this unit file has been generated. This is useful for tools that create unit files for systemd from external configuration files.

Blank lines and comment lines are ignored. Comment lines can start with a # or ;. Over-long lines can be broken up with a \ at the end of the line, which will be replaced by a space character when the file is read. File contents are case-sensitive.

Lines that are not section headers, empty lines, or comment lines contain options according to a ex_name=ex_value pattern. Various options may occur several times and systemd's handling of that depends on the option. Often, multiple options form a list. If you specify an empty value, all earlier settings will be ignored.

Options that are not listed in the documentation will be flagged with a warning by systemd and otherwise ignored. If a section or option name starts with X-, it is completely ignored (options in a X- section do not need their own X- prefix).

Yes/no settings in unit files can be given in a variety of ways. 1, true, yes, and on stand for yes. 0, false, no, and off stand for no.

Times can be specified in various ways, too. Simple integers will be interpreted as seconds. If you append a unit, then that unit applies. Allowed units include us, ms, s, min, h, d, and w in increasing sequence from microseconds to weeks (run man 7 systemd.time for more information). You can concatenate several time specifications (e.g., 10min 30s) and these times will be added.

Unit Types

The following until types are available in systemd:

.automount
An automount point for a file system. This declares that a mount point should be mounted on-demand, instead of when the system is booted. The names of these units result from a pathname transformation. The details of mounting must be described by a corresponding mount unit.
.device
A device file used by the kernel.
.mount
A mount point for a file system. The names of these units are derived from the pathname by means of replacing all forward slashes (/) with hyphens (-), and all other non-alphanumeric (as per ASCII) characters with a hexadecimal replacement, e.g., \x2d (the . character is only converted if it is the first character of a pathname). The name of the root directory (/) becomes -, but forward slashes at the start or end of all other names are removed. You can use the systemd-escape -p ex_object_path command to generate such a string (e.g., systemd-escape -p /dev/sdb) and the systemd-escape -pu ex_object_path command to revert it.
.path
Observes a file or directory on a file system, and starts another unit (by default, a .service unit of the same name) when, for example, changes to the file have been noticed, or a file has been added to an empty directory.
.scope
An externally created process.
.service
A process on the system that is executed and managed by systemd. This includes both background services that stay active for a long time, and processes that are only executed once. When a service is invoked by name, but no corresponding unit file can be found, systemd looks for a System V init script with the same name and generates a service unit for that service on-the-fly.
.slice
A grouping of units in a hierarchy. .slice units are used to manage system processes.
.snapshot
A saved instance of the state of the systemd manager.
.socket
A TCP/IP, UNIX Domain, or First In, First Out (FIFO) socket. systemd uses socket units to activate background services on-demand. Socket units always come with a corresponding .service unit that will be started when systemd notes activity on the socket in question.
.swap
A swap file or swap device. The names of these units result from a pathname transformation applied to the device file or filename in question.
.target
A target, or synchronization point, for other units during system boot or when transitioning into other system states. A grouping of units.
.timer
A unit that starts another unit (by default, a .service unit of the same name) at a certain point in time, or repeatedly at certain intervals. This makes systemd a replacement for cron and at.

Specifying Explicit Dependencies With Unit Files

Sometimes, it is necessary to specify explicit dependencies.

Various directives in the [Unit] section of a .service unit file allow you to do this. These include:

Requires=
Configures requirement dependencies on other units. If the current unit is activated, then the listed units are also activated. If one of the listed units is deactivated or its activation fails, then the current unit will also be deactivated (i.e., the current unit depends on the listed units).
The Requires= dependencies have nothing to do with the order in which the units are started or stopped. That can be separately configured with the After= or Before= directives. If no explicit order has been specified, systemd will start all units at the same time.
You can specify Requires= dependencies without changing a unit file. For example, you can create a directory called /etc/systemd/system/example.service.requires and add symbolic links to the desired unit files that example.service requires.
$ ls -l /etc/systemd/system/example.service.requires
lrwxrwxrwx 1 root root 34 Jul 17 15:56 network.target -> /lib/systemd/system/network.target
lrwxrwxrwx 1 root root 34 Jul 17 15:57 syslog.service -> /lib/systemd/system/syslog.service

The symbolic links above correspond to the following lines in the example.service unit file.

[Unit]
Requires=network.target syslog.service
Wants=
A weaker form of Requires=. This means that the listed units will be started together with the current unit, but if their activation fails, this has no influence on the process as a whole. This is the recommended method of making the start of one unit depend on the start of another unit.
With Wants=, you can also externally specify the dependencies by creating a directory, as demonstrated for the Requires= directive, e.g. (/etc/systemd/system/example.service.wants).
Conflicts=
A space-separated list of unit names. The reverse of Requires=. The units listed here will be stopped when the current unit is started, and vice versa.
Like the Requires= directive, the Conflicts= directive makes no stipulation as to the order in which units are started or stopped.
If a unit A conflicts with another unit B, and both are to be started at the same time, this operation fails if both units are an essential part of the operation. If one (or both) units are not essential parts of the operation, the operation is modified. Specifically, if only one unit is non-essential, that one will not be started. If both are non-essential, the unit mentioned in Conflicts= will be started and the unit whose unit file contains the Conflicts= directive will be stopped.
Before= and After=
These two settings expect a space-separated list of unit names. They configure ordering dependencies between units.
If example.service's unit file contains the Before=example_2.service option and both units are being started, the start of example_2.service will be delayed until example.service has been started.
After= is the inverse of Before=, i.e., if example_2.service's unit file contains the option After=example.service and both units are being started, the same effect results, i.e., the starting of example_2.service will be delayed until example.service has been started.
When deactivating units, the reverse order is observed. If a unit with a Before= or After= dependency on another unit is deactivated, while the other unit is being started, then the deactivation takes place before the activation, no matter which direction the dependency is pointing.

Unit File Customization

You can customize unit file-related settings without modifying the default unit files provided by your GNU/Linux distribution in /lib/systemd/system. For example, if you want to change some of the settings in an example.service unit file, you could do one of the following:

  • Copy your distribution's example.service file from /lib/systemd/system to /etc/systemd/system and make your desired customizations. This new unit file will override the one provided by your distribution in /lib/systemd/system.
  • Create a /etc/systemd/system/example.service.d directory containing a file, e.g., local.conf (the file can have a different name, but systemd requires that it end in .conf). The settings in local.conf will override the settings of the unit file with the same name in /lib/systemd/system (i.e., /lib/systemd/system/example.service).

    Settings listed in the /lib/systemd/system/example.service file, but not mentioned in /etc/systemd/system/example.service.d/local.conf, remain the same. Make sure to include any required section titles in /etc/systemd/system/example.service.d/local.conf, so that options are correctly identified. systemd makes no stipulation about the order in which .conf files are read. It is best to ensure that every option occurs in just a single file.

Sometimes, several services can use the same or a similar unit file, but it is best to avoid redundant unit files. To address this, systemd supports instantiation.

For example, if you have a unit file called getty@.service, you could configure a virtual console on /dev/tty2 by creating a symbolic link from getty@tty2.service to getty@.service. When this console is activated, systemd reads the getty@.service file and replaces the %I key (as well as some other sequences, and not just in template unit files) wherever it finds it, by whatever comes between @ and . in the name of the getty@tty2.service unit file (i.e., tty2). The result of that replacement is then put into force as the configuration.

Targets

systemd does away with the System V init concept of runlevels and replaces them with targets. Targets are synchronization points for other units during system boot or when transitioning into other system states. Essentially, it is a grouping of units (set of services).

While System V init allows only a relatively small number of runlevels and their configuration may be complicated, systemd makes it possible to easily define various targets. Unit files for targets do not have special options. The standard set of options for [Unit] and [Install] are sufficient.

These are common targets for systemd:

basic.target
Basic system startup is finished (i.e., the early boot stage is complete).
ctrl-alt-del.target
Executed when Control+Alt+Delete is pressed. Often, the same as reboot.target.
default.target
Target that systemd attempts to reach on system startup. Usually, the default target is either multi-user.target or graphical.target.
emergency.target
Starts a shell on the system console, for emergencies. Often, this is activated by means of the systemd.unit=emergency.target parameter on the kernel command line. This gives you nothing except for a shell, in contrast to rescue.target, which also does basic system initialization.
getty.target
Activates the statically-defined getty instances (for managing terminals). Corresponds to the getty lines in the /etc/inittab file on System V init.
graphical.target
Establishes a graphical login prompt. Depends on multi-user.target.
halt.target
Stops the system (without powering it down).
multi-user.target
Establishes a multi-user system without a graphical login prompt. Used by graphical.target.
network-online.target
Serves as a dependency for units that require network services (not ones that provide network services), e.g., mount units for remote file systems. How exactly the system determines whether the network is available or not depends on the method for network configuration.
poweroff.target
Stops the system and powers it down.
reboot.target
Restarts the system.
rescue.target
Performs basic system initialization and then starts a shell.

For backwards compatibility with System V init, systemd defines a number of targets that correspond to the classical runlevels. Each of these runlevels has a corresponding runlevel.target unit file (e.g., runlevel0.target) that is a symbolic link to the actual systemd target unit file (e.g., poweroff.target).

System V init Runlevel to systemd Target Mappings
System V init Runlevel systemd Target Comparable Symbolic Link Target
0 poweroff.target runlevel0.target
1 rescue.target runlevel1.target
2 multi-user.target runlevel2.target
3 multi-user.target runlevel3.target
4 multi-user.target runlevel4.target
5 graphical.target runlevel5.target
6 reboot.target runlevel6.target

systemctl

The systemctl command is used to control systemd. The general format of the command is:

systemctl ex_subcommand ex_parameters

systemctl has useful options. For example, --failed (or --state=failed) can be used to view all failed units.

Often, unit names are expected as parameters. These can be specified either with a filename extension (example.service) or without (example). In the latter case, systemd appends an extension that it considers appropriate.

There are many subcommands, and each subcommand has different parameters and options. These are some of the most useful systemctl subcommands.

Unit Commands

systemctl list-units
List units that systemd currently has in memory. By default, only units that are active, have pending jobs, or have failed are shown. This can be changed with the --all option.
You can specify a unit type with the -t (--type=) option (e.g., systemctl list-units -t target, which is similar to the runlevel or who -r commands). You can use a comma-separated list of unit types with this option, as well (e.g., systemctl list-units -t service,socket).
Shell search patterns are accepted.
systemctl list-sockets
List socket units currently in memory, ordered by the listening address.
Shell search patterns are accepted.
systemctl list-timers
List timer units currently in memory, ordered by the time they elapse next.
Shell search patterns are accepted.
# systemctl start ex_unit...
Start a unit.
Shell search patterns are accepted. The search patterns only work for units that systemd knows about. Inactive units that are not in a failed stated will not be searched, nor will units instantiated from templates whose exact names are not known before the instantiation.
# systemctl stop ex_unit
Stop a unit(s).
Shell search patterns are accepted.
# systemctl reload ex_unit...
Reload a unit.
This command causes a unit to re-read its service-specific configuration file. What actually happens depends on the unit in question (usually, it involves a SIGHUP command). You can configure this behavior in the unit file itself.
The configuration here is of the background services themselves, not the configuration of the services from systemd's point-of-view. If you want systemd to reload its own configuration file with respect to the service(s), you must use the # systemctl daemon-reload command.
Shell search patterns are accepted.
# systemctl restart ex_unit...
Stop and then start a unit. If ex_unit is not already running, it is just started.
Shell search patterns are accepted.
# systemctl try-restart ex_unit...
Stop and then start a unit if the unit is running.
Shell search patterns are accepted.
# systemctl reload-or-restart ex_unit...
Reload a unit, if it allows it. Otherwise, stop and then start it.
Shell search patterns are accepted.
# systemctl try-reload-or-restart ex_unit...
Reload a unit if it allows it. Otherwise, stop and then start it, but do not start it if it is not already running.
Shell search patterns are accepted.
# systemctl isolate example.target
Start the unit specified on the command line and its dependencies and stop all others, unless they have IgnoreOnIsolate=yes set. This is similar to changing the runlevel on a System V init system.
# systemctl kill ex_unit...
Kill a unit.
systemctl kill sends a signal to one or several processes of the unit. This is distinct, and more specific, than using commands like killall and pkill. To make the command more granular, you can use the --kill-who= option to specify which process of a unit is targeted (accepted values include main, control, and all; all is the default option).
You can specify which signal systemctl kill sends by using the --signal= option.
Shell search patterns are accepted.
systemctl status
Show system status.
You can pass systemctl status a specific unit(s) or PID(s) as an argument to only see the status of that unit(s) or PID(s), as well as its most recent log entries. The log excerpt is usually abridged to 10 lines and long lines will be shortened. This can be changed by using the --lines or --full options.
Shell search patterns are accepted.
systemctl cat ex_unit...
Display the backing file(s) for a unit, including fragments in configuration directories specifically for that unit (e.g., /etc/systemd/system/example.service.d). Comments with the filenames in question are inserted for clarity in the command's output.
Shell search patterns are accepted.
systemctl help ex_unit...
Display manual pages for a unit. ex_unit can be a unit name or a process ID (PID).
Shell search patterns are accepted.

Unit File Commands

systemctl list-unit-files
View all available unit files on the system, as well as their enablement state.
Each background service available in systemd needs a corresponding .service until file (e.g., example.service), and this file needs to be placed in the appropriate location (e.g., /etc/systemd/system). Then, it should appear when you run systemctl list-unit-files. By default, a newly installed service will be disabled, which means that the unit is available, but not automatically started when the system boots.
Shell search patterns are accepted as arguments to have systemctl list-unit-files only show units that match the specified pattern.
# systemctl enable ex_unit...
Enable a unit. ex_unit can be a unit name or unit path.
Enabling a unit means that it will automatically start at boot time. After an enable, systemd does the equivalent of a # systemctl daemon-reload. If you want the service to be immediately started, as well, you can add the --now option to this command.
systemctl enable creates a symbolic link from the target unit's wants directory that is specified in example.service's [Install] section (e.g., /etc/systemd/system/multi-user.target.wants/example.service) to example.service's unit file (e.g., /etc/systemd/system/example.service).
# systemctl enable example.service
Created symlink from /etc/systemd/system/multi-user.target.wants/example.service to /etc/systemd/system/example.service

The /etc/systemd/system/example.service file has a section stating the following:

[Install]
WantedBy=multi-user.target

A service can be started without first being enabled.

# systemctl disable ex_unit...
Disable a unit.
Disabling a unit means that it will not automatically start at boot time. After a disable, systemd does the equivalent of a # systemctl daemon-reload. If ex_unit is currently running, it will not be stopped by this command. However, you can immediately stop it by adding the --now option.
# systemctl reenable ex_unit...
Re-enable a unit. This command is equivalent to disabling and enabling the unit in question. It is useful to reset the symbolic links a unit file is enabled with to the defaults configured in its [Install] section.
# systemctl mask ex_unit...
Mask a unit. This is a stronger version of the disable subcommand, since it prohibits all kinds of activation of the unit.
systemd accomplishes this by symbolically linking the name of the unit file in /etc/systemd/system to /dev/null. Therefore, if you need to mask a unit, first remove, move, or rename the unit file in question in /etc/systemd/system, so that systemd can create the appropriate symbolic link.
# sytemctl unmask ex_unit...
Unmask a unit.
systemctl get-default
Display the default systemd target. This returns the target unit name default.target is aliased (symbolically linked) to.
# systemctl set-default example.target
Set the default target to boot into.
This command works by creating a symbolic link from /etc/systemd/system/default.target to /lib/systemd/system/example.target (e.g., # ln -fs /lib/systemd/system/example.target /etc/systemd/system/default.target; the -f (--force) option removes the existing destination file). This is equivalent to the initdefault line in the /etc/inittab file in a System V init system.

Manager Lifecycle Commands

# systemctl daemon-reload
Reload systemd manager configuration.
This command causes systemd to reload its configuration, which includes regenerating unit files that have been created at runtime from other configuration files on the system, and reconstructing the dependency tree. This command is implicitly run when you enable or disable a unit.
# systemctl daemon-reexec
Re-execute the systemd manager.
This command restarts the systemd program, which saves systemd's internal state and restores it later. Mostly, this is useful if a new version of systemd has been installed (or for debugging systemd). Communication channels that systemd manages on behalf of background services will persist across the restart.

System Commands

systemctl is-system-running
Checks whether the system is operational.
Possible answers include:
  • degraded The system is operational, but one or more units are in a failed state.
  • initializing Early bootup (the basic.target, rescue.target, or emergency.target targets have not yet been reached).
  • maintenance One of the rescue.target or emergency.target targets is active.
  • offline The manager is not running. Specifically, this is the operational state if an incompatible program is running system manager (PID 1).
  • running The system is fully operational.
  • starting Late bootup (there are still jobs in the queue or one of the rescue targets has not been reached yet).
  • stopping The manager is shutting down.
  • unknown The operational state could not be determined due to lack of resources or another error cause.
# systemctl default
Enter default mode. Equivalent to # systemctl isolate default.target.
# systemctl rescue
Enter rescue mode. Equivalent to # systemctl isolate rescue.target.
# systemctl emergency
Enter emergency mode. Equivalent to # systemctl isolate emergency.target.
# systemctl halt
Shut down and halt the system. Mostly equivalent to # systemctl start halt.target --job-mode=replace-irreversibly --no-block, but also prints a wall message to all users.
# systemctl poweroff
Shut down and power-off the system. Mostly equivalent to # systemctl start poweroff.target --job-mode=replace-irreversibly --no-block, but also prints a wall message to all users.
# systemctl reboot
Shut down and reboot the system. Mostly equivalent to # systemctl start reboot.target --job-mode=replace-irreversibly --no-block, but also prints a wall message to all users.

systemd-analyze

The systemd-analyze command can be used to analyze and debug the systemd system manager.

systemd-analyze
Display performance stats regarding system boot, view trace and current state information.
systemd-analyze blame
Display how long each process took to start.

systemd-analyze has many useful subcommands, as well. Run man systemd-analyze for more information.

Documentation

For more information on systemd, you can refer to its various man pages by running these commands:

  • man systemd
  • man systemd-system.conf
  • man systemd.unit
  • man systemd.directives
  • man systemd.time
  • man systemctl
  • man systemd-analyze

Also, you can check out the systemd.io site from the systemd project.

System V init (SysV init)

Most GNU/Linux distributions use systemd as their initialization system. However, not all members of the GNU/Linux community like systemd and there are distributions that have retained System V init (SysV init) as their initialization system of choice. Also, it is advantageous to understand how SysV init works, either for backwards-compatibility, or in case you encounter a SysV init GNU/Linux distribution.

As in systemd, a service is a program that runs as a background process. Runlevels describe the system's state and the services that it offers.

The init Process

Exactly how SysV init is implemented will depend on your GNU/Linux distribution of choice.

Debian

The Debian SysV init process was as follows:

  • A boot script (e.g., /etc/init.d/rcS) was run to prepare the system.
  • The /etc/inittab file was processed to determine the appropriate runlevel and scripts.
  • Scripts in /etc/init.d were run from symbolic links in the appropriate runlevel directories in the /etc directory (i.e., the /etc/rcx.d directories).

Fedora

The Fedora SysV init process was as follows:

  • A boot script (e.g., /etc/rc.d/init.d/boot) was run to prepare the system.
  • The /etc/inittab file was processed to determine the appropriate runlevel and scripts.
  • Scripts in /etc/rc.d/init.d were run from symbolic links in the appropriate runlevel directories in the /etc/rc.d directory (i.e., the /etc/rc.d/rcx.d directories).

/etc/inittab

The /etc/inittab file is used to configure what happens in each runlevel. Each line that is either not empty or a comment (i.e., a line that starts with a #) consists of four fields separated by colons. For example:

l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
#l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6

The four fields are:

  1. Label
  2. Runlevels
  3. Action
  4. Command
Label
The first field's purpose is to uniquely identify the line. You may pick an arbitrary combination of up to four characters. It is probably best to use only letters and digits. For terminals, the label corresponds to the name of the device file in question, but without the tty at the beginning.
Runlevels
The second field specifies the runlevels this line applies to. Usually, they are named with digits, and the line in question will be considered in all runlevels whose digit appears in this field.
Action
The third field specifies how to handle the line. The most important possibilities include:
  • ctrlaltdel Specifies what the system should do if the init process is being sent a SIGINT signal, which usually happens if the Control+Alt+Delete keyboard combination is pressed (e.g., ca::ctrlaltdel:/sbin/shutdown -r -t 4 now).
  • initdefault The runlevel field of this line specifies which runlevel the system should try for after each boot (e.g., id:5:initdefault:). If this entry, or the whole /etc/inittab file is missing, you will need to state a run level on the console.
  • powerwait, powerfail, powerokwait , and powerfailnow are used to interface SysV init with uninterruptible power supplies (UPSs) and define what should happen when a power failure occurs.
  • respawn The process described by this line is executed once when the system changes to the runlevel in question, and init waits for it to finish.
  • wait The process described by this line is executed once during system startup. init waits for it to finish. The runlevel field on this line will be ignored, since this command will be executed at every system startup.
# What to do when power fails or returns
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
#pn::powerfail:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop
Command
The fourth field describes the command to be executed. It extends to the end of the line.

/etc/inittab tells init which runlevel login processes are started at login to prompt the user to enter a username and password:

1:2345:respawn:/sbin/mingetty --noclear tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

If you make a change to /etc/inittab, you need to tell init that the changes have been made and to re-read the configuration by entering the # telinit q command.

The init Scripts

The system processes on the GNU/Linux system are started and stopped using an init script. An init script is used by the init process to start processes on system boot and whenever the current runlevel is changed. init scripts support parameters like:

  • start
  • stop
  • restart
  • reload
  • status
Debian init Scripts

For a Debian init system, init scripts were stored in /etc/init.d. Inside of the /etc directory, there were a series of directories named rc0.d through rc6.d that were each associated with a particular runlevel (rc is short for runcom, which means run commands). These rc directories contained symbolic links that pointed to the init scripts for system daemons that were located in /etc/init.d.

A boot script (usually /etc/init.d/rcS, but whose exact name was specified in /etc/inittab) performed tasks like:

  • Checking and correcting file systems specified in /etc/fstab
  • Initializing the system name and Linux clock
  • Completing important prerequisites for stable system operation

The /etc/init.d/rc script was used to switch between runlevels while the system was running. This was the script that the telinit command called to change runlevels.

Fedora init Scripts

For a Fedora init system, init scripts were stored in /etc/rc.d/init.d. Inside of the /etc/rc.d directory, there were a series of directories named rc0.d through rc6.d that were each associated with a particular runlevel. These rc directories contained symbolic links that pointed to the init scripts for system daemons that were located in /etc/rc.d/init.d.

A boot script (usually /etc/rc.d/init.d/boot, but whose exact name should was specified in /etc/inittab) performed tasks like:

  • Checking and correcting file systems specified in /etc/fstab
  • Initializing the system name and Linux clock
  • Completing important prerequisites for stable system operation

The /etc/rc.d/init.d/rc script was used to switch between runlevels while the system was running. This was the script that the telinit command called to change runlevels.

The rcx.d Directories

If you look inside of an rcx.d directory (where x is a number corresponding to a runlevel), there will be see two symbolic links for each system process. One symbolic link starts with a S, and the other starts with a K. The symbolic links that start with a S are used to start a service, while the symbolic links that start with a K are used to stop (kill) a service.

When the init process calls the rc script and sends it a runlevel to change to, the rc script runs all of init.d scripts in lexicographical order from the symbolic links in the corresponding rcx.d directory to start and stop services as appropriate for the runlevel being entered. These are the scripts employed when switching between runlevels on-the-fly.

The S or K letter is followed by a number and the name of the init script. The numbers in filenames are important, as they determine the sequence in which the scripts are run. This ensures that services that other services depend on are started first.

When init calls the rc script to switch runlevels, the rc script first looks at the rcx.d directory for the current runlevel and compares it with the rcx.d directory for the runlevel it is going to switch the system to. If there is a kill symbolic link for the already running service in the rcx.d directory for the current runlevel and a start symbolic link for the same service in the rcx.d directory for the new runlevel, the rc script leaves the service running because it should be running in both runlevels.

On the other hand, if there is a kill symbolic link for the service in the rcx.d directory for the current runlevel, but there is no start symbolic link for the same service in the rcx.d directory for the new runlevel, the rc script runs the kill script to stop the service. Conversely, if there is a start symbolic link for the service in the rcx.d directory for the new runlevel and there is no start symbolic link for the same service in the rcx.d directory for the current runlevel, the rc script runs the start script to start the service.

Runlevels

Runlevels describe the system's state and the services that it offers.

The SysV init runlevels are:

0
System poweroff.
1
Single-user mode with no networking. Also referred to as runlevel S or single.
2
Multi-user mode with no networking.
3
Multi-user mode with networking.
4
Unused. May be individually configured if required.
5
Same as runlevel 3, but with graphical user interface (GUI) login.
6
System reboot.

These runlevels derive from the Linux Standard Base (LSB), but not all GNU/Linux distributions enforce them. You can use runlevels 7 through 9, but you will need to configure them yourself.

Also, there are on-demand runlevels A, B, and C. You can create entries in /etc/inittab that are meant for any of these three runlevels with the ondemand action:

ex_label:AB:ondemand:ex_code

Then, when you issue a command line # telinit A, the entry above will be executed, but the actual runlevel will not change.

The system runs through the S runlevel during startup, before it changes over to runlevels 2 through 5. If you put the system into runlevel 1, you will end up in runlevel 5 (if you are using a GUI-based system).

In single-user mode (i.e., runlevel S/single/1), only the system administrator may work on the system console. There is no way to change to other virtual consoles. The single-user mode is normally used for administrative work, especially if the file system needs to be repaired or the quota system established.

By default, passing the S option to the kernel on the command line will mount the root file system as read-only on booting. After switching to single-user mode after a system boots up, you can also disable writing to the root file system on-the-fly using the remount and ro mount options (e.g., mount -o remount,ro /).

To remount a file system as read-only while the system is running, no process may have opened a file on the file system for writing (you can use the lsof command to display open files on a file system). All such programs must be terminated using the kill command.

To leave single-user mode, it is best to reboot the system (# reboot or # shutdown -r now).

runlevel

Both the current and previous runlevel of a system can be determined with the runlevel command. A N for the previous runlevel means that the current runlevel was entered right after the system start (the N stands for None).

$ runlevel
N 5

The who -r command will display the current runlevel, as well.

$ who -r
         run-level 5  2020-08-20 08:10

telinit

The telinit command changes the System V runlevel.

# telinit ex_runlevel

When you change runlevels, the init process runs the rc script, which shuts down services associated with the current runlevel and starts scripts associated with the runlevel you are changing to.

System V init Commands

There are other commands that can be used to interact with SysV init.

Parameters

As previously mentioned, init scripts accept several parameters (e.g., start, stop). The exact path to each script will depend on the GNU/Linux distribution that you are using.

# /etc/init.d/ex_script start or # /etc/rc.d/init.d/ex_script start
Start an init script.
# /etc/init.d/ex_script stop or # /etc/rc.d/init.d/ex_script stop
Stop an init script.
# /etc/init.d/ex_script restart or # /etc/rc.d/init.d/ex_script restart
Restart an init script. Restarting a service stops and restarts it.
# /etc/init.d/ex_script reload or # /etc/rc.d/init.d/ex_script reload
Reload an init script. Reloading a service leaves it running, but has it re-read its configuration file.
/etc/init.d/ex_script status or /etc/rc.d/init.d/ex_script status
Display the status of an init script service.

service

Interacting with services via init scripts and parameters is basic. On a modern SysV init system, it is preferable to use the service command instead.

service ex_script_name ex_command

ex_command can be any of the previously mentioned init script parameters start, stop, restart, reload, and status.

update-rc.d (Debian)

GNU/Linux distributions like Debian use the update-rc.d command to install and remove init script links. The command reads the information in the INIT INFO block of an init script to determine which runlevels the associated service should run in by default.

# update-rc.d ex_script_name enable
Enable and start a service.
This command enables the daemon specified at the runlevels listed in the Default-Start directive of the INIT INFO block of the service’s init script. It also disables the daemon at the runlevels listed in the Default-Stop directive of the INIT INFO block.
# update-rc.d ex_script_name disable
Disable and stop a service.
# update-rc.d ex_script_name start ex_priority_number ex_runlevels . stop ex_priority_number ex_runlevels .
Change the default runlevels for a service (e.g., # update-rc.d apache2 start 20 2 3 4 5 . stop 80 0 1 6 .). This command re-creates the appropriate start and kill script symbolic links in the various rcx.d directories saved in /etc.

chkconfig (Fedora)

GNU/Linux distributions like Fedora use the chkconfig command to update and query runlevel information for system services.

chkconfig or chkconfig -l
List each service and what runlevel they are configured to run at. -l is short for --list. The -l option can be passed the name of a specific script (service) to list only that service's current runlevel.
# chkconfig ex_script_name on
Enable and start a service.
# chkconfig ex_script_name off
Disable and stop a service.
# chkconfig --levels ex_runlevels ex_script_name
Change the default runlevels for a service (e.g., # chkconfig --level 35 iptables on and # chkconfig --level 01246 iptables off). ex_runlevels is given as a string of numbers from 0 to 6. For example, --level 35 specifies runlevels 3 and 5.

Documentation

More information can be found on the commands discussed above by examining the Linux User's Manual, either at the command line or online.

For more on SysV init, its history, and how it fits into the world of GNU/Linux system initialization, check out the following posts:

Why Linux’s systemd Is Still Divisive After All These Years | How-To Geek

Init system support in Debian [LWN.net]

Avatar

Enjoyed this post?

Subscribe to the feed for the latest updates.