systemd - Arch Linux 中文维基

跳转到内容

# systemd

来自 Arch Linux 中文维基

翻译状态：

- 本文（或部分内容）译自 Systemd，最近一次同步于 2025-01-24，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

相关文章

- systemd/用户
- systemd/定时器
- systemd/日志
- Systemd/FAQ
- init
- 守护程序
- udev
- 性能优化/启动过程
- 允许用户关机

摘自项目主页：

  systemd 是一个 Linux 系统基础组件的集合，提供了一个系统和服务管理器，运行为 PID 1 并负责启动其它程序。功能包括：支持并行化任务；同时采用 socket 式与 D-Bus 总线式启用服务；按需启动守护进程（daemon）；利用 Linux 的 cgroups 监视进程；支持快照和系统恢复；维护挂载点和自动挂载点；各服务间基于依赖关系进行精密控制。systemd 支持 SysV 和 LSB 初始脚本，可以替代 sysvinit。除此之外，功能还包括日志进程、控制基础系统配置，维护登录用户列表以及系统账户、运行时目录和设置，可以运行容器和虚拟机，可以简单的管理网络配置、网络时间同步、日志转发和名称解析等。

在历史上，systemd中的“服务”（service）被称作守护进程（daemon），它们在后台运行（即没有UI、不与终端交互），等待特定事件的发生并提供服务。例如，Web服务器会等待一个请求以提供相应的页面，SSH服务器会等待登录请求。除了这种提供完整功能的，还有一些守护进程的工作是隐藏在幕后的，如负责向日志文件写入消息的`syslog`、`metalog`，确保系统时间准确的ntpd。更多信息详见daemon(7)。

注意：Arch Linux 论坛的这篇帖子 详细地解释了 Arch Linux 迁移到 systemd 的原因。

## systemctl 基本用法

监视和控制 systemd 的主要命令是 systemctl。其用途包括查看系统状态以及管理系统和服务。详见 systemctl(1)。

提示：

- 在 systemctl 参数中添加 `-H 用户名@主机名` 可以远程控制其他机器。该功能使用 SSH 连接到远程的 systemd 实例。
- Plasma 用户可以安装 systemctl 图形前端 systemdgenie包。安装后可以在系统管理下找到。

### 使用单元

单元（unit）通常包括但不限于：服务（.service）、挂载点（.mount）、设备（.device）和套接字（.socket）。

使用 systemctl 时，通常需要使用单元文件的全名，包括扩展名（例如 `sshd.socket`）。不过在以下 systemctl 命令中可以使用简写：

- 如果无扩展名，systemctl 会假定扩展名为 .service。例如，`netctl` 和 `netctl.service` 是等价的。
- 挂载点会自动转化为相应的 .mount 单元。例如，`/home` 等价于 `home.mount` 。
- 与挂载点类似，设备会自动转化为相应的 .device 单元，因此 `/dev/sda2` 等价于 `dev-sda2.device`。

详见 systemd.unit(5)。

注意：有一些单元的名称包含一个 `@` 符号（例如：`name@string.service` ），这意味着它是模板单元 `name@.service` 的一个 实例，模板单元的实际文件名中不包括 `string` 部分（如 `name@.service`）。`string` 被称作实例标识符，在 systemctl 调用模板单元时，会将其当作一个参数传给模板单元，模板单元会使用这个传入的参数代替模板中的 `%i` 指示符。在启动单元时，尝试从模板单元实例化之前，systemd 会先检查 `name@string.suffix` 文件是否存在。如果存在，就直接使用这个文件，而不是模板实例化（不过，这种“碰撞”非常少见）。大多数情况下，包含 `@` 标记都意味着这个文件是模板。如果一个模板单元被调用时没有指定实例标识符，该调用通常会失败，除非是在某些特殊的 systemctl命令（如`cat`）中使用。

因为调用systemctl时默认了 `--system` 参数，下列命令默认对系统单元进行操作。若要对（调用用户的）用户单元进行操作，则需在非root身份下执行systemctl --user。参看systemd/用户#基础设置以为所有用户启用或禁用单元。

提示：

- 下面的大部分命令都可以跟多个单元名，详细信息参见 systemctl(1)。
- `--now` 选项可与 `enable`、`disable` 和 `mask` 同时使用，可使这些动作立即生效，而非重启后生效。
- 一个软件包可能会为不同的功能提供多个不同的单元。如果你刚安装了软件包，可以通过 `pacman -Qql package | grep -Fe .service -e .socket` 命令检查这个软件包提供了哪些单元。

