Linux Init Service介绍

Published on 2016 - 07 - 19

Overview

Ongoing services offered by a Linux system, such as access to a printer service or login service, are typically implemented by what is referred to as a daemon process. Most Linux systems have a method of managing each daemon process as a service using one of several popular initialization systems (also referred to as init systems). Advantages of using init systems include the ability to do the following:

  • Identify runlevels — Put together sets of services in what are referred to as runlevels or targets
  • Establish dependencies — Set service dependencies so, for example, a service that requires network interfaces won't start until all network startup services have started successfully
  • Set the default runlevel — Select which runlevel or target starts up when the system boots
  • Manage services — Run commands that tell individual services to start, stop, pause, restart, or even reload configuration files

Several different init systems are in use with Linux systems today:

  • SysVinit — This traditional init system was created for UNIX System V systems in the early 1980s. It offers an easy-to-understand method of starting and stopping services based on runlevel. Most UNIX and Linux services based on runlevel. Most UNIX and Linux systems up until a few years ago used SysVinit.
  • Upstart — Popularized in Ubuntu and used briefly in Fedora and RHEL, this init system improved handling of dependencies between services and could substantially improve system startup time. It has only recently been supplanted by systemd in Fedora and RHEL, and will soon do so in Ubuntu.
  • Systemd — The latest versions of Fedora and RHEL use the systemd init system. It is the most complex of the init systems, but also offers much more flexibility. Systemd not only offers features for starting and working with services, but also lets you manage sockets, devices, mount points, swap areas, and other unit types.

Initialization Daemon: init or systemd

The initialization daemon can be thought of as the “mother of all processes.” This daemon is the first process to be started by the kernel on the Linux server. For Linux distributions that use SysvInit or Upstart, the init daemon is literally named init. For systemd, the init daemon is named systemd.

The Linux kernel has a process ID (PID) of 0. Thus, the initialization process (init or systemd) daemon has a parent process ID (PPID) of 0, and a PID of 1. Once started, init is responsible for spawning (launching) processes configured to be started at the server's boot time, such as the login shell (getty or mingetty process). It is also responsible for managing services.

The Linux init daemon was based upon the UNIX System V init daemon. Thus, it is called the SysVinit daemon. However, it was not the only classic init daemon. The init daemon is not part of the Linux kernel. Therefore, it can come in different flavors, and Linux distributions can choose which flavor to use. Another classic init daemon was based on Berkeley UNIX, also called BSD. Therefore, the two original Linux init daemons were BSD init and SysVinit.

The classic init daemons worked without problems for many years. However, these daemons were created to work within a static environment. As new hardware, such as USB devices, came along, the classic init daemons had trouble dealing with these and other hot-plug devices. Computer hardware had changed from static to event-based. New init daemons were needed to deal with these fluid environments.

In addition, as new services came along, the classic init daemons had to deal with starting more and more services. Thus, the entire system initialization process was less efficient and ultimately slower.

The modern initialization daemons have tried to solve the problems of inefficient system boots and non-static environments. Two of these init daemons are the Upstart init and systemd daemons. Recently, Ubuntu, RHEL, and Fedora distributions have made the move to the newer systemd daemon while maintaining backward compatibility to the classic SysVinit, Upstart, or BSD init daemons.

Upstart, available at upstart, was originally developed by Canonical, the parent of the Ubuntu distribution. Earlier releases of other distributions adopted it for a short time before transitioning to systemd, including:

RHEL version 6
Fedora versions 9 through 14
Ubuntu versions 6–14.10
openSUSE versions 11.3–12.1

systemd: A new daemon, systemd, available at Systemd, was written primarily by Lennart Poettering, a Red Hat developer. Including:

Fedora 15
Red Hat Enterprise Linux 7
OpenSUSE 12.2
Ubuntu 15.04

In order to properly manage your services, you need to know which initialization daemon your server has. Figuring that out can be a little tricky. The initialization process running on a SysVinit or Upstart is named init. For the first systemd systems, it was also called init, but is now named systemd. Running ps -e can immediately tell you if yours is a Systemd system:

