[TOC]
# 控制启动过程
## 目标:
能够影响启动过程并且能够使用 systemd 目标来修复常见的启动问题。
选择 systemd 目标
systemd 目标是一组应在启动后达到所需状态的 systemd 单元。下表中列出了重要目标。
| 目标 | 用途 |
| --- | --- |
| graphical.target | 系统支持多用户、图形和基于文本的登录。 |
| multi-user.target | 系统仅支持多用户、基于文本的登录。 |
| rescue.target | sulogin 提示,表示基本系统初始化完成。 |
| emergency.target | sulogin 提示,表示 initramfs 回转完成,且系统 root 以只读形式挂载于 / 上。 |
某个目标可能属于另一目标;例如,graphical.target 包含 multi-user.target,后者反过来取决于 base.target 和其他目标。使用以下命令可从命令行查看这些依赖关系:
~~~
[root@serverX~]# systemctl list-dependencies graphical.target | grep target
~~~
使用以下命令可查看所有可用目标的概述:
~~~
[root@serverX~]# systemctl list-units --type=target --all
~~~
使用以下命令可查看磁盘上安装的所有目标的概述:
~~~
[root@serverX~]# systemctl list-unit-files --type=target --all
~~~
#### 在运行时选择目标
在运行的系统中,管理员可以随意使用 systemctl isolate 命令来切换到其他目标;例如,systemctl isolate multi-user.target。
### 注意
并非所有目标都能隔离。只有单元文件中设置了 AllowIsolate=yes 的目标才可以隔离;例如 graphical.target 目标可以隔离,但 cryptsetup.target 目标不能隔离。
#### 设置默认目标
在系统启动且将控制权从 initramfs 交给 systemd 后,systemd 会尝试激活 default.target 目标。通常,default .target 目标是(/etc/systemd/system/ 中)指向 graphical.target 或 multi-user.target 的符号链接。
systemctl 工具提供了两个命令来管理链接:get-default 和 set-default。
~~~
[root@serverX~]# systemctl get-default
multi-user.target
[root@serverX~]# systemctl set-default graphical.target
rm '/etc/systemd/system/default.target'
ln -s '/usr/lib/systemd/system/graphical.target' '/etc/systemd/system/default.target'
[root@serverX~]# systemctl get-default
graphical.target
~~~
在启动时选择其他目标
要在启动时选择其他目标,可从启动加载器将特殊选项附加到内核命令行:systemd.unit=。例如,要将系统启动到救援Shell,请在交互式启动加载器菜单中传递以下选项:
~~~
systemd.unit=rescue.target
~~~
要使用这种选择其他目标的方法,请针对 Red Hat Enterprise Linux 7 系统执行以下步骤:
1. (重新)启动系统。
2. 按任意键中断启动加载器菜单倒计时。
3. 将光标移至要启动的条目。
4. 按 e 编辑当前条目。
5. 将光标移至 linux16 开头的行。此为内核命令行。
6. 附加 systemd.unit=desired.target。
7. 按 Ctrl+x 使用这些更改进行启动。
## 恢复 root 密码
在仍以管理员或者具有完整 sudo 访问权限的用户身份登录时,恢复 root 用户密码是一项微不足道的任务,但在管理员未登录时,这项任务便略微有点复杂。在后面的情况中,管理员可以从 Live CD 中启动,从其中挂载根文件系统并编辑 /etc/shadow。管理员还能够在不使用外部介质的情况下执行根密码恢复。
### 注意
在 Red Hat Enterprise Linux 6 及早期版本中,管理员可以从启动系统进入 runlevel 1,然后看到一个 root 提示。在 Red Hat Enterprise Linux 7 计算机上与 runlevel 1 最接近的模拟是 rescue.target 和 emergency.target 目标,这两个目标都需要 root 密码才能登录。
在 Red Hat Enterprise Linux 7 中,可以使从 initramfs 运行的脚本在某些点暂停,提供 root shell,然后在该 shell 存在的情况下继续。虽然这主要是为了调试,但也可用于恢复丢失的 root 密码:
1. 重新启动系统。
2. 按任意键中断启动加载器倒计时。
3. 将光标移到需要启动的条目。
4. 按 e 编辑选定的条目。
5. 将光标移到内核命令行(以 linux16 开头的行)。
6. 附加 rd.break(就在从 initramfs 向实际系统移交控制权前,该操作会中断)。
### 注意
initramfs 提示会显示在内核命令行中指定为最后的任何控制台中。
7. 按 Ctrl+x 使用这些更改进行启动。
此时,会显示 root Shell,且实际系统的 root 文件系统会在 /sysroot 中以只读方式挂载。
### 重要
由于此时尚未启用 SELinux,因此任何创建的新文件都不会分配有 SELinux 上下文。请记住,有些工具(例如 passwd)首先会创建一个文件,然后移动新文件以代替要编辑的文件,从而有效地创建不带 SELinux 上下文的新文件。
此时要恢复 root 密码,请使用以下步骤:
1. 以读写形式重新挂载 /sysroot。
~~~
switch_root:/# mount -oremount,rw /sysroot
~~~
2. 切换为 chroot 存放位置,其中 /sysroot 被视为文件系统树的 root。
~~~
switch_root:/# chroot /sysroot
~~~
3. 设置 root 密码:
~~~
sh-4.2# passwd root
~~~
4. 确保所有未标记的文件(包括此时的 /etc/shadow)在启动过程中都会重新获得标记。
~~~
sh-4.2# touch /.autorelabel
~~~
5. 键入 exit 两次。第一次将退出 chroot 存放位置,第二次将退出 initramfs 调试 shell。
此时,系统将继续启动,执行完整的 SELinux 重新标记,然后再次重新启动。
## 诊断和修复 systemd 启动问题
如果在启动服务过程中出现问题,则有几个工具可供系统管理员用于协助调试和/或故障排除:
早期调试 shell
通过运行 systemctl enable debug-Shell.service,启动序列早期将在 TTY9(Ctrl+Alt+9)上生成一个 root Shell。该 Shell 会自动作为 root 登录,这样,管理员可以在系统仍在启动时使用一些其他调试工具。
### 警告
在完成调试后,请不要忘记禁用 debug-shell.service 服务,因为该服务会使未经身份验证的 root shell 向任何拥有本地控制台访问权限的人开放。
#### 紧急情况和救援目标
通过从启动加载器将 systemd.unit=rescue.target 或 systemd.unit=emergency.target 附加到内核命令行,系统将生成特殊的救援或紧急情况 shell,而不是正常启动。这两个 shell 都需要提供 root 密码。emergency 目标使 root 文件系统以只读方式挂载,而 rescue.target 会等待 sysinit.target 先完成,这样更多的系统会进行初始化,例如日志记录,文件系统等。从这些 shell 退出后,系统会继续进行常规启动过程。
#### 阻塞作业
在启动过程中,systemd 会生成大量作业。如果其中某些作业无法完成,则它们会防碍其他作业运行。要检查当前作业列表,管理员可以使用命令 systemctl list-jobs。所有列为 running的作业都必须完成,然后列为 waiting 的作业才可以继续。
### 参考
systemd.target、systemd.special、sulogin、sushell 和 systemctl man page
/usr/lib/systemd/system/debug-shell.service