动作 | 命令 | 注释
--- | --- | ---
分析系统状态
显示系统状态 | `systemctl status` |
列出正在运行的单元 | `systemctl` 或 `systemctl list-units` |
列出失败的单元 | `systemctl --failed` |
列出已安装的单元1 | `systemctl list-unit-files` |
显示特定PID对应进程的状态 | `systemctl status pid` | cgroup slice，内存占用，父进程
检查单元状态
显示单元的手册页 | `systemctl help 单元` | 如果单元支持
显示单元的状态 | `systemctl status 单元` | 包括其是否在运行
检查单元是否配置为自动启动（enabled） | `systemctl is-enabled 单元` |
启动（start）、重新启动和重新加载单元
立即启动单元 | 以root身份执行`systemctl start 单元` |
立即停止单元 | 以root身份执行`systemctl stop 单元` |
重新启动单元 | 以root身份执行`systemctl restart 单元` |
重新加载单元及其配置 | 以root身份执行`systemctl reload 单元` |
重新加载 systemd 配置2 | 以root身份执行`systemctl daemon-reload` | 扫描单元的变动
启用（enable）单元
启用单元：开机时自动启动该单元 | 以root身份执行`systemctl enable 单元` |
启用单元，并立即启动它 | 以root身份执行`systemctl enable --now 单元` |
取消开机自动启动单元 | 以root身份执行`systemctl disable 单元` |
重新启用单元3 | 以root身份执行`systemctl reenable 单元` | 先取消启用，再启用
屏蔽单元
屏蔽单元，使其无法启动4 | 以root身份执行`systemctl mask 单元` |
取消屏蔽单元 | 以root身份执行`systemctl unmask 单元` |

1. systemd.unit(5) § UNIT FILE LOAD PATH 中描述了查找单元文件的路径。
2. 这不会要求已改变的单元重新加载自己的配置（见重新加载动作）。
3. 可在单元的`[Install]`节发生变更（在上一次启用后）时使用。
4. 既不能手动启动，也无法作为依赖启动。因此屏蔽单元是危险的。 查看已屏蔽的单元：

       # systemctl list-unit-files --state=masked

### 电源管理

安装 polkit 后才能以普通用户身份使用电源管理。如果你正登录在一个本地的 systemd-logind 用户会话，且当前没有其它活动的会话，那么以下命令无需 root 权限即可执行。否则（例如，当前有另一个用户登录在某个 tty），systemd 将会自动请求输入 root 密码。

动作 | 命令
--- | ---
重启 | `systemctl reboot`
关机 | `systemctl poweroff`
待机 | `systemctl suspend`
休眠（将内存写入硬盘） | `systemctl hibernate`
进入混合休眠模式（同时休眠到硬盘并待机） | `systemctl hybrid-sleep`
先待机，在一个特定时间唤醒后进入休眠模式 | `systemctl suspend-then-hibernate`
使用#软重启来仅重启用户空间 | `systemctl soft-reboot`

#### 软重启

软重启是一种不涉及内核，仅重启用户空间的重启操作。这个操作由 systemd-soft-reboot.service(8) 实现，并且可以通过 `systemctl soft-reboot` 来进行一次软重启。正如 kexec 一样，这个操作跳过了重新初始化固件，也不会进行内核初始化和初始化 RAM 文件系统。同时，未锁定的 dm-crypt 设备也将保持解锁状态。

当 `/run/nextroot` 包含了一个合法的 rootfs 结构（比如说挂载了另一个发行版的根分区或者另一个快照），软重启操作将会切换系统根分区到其中。切换之后并不会丢失一些由内核管理的状态，比如说网络连接。

提示：`/run/nextroot/`不一定是一个挂载点或者存在于物理设备上。例如，它可以在 `/run/` tmpfs 中。systemd 将会在软重启时自动将`/run/nextroot/` 转化为一个挂载点。
注意：不要在涉及内核和 initramfs 的更新后执行 `systemctl soft-reboot`。

## 编写单元文件

`systemd` 单元文件的语法来源于XDG 桌面项配置的.desktop文件，最初的源头则是Microsoft Windows的.ini文件。单元文件可以从多个地方加载，`systemctl show --property=UnitPath` 可以显示加载目录。主要的加载目录为（按优先级从低到高排列）：

- `/usr/lib/systemd/system/` ：软件包安装的单元
- `/etc/systemd/system/` ：系统管理员安装的单元

注意：

- 当 `systemd` 运行在用户模式下时，使用的加载路径是完全不同的。
- systemd 单元名仅能包含 ASCII 字符，下划线和点号以及有特殊意义的字符('@', '-')。其它字符需要用C风格的"\x2d" 替换或使用对应的预定义语法（“@”，“-”）。参阅 systemd.unit(5) 和 systemd-escape(1) 。

单元文件的语法，可以参考系统已经安装的单元，也可以参考 systemd.service(5) § EXAMPLES。