# ps -e | head
  PID TTY          TIME CMD
    1 ?        00:04:36 systemd
    2 ?        00:00:03 kthreadd
    3 ?        00:00:15 ksoftirqd/0

If your initialization process is init, look through the following to help determine your Linux server's initialization system:

  • Do your Linux distribution and version appear in the preceding list of Upstart adopters? If they do, your Linux init daemon is the Upstart init daemon.
  • Try searching your Linux distribution's init daemon for clues, using the strings and the grep commands. The following code example shows the init daemon on a Linux Mint distribution being searched for systemd and Upstart init daemon references. The search for systemd yields nothing. However, the search for Upstart produces results. Thus, in the second example, the Linux Mint distribution uses the Upstart init daemon.
$ sudo strings /sbin/init | grep -i systemd
$ sudo strings /sbin/init | grep -i upstart
upstart-devel@lists.ubuntu.com
UPSTART_CONFDIR
UPSTART_NO_SESSIONS

批注:Debian,Gentoo也都用inittab, Ubuntu在6.10之前也都用这个文件。不过现在,ubuntu标新立异越来越多,跟其它发行版不兼容了。安装了很多Linux发行版很难找到还在使用inittab了。所以inittab得介绍会以书本为主。

Classic init daemons

the SysVinit daemon and the BSD init daemon's configuration information is taken at boot time from the /etc/inittab file. The following is a classic SysVinit /etc/inittab file:

# cat /etc/inittab
# inittab  This file describes how the INIT process should set up
# Default runlevel. The runlevels used by RHS are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, no NFS (Same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
id:5:initdefault:
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
pf::powerfail:/sbin/shutdown -f -h +2
     "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c
     "Power Restored; Shutdown Cancelled"
# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty 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
# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm -nodaemon

The /etc/inittab file tells the init daemon which runlevel is the default runlevel. A runlevel is a categorization number that determines what services are started and what services are stopped. In the preceding example, a default runlevel of 5 is set with the line id:5:initdefault:. Table shows the standard seven Linux runlevels:

Runlevel # Name Description
0 Halt All services are shut down and the sever is stopped
1 or S Single User Mode The root account is automatically logged in to the server. Other users cannot log in to the server. Only the command line interface is available. Network services are not started.
2 Multiuser Mode Users can log in to the server, but only the command line interface is available. On some systems, network interfaces and services are started; on others they are not. Originally, this runlevel was used to start dumb terminal devices so users could log in (but no network services were started).
3 Extended Multiuser Mode Users can log in to the server, but only the command line interface is available. Network interfaces and services are started. This is a common runlevel for servers.
4 User Defined Users can customize this runlevel.
5 Graphical Mode Users can log in to the server. Command line and graphical interfaces are available. Network services are started. This is a common runlevel for desktop systems.
6 Reboot The server is rebooted.

The only runlevels that should be used in the /etc/inittab file are 2 through 5. The other runlevels could cause problems. For example, if you put runlevel 6 in the /etc/inittab file as the default, when the server reboots, it would go into a loop and continue to reboot over and over again.

The runlevels are not only used as a default runlevel in the /etc/inittab file. They can also be called directly using the init daemon itself. Thus, if you want to immediately halt your server, you type init 0 at the command line:

# init 0
...
System going down for system halt NOW!

To see your Linux server's current runlevel, simply type in the command runlevel. The first item displayed is the server's previous runlevel, which in the following example is 5. The second item displayed shows the server's current runlevel, which in this example is 3.

$ runlevel
5 3

How does the server know which services to stop and which ones to start when a particular runlevel is chosen? When a runlevel is chosen, the scripts located in the /etc/rc.d/rc#.d directory (where # is the chosen runlevel) are run. These scripts are run whether the runlevel is chosen via a server boot and the /etc/inittab initdefault setting, or when the init or telinit command is used. For example, if runlevel 5 is chosen, then all the scripts in the /etc/rc.d/rc5.d directory are run;

# ls /etc/rc.d/rc5.d
K01smolt                     K88wpa_supplicant   S22messagebus
K02avahi-dnsconfd            K89dund             S25bluetooth
K02NetworkManager            K89netplugd         S25fuse
K02NetworkManagerDispatcher  K89pand             S25netfs
K05saslauthd                 K89rdisc            S25pcscd
K10dc_server                 K91capi             S26hidd
K10psacct                    S00microcode_ctl    S26udev-post
K12dc_client                 S04readahead_early  S28autofs
K15gpm                       S05kudzu            S50hplip
K15httpd                     S06cpuspeed         S55cups
K20nfs                       S08ip6tables        S55ssh

Notice that some of the scripts within the /etc/rc.d/rc5.d directory start with a K and some start with an S. The K refers to a script that will kill (stop) a process. The S refers to a script that will start a process. Also, each K and S script has a number before the name of the service or daemon they control. This allows the services to be stopped or started in a particular controlled order. You would not want your Linux server's network services to be started before the network itself was started.

Actually, the files in the /etc/rc.d/rc#.d directories are not scripts, but instead symbolic links to scripts in the /etc/rc.d/init.d directory. Thus, there is no need to have multiple copies of particular scripts.

# ls -l /etc/rc.d/rc5.d/K15httpd
lrwxrwxrwx 1 root root 15 Oct 10 08:15
 /etc/rc.d/rc5.d/K15httpd -> ../init.d/httpd
# ls /etc/rc.d/init.d
anacron            functions  multipathd               rpcidmapd
atd                fuse       netconsole               rpcsvcgssd
auditd             gpm        netfs                    saslauthd
autofs             haldaemon  netplugd                 sendmail
avahi-daemon       halt       network                  setroubleshoot
avahi-dnsconfd     hidd       NetworkManager           single
bluetooth          hplip      NetworkManagerDispatcher smartd
btseed             hsqldb     nfs                      smolt
bttrack            httpd      nfslock                  spamassassin
capi               ip6tables  nscd                     squid
ConsoleKit         iptables   ntpd                     sshd
cpuspeed           irda       pand                     syslog
crond              irqbalance pcscd                    tux
cups               isdn       psacct                   udev-post
cups-config-daemon killall    rdisc                    vncserver
dc_client          kudzu      readahead_early          winbind
dc_server          mcstrans   readahead_later          wpa_supplicant
dhcdbd             mdmonitor  restorecond              xfs
dund               messagebus rpcbind                  ypbind
firstboot          microcode  rpcgssd                  yum-updatesd

Notice that each service has a single script in /etc/rc.d/init.d. There aren't separate scripts for stopping and starting a service. These scripts will stop or start a service depending upon what parameter is passed to them by the init daemon.

The following is a partial example of the httpd script on a Linux system that uses the SysVinit daemon. It contains a case statement for handling the parameter ($1) that was passed to it, such as start, stop, status, and so on.

# cat /etc/rc.d/init.d/httpd
#!/bin/bash
#
# httpd        Startup script for the Apache HTTP Server
#
# chkconfig: - 85 15
# description: Apache is a World Wide Web server.
#              It is used to serve \
#              HTML files and CGI.
# processname: httpd
# config: /etc/httpd/conf/httpd.conf
# config: /etc/sysconfig/httpd
# pidfile: /var/run/httpd.pid
# Source function library.
. /etc/rc.d/init.d/functions
...
# See how we were called.
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status $httpd
        RETVAL=$?
        ;;
...
esac
exit $RETVAL

Upstart init daemon

The primary difference between the classics and Upstart is the handling of stopping and starting services. The SysVinit daemon was created to operate in a static environment. The Upstart init daemon was created to operate in a flexible and ever-changing environment.

With SysVinit, services are stopped and started based upon runlevels. The Upstart init daemon is not concerned with runlevels but with system events. Events are what determine when services are stopped and/or started.

An event is a Linux server occurrence that triggers a needed system state change, which is communicated to the Upstart init daemon. The following are examples of system events:

  • The server boots up.
  • The init command is used.
  • A USB device is plugged into the server.

The classic init daemons could handle the first two event examples, but they could not deal well with the third.