提示：在单元文件中以`#`开头的行将被视作注释，但`#`仅能在一行开头使用。不要在 systemd 的参数后面使用行末注释，否则该单元将不能正常启动。

systemd-analyze(1) 可以帮助你检查错误。请参见那一章节的 `systemd-analyze verify FILE...` 部分。

### 处理依赖关系

使用 systemd 时，可通过正确编写单元配置文件来解决单元间的依赖关系。典型的情况是，单元A要求单元B在A启动之前运行。在此情况下，可向单元A配置文件中的 `[Unit]` 段添加 `Requires=B` 和 `After=B` 即可。若此依赖关系是可选的，可添加 `Wants=B` 和 `After=B`。请注意 `Wants=` 和 `Requires=` 并不暗含 `After=` ，即如果 `After=`选项没有指定，这两个单元将被并行启动。

依赖关系通常被用在服务（service）而不是目标（target）上。例如，`network.target` 一般会被某个配置网络接口的服务引入作为依赖。所以，若要让自定义单元在系统到达`network.target`后再启动， 将自定义的单元排在该类配置网络接口的服务之后即可，因为该类服务启动时 `network.target` 一定已经启动。

### 服务（service）类型

编写自定义的服务（service）文件时，可以选择几种不同的服务启动方式。启动方式可通过配置文件 `[Service]` 段中的 `Type=` 参数进行设置。

- `Type=simple` ：（默认值） systemd认为该服务将立即启动且服务进程不会fork。如果其他服务需要在此服务之后启动，请不要使用此类型，除非它是通过套接字激活的。
- `Type=forking` ：systemd认为当该服务进程fork，且父进程退出后服务启动成功。对于典型的守护进程，除非你确定此启动方式无法满足需求，使用此类型启动即可。使用此启动类型应同时指定 `PIDFile=`，以便systemd能够跟踪服务的主进程。
- `Type=oneshot` ：这一选项适用于只执行一项任务、随后立即退出的服务。可能需要同时设置 `RemainAfterExit=yes`使得systemd在服务进程退出之后仍然认为服务处于启用状态，这对于改变系统状态（如挂载分区）的单元尤其适用。对于 simple 和 oneshot 类型的区别，请参阅 [1]。
- `Type=notify` ：与 `Type=simple` 相同，但约定服务会在就绪后向systemd发送一个信号以通知systemd。这一通知的参考实现由 `libsystemd-daemon.so` 提供。
- `Type=dbus` ：若以此方式启动，当指定的 `BusName` 出现在DBus系统总线上时，systemd认为服务就绪。
- `Type=idle` ：`systemd`会等待所有活动任务都完成后再执行服务进程。其他行为与 `Type=simple` 类似。

`type` 的更多解释可以参考 systemd.service(5) § OPTIONS。

### 修改现存单元文件

为了避免和 pacman 冲突，不应该直接编辑软件包提供的文件。有两种方法可以不改动原始文件就做到修改单元文件：创建一个优先级更高的本地单元文件以覆盖原有的单元文件或创建一个片段（drop-in snippets），应用到原始单元文件之上。两种方法都需要在修改后重新加载单元：用 `systemctl edit` 编辑单元(会自动重载单元)或通过下面命令重新加载单元：

    # systemctl daemon-reload

提示：

- `systemd-delta` 命令用来查看哪些单元文件被覆盖、扩增，哪些被修改。
- 使用 `systemctl cat unit` 可以查看单元的内容和所有相关的片段。

#### 替换单元文件

要替换 `/usr/lib/systemd/system/unit`, 创建文件 `/etc/systemd/system/unit` 并重新启用单元以更新符号链接：

    # systemctl reenable unit

或者运行：

    # systemctl edit --full unit

这将会在默认编辑器中打开 `/etc/systemd/system/unit`。如果文件不存在，可以将软件包安装的版本复制到这里，在编辑完成之后，会自动加载新版本。

注意：即使 Pacman 更新了新的单元文件，软件包中的版本也不会被使用，所以这个方式会增加系统维护的难度，推荐使用下面一种方法。

#### 附加配置片段

要为单元文件`/usr/lib/systemd/system/unit`附加配置片段，先创建名为 `/etc/systemd/system/unit.d/` 的目录，然后放入 `*.conf` 文件，其中可以添加或覆盖参数。这里设置的参数优先级高于原来的单元文件。systemd会解析这些参数并将这些文件应用到原单元文件上。

要附加配置片段，最简单的方法是执行：

    # systemctl edit unit --drop-in=drop_in_name

这将会在编辑器中打开文件 `/etc/systemd/system/unit.d/drop_in_name.conf`，编辑完成之后自动加载。若省略`--drop-in=`选项，systemd将使用默认文件名：`override.conf`。

注意：