Upstart handles services through defined jobs. An Upstart job can be either a task or a service. A task performs a limited duty, completes its work, and then returns to a waiting state. A service, on the other hand, is a long-running program that never finishes its work or self-terminates, but instead stays in a running state. A daemon is an example of an Upstart service job.

The example that follows shows several Upstart jobs that include both task and service jobs. The task jobs are in a stop/waiting state, such as the task rc. The service jobs are in a start/running state, such as the cups daemon.

$ initctl list
avahi-daemon start/running, process 456
mountall-net stop/waiting
rc stop/waiting
rsyslog start/running, process 411
...
ssh start/running, process 405
udev-fallback-graphics stop/waiting
control-alt-delete stop/waiting
hwclock stop/waiting
mounted-proc stop/waiting
network-manager start/running, process 458

These various jobs are defined via a jobs definition file. All the job definition files are located in the /etc/init directory as shown here:

$ ls /etc/init
acpid.conf               networking.conf
alsa-restore.conf        network-interface.conf
alsa-store.conf          network-interface-security.conf
anacron.conf             network-manager.conf
control-alt-delete.conf  procps.conf
cron.conf                rc.conf
cups.conf                rcS.conf

The Upstart init daemon depends upon events to trigger certain services to start, stop, restart, and so on. Events are either communicated to the Upstart init daemon or created by the Upstart daemon. This is called an emitted event. The actions taken when an event is emitted are dependent upon the settings in a job's configuration file. Consider the following Network Manager daemon's configuration file:

$ cat /etc/init/network-manager.conf
# network-manager - network connection manager
#
# The NetworkManager daemon manages the system's network connections
# automatically switching between the best available.
description     "network connection manager"
start on (local-filesystems and started dbus)
stop on stopping dbus
expect fork
respawn
exec NetworkManager
$

From the example, you can see that there are two events that must take place in order to trigger the Upstart init daemon to start the NetworkManager daemon:

  • The local-filesystems event—The Upstart init daemon emits this event when all the local filesystems in the /etc/fstab configuration file have been mounted.
  • The dbus daemon started event—The Upstart init daemon emits this started event when the dbus daemon has reached the start/running state.

Thus, when these two events occur, the Upstart init daemon is informed and starts the NetworkManager daemon.

Learning Upstart's backward compatibility to SysVinit

Upstart provides backward compatibility to the SysVinit daemon. This has allowed the Linux distributions time to slowly migrate to Upstart.

The /etc/inittab file is still on some distributions. RHEL 6 and the Fedora distributions still using Upstart use /etc/inittab to boot to the default runlevel listed. The example of the /etc/inittab file that follows comes from a server running a version of Fedora, which uses the Upstart init daemon.

$ cat /etc/inittab
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
...
#
id:5:initdefault:

As you can see from the comment lines in the /etc/inittab file, the only thing this file is used for on Linux distributions that maintain it is to change the default runlevel at server boot time.

System initialization compatibility to SysVinit is maintained on some distributions, such as Ubuntu, via the /etc/init/rc-sysinit.conf configuration file. This is one of the configuration files used at system boot. In the example that follows, Upstart checks for a /etc/inittab file and also runs any scripts that may still be in the /etc/init.d/rcS directory:

$ cat /etc/init/rc-sysinit.conf
# rc-sysinit - System V initialisation compatibility
#
# This task runs the old System V-style system init scripts,
# and enters the default runlevel when finished.
...
start on (filesystem and static-network-up) or failsafe-boot
stop on runlevel
# Default runlevel, this may be overriden on the kernel command-line
# or by faking an old /etc/inittab entry
env DEFAULT_RUNLEVEL=2
emits runlevel
...
task
script
# Check for default runlevel in /etc/inittab
    if [ -r /etc/inittab ]
    then
      eval "$(sed -nre 's/^[^#][^:]*:([0-6sS]):initdefault:
.*/DEFAULT_RUNLEVEL="\1";/p' /etc/inittab || true)"
    fi
    # Check kernel command-line for typical arguments
    for ARG in $(cat /proc/cmdline)
    do
      case "${ARG}" in
      -b|emergency)
          # Emergency shell
          [ -n "${FROM_SINGLE_USER_MODE}" ] || sulogin
          ;;
       [0123456sS])
          # Override runlevel
          DEFAULT_RUNLEVEL="${ARG}"
          ;;
      -s|single)
          # Single user mode
          [ -n "${FROM_SINGLE_USER_MODE}" ] || DEFAULT_RUNLEVEL=S
          ;;
      esac
    done
    # Run the system initialisation scripts
    [ -n "${FROM_SINGLE_USER_MODE}" ] || /etc/init.d/rcS
    # Switch into the default runlevel
    telinit "${DEFAULT_RUNLEVEL}"
end script

As you can see from the preceding example, the runlevel concept is maintained in the Upstart init daemon. In fact, there is even a runlevel signal that Upstart can emit.

# man -k "event signal"
control-alt-delete   (7) - ... console press of Control-Alt-Delete
keyboard-request     (7) - ... console press of Alt-UpArrow
power-status-changed (7) - ... change of power status
runlevel             (7) - ... change of system runlevel
started              (7) - ... a job is running
starting             (7) - ... a job is starting
startup              (7) - ... system startup
stopped              (7) - ... a job has stopped
stopping             (7) - ... a job is stopping

Switching to a different runlevel is still allowed through the init or telinit commands. Any runlevel event is handled by the rc task.

$ initctl status rc
rc stop/waiting

The rc task job's configuration file is shown next. When a runlevel event is emitted, the rc configuration file calls the /etc/rc.d/rc script. When called, the /etc/rc.d/rc script runs the scripts located in the /etc/rc.d/rc#.d, where # is the chosen runlevel. This provides runlevel backward compatibility to SysVinit.

$ cat /etc/init/rc.conf
# rc - System V runlevel compatibility
#
# This task runs the old sysv-rc runlevel scripts.  It
# is usually started by the telinit compatibility wrapper.
start on runlevel [0123456]
stop on runlevel [!$RUNLEVEL]
task
export RUNLEVEL
console output
exec /etc/rc.d/rc $RUNLEVEL

To change the default runlevel on an Ubuntu distribution that uses Upstart, edit /etc/init/rc-sysinit.conf and change the line env DEFAULT_RUNLEVEL=# where # is 2 to 5. However, remember that the runlevels 2–5 on Ubuntu are equivalent to SysVinit runlevel 5. Therefore, this activity is rather pointless.

在Ubuntu系统中/etc/inittab文件被替换成了/etc/init/rc-sysinit.conf

systemd initialization

With the SysVinit daemon, services are stopped and started based upon runlevels. The systemd is also concerned with runlevels, but they are called target units. Although the main job of systemd is to start services, it can manage other types of things called units. A unit is a group consisting of a name, type, and configuration file and is focused on a particular service or action. There are eight systemd unit types:

  • automount
  • device
  • mount
  • path
  • service
  • snapshot
  • socket
  • target

The two primary systemd units you need to be concerned with for dealing with services are service units and target units. A service unit is for managing daemons on your Linux server. A target unit is simply a group of other units.

The example that follows shows several systemd service units and target units. The service units have familiar daemon names, such as cups and sshd. Note that each service unit name ends with .service. The target units shown have names like sysinit. (sysinit is used for starting up services at system initialization.) The target unit names end with .target.

# systemctl list-units | grep .service
...
cups.service           loaded active running CUPS Printing Service
dbus.service           loaded active running D-Bus Message Bus
...
NetworkManager.service loaded active running Network Manager
prefdm.service         loaded active running Display Manager
remount-rootfs.service loaded active exited  Remount Root FS
rsyslog.service        loaded active running System Logging
...
sshd.service           loaded active running OpenSSH server daemon
systemd-logind.service loaded active running Login Service
...
# systemctl list-units | grep .target
basic.target           loaded active active  Basic System
cryptsetup.target      loaded active active  Encrypted Volumes
getty.target           loaded active active  Login Prompts
graphical.target       loaded active active  Graphical Interface
local-fs-pre.target    loaded active active  Local File Systems (Pre)
local-fs.target        loaded active active  Local File Systems
multi-user.target      loaded active active  Multi-User
network.target         loaded active active  Network
remote-fs.target       loaded active active  Remote File Systems
sockets.target         loaded active active  Sockets
sound.target           loaded active active  Sound Card
swap.target            loaded active active  Swap
sysinit.target         loaded active active  System Initialization
syslog.target          loaded active active  Syslog