- 附加配置片段中的键（配置项）仍必须置于相应的节（section）下。
- 并不是所有参数都会被子配置文件覆盖。例如要修改 `Conflicts=` 就必须替换原始文件。
- 你可以使用顶级附加配置文件来影响所有相同类型的单元。例如，在 `/etc/systemd/system/service.d/` 中的附加配置文件会影响所有 .service 单元。你可以在#Notifying_about_failed_services中看到一个示例。

#### 重置到软件包的版本

要回退使用`systemctl edit`对单元进行的所有变更，执行:

    # systemctl revert unit

#### 示例

如果想添加一个额外的依赖，创建如下文件即可：

    /etc/systemd/system/<unit>.d/customdependency.conf

    [Unit]
    Requires=<新依赖>
    After=<新依赖>

要修改一个单元的 `ExecStart` 命令，创建下面文件:

    /etc/systemd/system/unit.d/customexec.conf

    [Service]
    ExecStart=
    ExecStart=<新命令>

修改 `ExecStart` 前必须将其置空，参见 [2] 。所有可能多次赋值的变量都需要这个操作，例如定时器的 `OnCalendar` 。

下面是自动重启服务的一个例子：

    /etc/systemd/system/unit.d/restart.conf

    [Service]
    Restart=always
    RestartSec=30

### 服务日志级别

对于直接向 journald 或 syslog 发送日志的服务，你可以通过在 `[Service]` 部分设置 `LogLevelMax=` 参数来控制其详细程度，该参数的值可以是 0 到 6 之间的数字。例如：

    /etc/systemd/system/unit.d/override.conf

    [Service]
    LogLevelMax=3

标准的日志级别与用于过滤 journal 的级别相同。设置较低的数字会排除所有较高且不太重要的日志消息。

#### 抑制服务的标准输出

如果服务正在回显 stdout 和/或 stderr 输出，默认情况下这些输出也会进入 journal。可以通过在 `[Service]` 部分设置 `StandardOutput=null` 和/或 `StandardError=null` 来抑制此行为。除了 `null` 之外，还可以使用其他值来进一步调整此行为。参见 systemd.exec(5) § LOGGING_AND_STANDARD_INPUT/OUTPUT。

## 目标（target）

systemd使用目标来通过依赖关系将多个单元组织起来。目标还是系统的标准化同步点（确保系统处于特定状态）。目标与runlevels的设计目的相似，但两者也有些许不同。每一个目标都以名称而不是数字标识，用以达成特定的目的。多个目标可以同时被激活。有的目标继承另一个目标的所有服务，同时向其中增添一些服务。有些systemd目标模仿了常见的SystemVinit runlevels。

### 获取当前目标

使用systemd的命令而非`runlevel`：

    $ systemctl list-units --type=target

### 创建自定义目标

在sysvinit中有明确定义的运行级别（如：0、1、3、5、6）与 systemd 中特定的目标存在一一对应的关系。然而，对于用户自定义运行级别（2、4）却没有。如需要同样功能，建议你以原有运行级别所对应的 systemd 目标为基础，新建一个`/etc/systemd/system/<目标名>.target`（可参考`/usr/lib/systemd/system/graphical.target`）, 然后创建目录`/etc/systemd/system/<目标名>.wants`，并向其中加入需启用的服务链接（指向`/usr/lib/systemd/system/`中的对应文件）。

### “SysV运行级别”与“systemd目标”对照表

SysV 运行级别 | Systemd 目标 | 注释
--- | --- | ---
0 | poweroff.target | 关闭系统（halt）
1, s, single | rescue.target | 单用户模式
2, 4 | multi-user.target | 用户自定义运行级别，默认与级别3相同。
3 | multi-user.target | 多用户，无图形界面。用户可以通过终端或网络登录。
5 | graphical.target | 多用户，图形界面。继承级别3的服务，并启动图形界面服务。
6 | reboot.target | 重启
emergency | emergency.target | 急救模式（Emergency shell）

### 切换当前运行目标

systemd中，目标通过“目标单元”访问。通过如下命令切换：

    # systemctl isolate graphical.target

该命令仅更改当前运行目标，对下次启动无影响。这等价于sysvinit中的`telinit 3`或`telinit 5`命令。

### 更改开机默认启动目标

开机启动的目标是`default.target`，默认符号链接到`graphical.target`（大致相当于原来的运行级别5）。

用 systemctl 检查当前的默认启动目标：

    # systemctl get-default

用systemctl修改`default.target`符号链接以变更开机默认启动目标：

    # systemctl set-default multi-user.target

    Removed /etc/systemd/system/default.target.
    Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target.

另一方法是向bootloader添加内核参数：

- `systemd.unit=multi-user.target` （大致相当于运行级别3）
- `systemd.unit=rescue.target` （大致相当于运行级别1）

### 默认目标顺序

Systemd 根据下面顺序选择 `default.target`：

1. 上面的内核参数
2. `/etc/systemd/system/default.target` 软链接
3. `/usr/lib/systemd/system/default.target` 软链接

## systemd组件

systemd的部分组件如下：

- kernel-install——一个用以自动将内核及对应的initramfs镜像移动到boot分区的脚本；
- systemd-analyze(1)——可用于确定启动性能、统计信息并检索其他状态和跟踪信息，以及验证单元文件的正确性。它还用于访问高级调试所需的特殊功能。
- systemd-boot——简单的UEFI启动管理器；
- systemd-creds——安全地存储并获取systemd单元使用的credentials；
- systemd-cryptenroll——Enroll PKCS#11, FIDO2, TPM2 token/devices to LUKS2 encrypted volumes；
- systemd-firstboot——负责在系统第一次启动前的设置初始化；
- systemd-homed——portable human-user accounts；
- systemd-logind(8)——会话管理；
- systemd-networkd——网络配置管理；
- systemd-nspawn——轻量namespace容器；
- systemd-repart——创建分区表，添加或扩大分区；
- systemd-resolved——网络域名解析；
- systemd-run(1) / run0(1)——以交互式的方式临时的提升或获得不同的权限。
- systemd-stub(7)——用于创建统一内核镜像的UEFI boot stub；
- systemd-sysusers(8)——在安装软件包或系统启动时创建系统用户和组、将用户加入组；
- systemd-timesyncd——通过网络同步系统时间；
- systemd/Journal——系统日志；
- systemd/Timers——用于控制.service文件或事件的间隔或实时计时器，可替代cron。

### systemd.mount - 挂载

systemd负责挂载`/etc/fstab`中指定的分区和文件系统。systemd-fstab-generator(8)将`/etc/fstab`中的所有条目翻译为systemd单元。该过程将在系统启动或系统管理器的配置被重新加载时执行。

systemd扩展了通常fstab的用法并提供了更多挂载选项。这些挂载选项可影响挂载点单元的依赖关系。例如，它们可以确保某一挂载操作只会在连接网络或另一分区挂载后进行。systemd的特定挂载选项（大多以`x-systemd.`开头）的完整列表见systemd.mount(5) § FSTAB。

automounting是这些挂载选项的一个例子。它意味着资源只会在请求时挂载，而非在系统启动时自动挂载，详见fstab#通过 systemd 自动挂载。

#### GPT分区自动挂载

在UEFI启动的系统上，GPT分区如`root`、`home`、`swap`等可以根据Discoverable Partitions Specification自动挂载。因此，可在fstab中省略自动挂载的分区。此外，若根分区已被自动挂载，可省去内核命令行中的`root=`。详见systemd-gpt-auto-generator(8)。

使用GPT分区自动挂载的先决条件有：