The Linux system unit configuration files are located in the /lib/systemd/system and/etc/systemd/system directories. You could use the ls command to look through those directories, but the preferred method is to use an option on the systemctl command as follows:

# systemctl list-unit-files --type=service
UNIT FILE                                   STATE
...
cups.service                                enabled
...
dbus.service                                static
...
NetworkManager.service                      enabled
...
poweroff.service                            static
...
sshd.service                                enabled
sssd.service                                disabled
...
134 unit files listed.

The unit configuration files shown in the preceding code are all associated with a service unit. Configuration files for target units can be displayed via the following method.

# systemctl list-unit-files --type=target
UNIT FILE                  STATE
anaconda.target            static
basic.target               static
bluetooth.target           static
cryptsetup.target          static
ctrl-alt-del.target        disabled
default.target             enabled
...
shutdown.target            static
sigpwr.target              static
smartcard.target           static
sockets.target             static
sound.target               static
swap.target                static
sysinit.target             static
syslog.target              static
time-sync.target           static
umount.target              static
43 unit files listed.

Notice that both of the configuration units' file examples shown display units with a status of either static, enabled, or disabled. The enabled status means that the unit is currently enabled. The disabled status means that the unit is currently disabled. The next status, static, is slightly confusing. It stands for “statically enabled,” and it means that the unit is enabled by default and cannot be disabled, even by root.

The service unit configuration files contain lots of information, such as what other services must be started, when this service can be started, which environmental file to use, and so on. The following example shows the sshd's unit configuration file:

# cat /lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
After=syslog.target network.target auditd.service
[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=multi-user.target

This basic service unit configuration file has the following options:

  • Description—A free-form description (comment line) of the service.
  • After—Configures ordering. In other words, it lists which units should be activated before this service is started.
  • Environment File—The service's configuration file.
  • ExecStart—The command used to start this service.
  • ExecReload—The command used to reload this service.
  • WantedBy—The target unit this service belongs to.

Notice that the target unit, multi-user.target, is used in the sshd service unit configuration file. The sshd service unit is wanted by the multi-user.target. In other words, when the multi-user.target unit is activated, the sshd service unit is started.

You can view the various units that a target unit will activate by using the following command:

# systemctl show --property "Wants" multi-user.target
Wants=multipathd.service avahi-daemon.service sshd-keygen.se
(END) q

Unfortunately, the systemctl command does not format the output for this well. It literally runs off the right edge of the screen so you cannot see the full results. And you must enter q to return to the command prompt. To fix this problem, pipe the output through some formatting commands to produce a nice alphabetically sorted display, as shown in the example that follows.

# systemctl show --property "Wants" multi-user.target \
     | fmt -10 | sed 's/Wants=//g' | sort
abrt-ccpp.service
abrtd.service
abrt-oops.service
abrt-vmcore.service
atd.service
auditd.service
avahi-daemon.service
crond.service
cups.path
dbus.service
fcoe.service

A target unit has both Wants and requirements, called Requires. A Wants means that all the units listed are triggered to activate (start). If they fail or cannot be started, no problem—the target unit continues on its merry way. The preceding example is a display of Wants only.

A Requires is much more stringent and potentially catastrophic than a Wants. A Requires means that all the units listed are triggered to activate (start). If they fail or cannot be started, the entire unit (group of units) is deactivated.

You can view the various units a target unit Requires (must activate or the unit will fail), using the command in the example that follows. Notice that the Requires output is much shorter than the Wants for the multi-user target. Thus, no special formatting of the output is needed.

# systemctl show --property "Requires" multi-user.target
Requires=basic.target

The target units also have configuration files, as do the service units. The following example shows the contents of the multi-user.target configuration file.

# cat /lib/systemd/system/multi-user.target
#  This file is part of systemd.
#
...
[Unit]
Description=Multi-User
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
[Install]
Alias=default.target

This basic target unit configuration file has the following options:

  • Description—This is just a free-form description of the target.
  • Requires—If this multi-user.target gets activated, the listed target unit is also activated. If the listed target unit is deactivated or fails, then multi-user.target is deactivated. If there are no After and Before options, then both multi-user.target and listed target unit activate simultaneously.
  • Conflicts—This setting avoids conflicts in services. Starting multi-user.target stops the listed targets and services, and vice-versa.
  • After—This setting configures ordering. In other words, it determines which units should be activated before starting this service.
  • AllowIsolate—This option is a Boolean setting of yes or no. If set to yes, then this target unit, multi-user.target, is activated along with its dependencies and all others are deactivated.
  • ExecStart—This command starts the service.
  • ExecReload—This command reloads the service.
  • Alias—With this command, systemd creates a symbolic link from the target unit names listed to this unit, multi-user.target.

Learning systemd's backward compatibility to SysVinit

The systemd daemon has maintained backward compatibility to the SysVinit daemon. This allows Linux distributions time to slowly migrate to systemd.

While runlevels are not truly part of systemd, the systemd infrastructure has been created to provide compatibility with the concept of runlevels. There are seven target unit configuration files specifically created for backward compatibility to SysVinit:

  • runlevel0.target
  • runlevel1.target
  • runlevel2.target
  • runlevel3.target
  • runlevel4.target
  • runlevel5.target
  • runlevel6.target

As you probably have already figured out, there is a target unit configuration file for each of the seven classic SysVinit runlevels. These target unit configuration files are symbolically linked to target unit configuration files that most closely match the idea of the original runlevel. In the example that follows, the symbolic links are shown for runlevel target units. Notice that the runlevel target units for runlevel 2, 3, and 4 are all symbolically linked to multi-user.target. The multi-user.target unit is similar to the legacy Extended Multi-user Mode.

# ls -l /lib/systemd/system/runlevel*.target
lrwxrwxrwx. 1 root root 15 Mar 27 15:39
 /lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx. 1 root root 13 Mar 27 15:39
 /lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx. 1 root root 17 Mar 27 15:39
 /lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Mar 27 15:39
 /lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 Mar 27 15:39
 /lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx. 1 root root 16 Mar 27 15:39
 /lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx. 1 root root 13 Mar 27 15:39
 /lib/systemd/system/runlevel6.target -> reboot.target

The /etc/inittab file still exists, but it contains only comments stating this configuration file is not used and gives some basic systemd information. The /etc/inittab file no longer has any true functional use. The following is an example of a /etc/inittab file on a Linux server that uses systemd.

# cat /etc/inittab
# inittab is no longer used when using systemd.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by
# /etc/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels.
# By default, there are two main targets:
#
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5
#
# To set a default target, run:
#
# ln -s /lib/systemd/system/<target name>.target
# /etc/systemd/system/default.target

The /etc/inittab explains that if you want something similar to a classic 3 or 5 runlevel as your default runlevel, you need to create a symbolic link from the default.target unit to the runlevel target unit of your choice. To check what default.target is currently symbolically linked to (or in legacy terms, to check the default runlevel), use the command shown here. You can see that on this Linux server, the default is to start up at legacy runlevel 3.

# ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 36 Mar 13 17:27
 /etc/systemd/system/default.target ->
   /lib/systemd/system/runlevel3.target

The capability to switch runlevels using the init or telinit command is still available. When issued, either of the commands is translated into a systemd target unit activation request. Therefore, typing init 3 at the command line really issues the command systemctl isolate multi-user.target. Also, you can still use the runlevel command to determine the current legacy runlevel, but it is strongly discouraged.

The classic SysVinit /etc/inittab handled spawning the getty or mingetty processes. The systemd init handles this via the getty.target unit. The getty.target is activated by the multi-user.target unit. You can see how these two target units are linked by the following command:

# systemctl show --property "WantedBy" getty.target
WantedBy=multi-user.target

参考文献