- 使用mkinitcpio时，需要systemd hook。
- 所有自动挂载的分区必须与ESP分区在同一块物理硬盘上。
- 必须设置正确的GPT分区类型。详见Partitioning#Partition scheme。
- 引导加载程序必须设置LoaderDevicePartUUIDEFI变量，以便识别使用的EFI系统分区。systemd-boot，systemd-stub(7)，GRUB (使用grub-mkconfig生成`grub.cfg`），rEFInd（默认未启用）支持该特性。若使用自定义的`grub.cfg`，则需要加载bli模块。 可通过执行`bootctl`并检查`Boot loader sets ESP information`的状态进行确认，或在用统一内核镜像启动时检查`Stub sets ESP information`的状态。

udev会创建一个指向根卷块设备的`/dev/gpt-auto-root`符号链接。如果根分区使用LUKS加密，`/dev/gpt-auto-root`将指向解锁/映射的卷，而`/dev/gpt-auto-root-luks`将指向加密分区。

提示：某个分区的自动挂载可通过如下两种方式关闭：修改分区的类型GUID或设置分区属性的63"do not automount"位，详见gdisk#Prevent GPT partition automounting。

##### /var

要自动挂载`/var`分区，分区的PARTUUID必须与以machine ID为密钥，分区类型UUID为消息的SHA256 HMAC哈希计算结果相同。可通过如下命令得到符合要求的PARTUUID：

    $ systemd-id128 -u var-partition-uuid

注意：systemd-id128(1)从`/etc/machine-id`读取machine ID，因此必须在系统安装后才能得到符合要求的PARTUUID。

### systemd-sysvcompat

systemd-sysvcompat包（由base包需要）的主要工作是提供传统的Linux init可执行文件。在由systemd控制的系统上，`init`只是一个到`systemd`可执行文件的符号链接。

此外，该包还提供了SysVinit用户可能需要的功能的4个快捷方式：halt(8)，poweroff(8)，reboot(8)和shutdown(8)。这4个命令都是到`systemctl`的符号链接，其行为受systemd控制。因此，在#电源管理中提到的规则对它们同样适用。

在由systemd控制的系统上，可通过`init=`内核启动参数取消对System V的兼容性支持。详见/bin/init is in systemd-sysvcompat ?。

### systemd-tmpfiles - 临时文件

systemd-tmpfiles创建，删除并清理临时文件/文件夹。systemd-tmpfiles读取`/etc/tmpfiles.d/`、`/usr/lib/tmpfiles.d/`中的配置文件（前者比后者优先级高）以确定执行什么操作。

这些配置文件通常与服务文件一同提供，并以`/usr/lib/tmpfiles.d/<程序>.conf`风格命名。例如，Samba守护进程需要`/run/samba`目录存在且权限设置正确，因此samba包中附带了如下配置：

    /usr/lib/tmpfiles.d/samba.conf

    D /run/samba 0755 root root

配置文件也可能用于在启动时向特定文件中写入值。例如，要禁止系统从USB设备唤醒。在之前可使用`/etc/rc.local`在启动时执行`echo USBE > /proc/acpi/wakeup`，而现在可以这么做：

    /etc/tmpfiles.d/disable-usb-wake.conf

    #    Path                  Mode UID  GID  Age Argument
    w    /proc/acpi/wakeup     -    -    -    -   USBE

可以通过在参数中使用 `\n` 或者在多行配置的情况下用 `w+` 类型来进行追加（包括第一行）。

    /etc/tmpfiles.d/disable-usb-wake.conf

    #    Path                  Mode UID  GID  Age Argument
    w+   /proc/acpi/wakeup     -    -    -    -   USBE
    w+   /proc/acpi/wakeup     -    -    -    -   LID0

详见systemd-tmpfiles(8)、tmpfiles.d(5)。

注意：若要向`/sys`中的配置文件写入值，可能不能使用该方法。因为systemd-tmpfiles-setup服务可能在相关模块加载前运行。在这种情况下，可先通过`modinfo <模块名>`检查该模块是否可通过设定模块参数来修改相应的选项。若有对应的模块参数，可通过/etc/modprobe.d目录中的配置文件设定相应参数以达到修改选项的目的。否则，将只能通过udev 规则来在设备被识别时设定相应属性。

### Drop-in 配置文件

本文或本章节的事实准确性存在争议。

原因： 本页面是关于PID 1（init）的，单元文件的drop-in配置已经提到。Drop-in是一个通用概念，加上其他systemd组件有专门的wiki页面。因此本节似乎不属于这里。（在 Talk:Systemd#YHNdnzj : Configuration files in conf.d / drop-in snippets: misplaced? 中讨论）

为了避免与pacman更新冲突，不应直接编辑由软件包提供的配置文件。为此，许多（但不是所有）systemd软件包提供了一种修改配置的方式，但不直接修改原始文件，而是通过创建drop-in片段来实现。请检查软件包手册以查看是否支持drop-in配置文件。

要为单元文件`/etc/systemd/unit.conf`创建drop-in配置文件，请创建目录`/etc/systemd/unit.conf.d/`并在其中放置.conf文件以覆盖或添加新选项。systemd将解析并应用这些文件到原始单元之上。

检查整体配置：

    $ systemd-analyze cat-config systemd/unit.conf

应用的drop-in片段文件及其内容将列在最后。重启服务以使更改生效。

## 小技巧

这篇文章的某些内容需要扩充。

原因：我们应该在某个地方明确记录套接字激活相对于简单服务启动的优势。这在页面开头和相关页面（如Avahi）中简要提到。 (在 Talk:Systemd 中讨论)

### 激活套接字

有一些包提供了一个 .socket 单元。例如，cups包 提供了一个 `cups.socket` 单元[3]。如果 `cups.socket` 被启用（并且 `cups.service` 保持关闭），systemd 并不会立刻启动 CUPS，它会监听适当的套接字并且当任何一个程序尝试连接 CUPS 服务中的一个时，systemd 会启动 `cups.service` 并且透明地将这些端口的控制权移交给 CUPS 进程。

### GUI配置工具

- systemadm — 用于systemd单元的图形化浏览器。可显示单元列表，并能按类型筛选。

  https://cgit.freedesktop.org/systemd/systemd-ui/ || systemd-ui包

- SystemdGenie — 基于KDE的systemd管理工具。

  https://invent.kde.org/system/systemdgenie || systemdgenie包

### 在网络已连接后再启动某服务

如果需要将某服务延迟到网络已连接后再启动, 直接在 .service 文件中包含以下依赖项：

    /etc/systemd/system/<单元名>.service

    [Unit]
    ...
    Wants=network-online.target
    After=network-online.target
    ...

要使`network-online.target`正确反映网络状态，必须启用所使用的网络管理器的网络等待服务。

- 若使用NetworkManager, `NetworkManager-wait-online.service`应该与`NetworkManager.service`一同启用。可通过`systemctl is-enabled NetworkManager-wait-online.service`进行检查。若服务没用启用，重新启用`NetworkManager.service`。
- 若使用netctl, 启用`netctl-wait-online.service` (除非使用了netctl-auto； 详见FS#75836)。
- 若使用systemd-networkd, `systemd-networkd-wait-online.service`应该与`systemd-networkd.service`一同启用。可通过`systemctl is-enabled systemd-networkd-wait-online.service`进行检查。若服务没用启用，重新启用`systemd-networkd.service`。

如果需要更为详细的解释，请查看网络配置同步点中的讨论。

若某服务需要执行DNS查询，其应该被排在`nss-lookup.target`后：

    /etc/systemd/system/<单元名>.service

    [Unit]
    ...
    Wants=network-online.target
    After=network-online.target nss-lookup.target
    ...

详见systemd.special(7) § Special Passive System Units.

要`nss-lookup.target`发挥作用，必须有一个单元通过`Wants=nss-lookup.target`引入`nss-lookup.target`，并通过`Before=nss-lookup.target`排在`nss-lookup.target`之前。一般情况下，上述配置由本地DNS解析器完成。

检查哪一个正在运行的单元引入了`nss-lookup.target`：

    $ systemctl list-dependencies --reverse nss-lookup.target

### 默认启用新安装的单元

Arch Linux附带的`/usr/lib/systemd/system-preset/99-default.preset`包含`disable *`，这会导致默认情况下的systemctl preset是禁用所有新安装的的单元。因此某个新包安装后, 用户必须手动启用新单元。

若上述行为不符合预期, 创建一个从`/etc/systemd/system-preset/99-default.preset`到`/dev/null`的符号链接来覆盖该配置文件，这会导致 systemctl preset无视单元类型直接启用所有单元，除非systemctl preset的配置目录中有文件另有声明。用户单元不受影响。详见systemd.preset(5)。

注意：若某个软件包含有多个互相冲突的单元，默认启用所有单元可能会出现问题。systemctl preset原本旨在供发行版或系统管理员使用。在有两个冲突单元将被同时启用的情况下，应明确在systemctl preset的配置文件中禁用其中一个单元，详见systemd.preset(5)。

### 应用程序环境沙盒

可通过一个单元文件创建一个沙盒以在加固的虚拟环境中隔离应用程序及其进程。systemd充分利用namespaces，一系列允许/拒绝 capabilities 和 cgroups，以通过可拓展的执行环境设置（systemd.exec(5)）将进程禁锢在容器中。

将现有systemd单元文件进行沙盒化加固通常需要结合使用strace包，stderr和journalctl(1)等进行大量试验。因此，最好先在上游文档中搜索已完成的测试以作为试验的基础。

首先，最好通过以下命令获得特定单元可能的加固选项作为基础：

    $ systemd-analyze security <单元>

关于如何使用 systemd 部署沙盒的一些示例：

- `CapabilityBoundingSet`定义了一个列表，以指明某个单元可以/不能使用哪些capabilities(7)。详见systemd.exec(5) § CAPABILITIES。
  - 例如，对`CAP_SYS_ADM` capability的控制应该是安全沙盒的目标: `CapabilityBoundingSet=~ CAP_SYS_ADM`

### 通知失败的单元

本文或本章节可能需要合并到systemd/Timers#MAILTO。

附注： 相同话题，不同解决方案（在 Talk:Systemd 中讨论）

要在服务故障时发出通知，可在相应服务的单元文件中添加`OnFailure=`设置，这可通过#附加配置片段完成。若要在每一个服务的单元文件中添加该设置，可使用一个顶层附加配置片段，详见systemd.unit(5)。

为服务单元创建顶层附加配置片段：

    /etc/systemd/system/service.d/toplevel-override.conf

    [Unit]
    OnFailure=failure-notification@%n.service

这将向每个服务单元文件中添加`OnFailure=failure-notification@%n.service`。若单元甲失败，会启动`failure-notification@单元甲.service`来递送相关通知（或执行其它配置的动作）。

创建`failure-notification@.service`模板单元：

    /etc/systemd/system/failure-notification@.service

    [Unit]
    Description=Send a notification about a failed systemd unit

    [Service]
    Type=oneshot
    ExecStart=/path/to/failure-notification.sh %i
    # 以临时用户/组运行并启用其他安全措施
    DynamicUser=true

接下来可创建`failure-notification.sh`脚本，定义执行的操作或发送通知的方式（邮件、桌面通知、gotify、XMPP等）。`%i`将被替换为失败单元的名称并作为参数被传递给`failure-notification.sh`脚本。

为防止`failure-notification@.service`的实例启动失败时引发`failure-notification@.service`实例的递归性启动，在`failure-notification@.service`单元的配置目录下创建一个与顶层附加配置片段文件名相同的空的附加配置片段（该空的附加配置片段比全局附加配置片段优先级更高）：

    # mkdir -p /etc/systemd/system/failure-notification@.service.d
    # touch /etc/systemd/system/failure-notification@.service.d/toplevel-override.conf

## 疑难解答

### 寻找失败的单元

要寻找启动失败的systemd单元，执行：

    $ systemctl --state=failed

可通过它们的日志查找失败的原因。详见systemd/Journal#过滤输出。

### 诊断系统启动问题

systemd有许多用于调试系统启动过程中的问题的选项。要捕获在systemd接管启动流程前的日志，参阅boot debugging。还可参阅此系统调试文档。

### 诊断一个服务

如果某个 systemd 服务的工作状况不合预期或想了解发生了什么的更多信息，将`SYSTEMD_LOG_LEVEL`环境变量的值设为`debug`。例如，要以调试模式运行systemd-networkd守护进程：

在此服务的配置文件中加入如下配置片段：

    [Service]
    Environment=SYSTEMD_LOG_LEVEL=debug

或者手动设置该环境变量以达到相同效果：

    # SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd

之后，重新启动systemd-networkd并以`-f`/`--follow`启动journalctl观察该单元的日志。

### 关机/重启十分缓慢

如果关机十分缓慢（甚至跟死机了一样），很可能是某个拒不退出的服务在作怪。对于每个服务systemd会等待一段时间，然后再尝试杀死它。要确定是否受到该问题影响，详见 systemd 文档中的Shutdown completes eventually 这篇文章。

一个常见的原因是存在一个搁置的关机或挂起进程。要确认是否为这种情况，执行下列命令中的任何一个并观察有无类似的输出：

    # systemctl poweroff

    Failed to power off system via logind: There's already a shutdown or sleep operation in progress

    # systemctl list-jobs

      JOB UNIT                    TYPE  STATE
    ...
    21593 systemd-suspend.service start running
    21592 suspend.target          start waiting
    ..

该问题的解决方法是取消这些关机/挂起工作：

    # systemctl cancel
    # systemctl stop systemd-suspend.service

并再次尝试关机或重启。

### 一些短命进程似乎没有产生任何日志输出

对于短命的服务进程（启动后迅速失败），若以root身份执行`journalctl -u <单元名>`可能看不到任何输出，此时可转而使用进程的PID。例如，若`systemd-modules-load.service`单元失败，通过`systemctl status systemd-modules-load`得到的对应进程PID为123，以root身份执行`journalctl -b _PID=123`或许就能得到日志输出。上述问题的原因是日志元数据（如`_SYSTEMD_UNIT`、`_COMM`）以异步方式被采集，且依赖于`/proc`中相应进程的目录。修复该问题需要修改内核以通过socket提供需要的数据（类似于`SCM_CREDENTIALS`）。简而言之，该问题是一个bug，只需记住由于systemd的设计，在启动后迅速失败的单元可能不会打印任何输出到系统日志中。

### systemd-tmpfiles-setup.service在系统启动时失败

自systemd 219开始，`/usr/lib/tmpfiles.d/systemd.conf`为`/var/log/journal`下的目录指定了ACL选项。因此存放日志的文件系统必须启用ACL支持。

如何在存放`/var/log/journal`的文件系统上启用ACL的说明见Access Control Lists#启用 ACL。

### 在远程主机上关闭救援（emergency）模式

当救援模式被触发时，机器不会连接网络，因此对于托管于Azure或Google Cloud的远程主机，或许需要关闭救援模式。

要关闭救援模式，屏蔽`emergency.service`和`emergency.target`。

## 参见

- Wikipedia:systemd
- 官方网站
  - systemd 优化
  - systemd 常见问题解答
  - systemd 技巧与窍门
- systemd(1)
- 其他发行版
  - Gentoo:Systemd
  - Debian:Systemd
  - Ubuntu:Systemd
  - Fedora:Systemd
  - openSUSE:Systemd
- 如何使用 Systemctl 管理 Systemd 服务和单元
- 使用 systemd-logind 进行会话管理
- Emacs 对 Systemd 文件的语法高亮
- 两篇 部分介绍文章，发表于 The H Open 杂志。

分类：​

- 初始化

隐藏分类：​

- 使用“模板:准确性”标记的页面或章节
- 使用“模板:合并”标记的页面或章节

systemd
添加话题