![最小化 systemd 启动需要什么才能在虚拟控制台上启动 getty?](https://linux22.com/image/54280/%E6%9C%80%E5%B0%8F%E5%8C%96%20systemd%20%E5%90%AF%E5%8A%A8%E9%9C%80%E8%A6%81%E4%BB%80%E4%B9%88%E6%89%8D%E8%83%BD%E5%9C%A8%E8%99%9A%E6%8B%9F%E6%8E%A7%E5%88%B6%E5%8F%B0%E4%B8%8A%E5%90%AF%E5%8A%A8%20getty%EF%BC%9F.png)
对于 SysV init
,我需要/etc/inittab
重新生成 getty 条目、/sbin/init
二进制文件、shell 的二进制文件和共享库、login
PAM getty
/security/shadow 内容以及一些设备文件。
因为upstart
我需要几乎相同的要求,但不是/etc/inittab
,我在 下有一些*.conf
文件/etc/init
:一个 *.conf ,用于start on startup
设置运行级别telinit
,以及一个 *.conf ,用于每个getty
在适当的运行级别上在该 tty 上启动/重生的 tty 。
我需要什么配置和二进制文件systemd
init
?
我找到的所有文档似乎都集中在如何使用已安装的系统来启动和停止服务。
从运行中复制的最小文件列表(内核/initrd 除外)拱或者软呢帽安装就可以了,但我似乎找不到有关 的那种信息systemd
。
我想知道的是,对于systemd
,需要哪些文件以及它们必须包含什么,才能在 initramfsswitch_root
调用systemd
/sbin/init
.
upstart
二进制文件和两个文件的示例*.conf
:
文件/etc/init/whatever.conf
:
启动时开始 发出运行级别 任务 脚本 远程初始化2 结束脚本
文件/etc/init/tty1.conf
:
从运行级别开始 [12345] 重生 执行 /sbin/agetty -8 --noclear 38400 tty1 linux
示例sysvinit
,二进制文件和 1 个名为 的conf 文件/etc/inittab
:
id:2:初始化默认值: c1:12345:respawn:/sbin/agetty 38400 tty1 linux
现在我正在寻找systemd
同等的东西。
我假设某处至少*.service
需要 1 个文件,其中一个[Service]
条目包含ExecStart=-/sbin/agetty --noclear %I linux
and Restart=always
,但还需要什么?
答案1
首先,systemd
不是传统的unix init
。 Systemd 的功能要多得多,因此比较两者有点不公平。
要回答这个问题,似乎需要一些二进制文件和以下配置文件:
/usr/lib/systemd/system/default.target /usr/lib/systemd/system/basic.target /usr/lib/systemd/system/sysinit.target /usr/lib/systemd/system/getty.target /usr/lib/systemd/系统/[电子邮件受保护] /usr/lib/systemd/system/console-getty.service
然后发出创建这些符号链接:systemctl enable console-getty.service [email protected]
/etc/systemd/system/default.target.wants/[电子邮件受保护]-> /lib/systemd/system/getty@service /etc/systemd/system/getty.target.wants/console-getty.service -> /lib/systemd/system/console-getty.service
笔记:要利用systemd
的特殊功能来动态启动、按+agetty
时按需启动等,看来您还必须至少有这两个文件:AltF3
/etc/systemd/logind.conf /lib/systemd/系统/[电子邮件受保护]
其中[email protected]
是 的符号链接[email protected]
。
配置文件内容:
除了标记 和 (可能)之外, default.target
, getty.target
,文件可以为空。sysinit.target
[Unit]
Description=xxx
basic.target
还包含依赖信息:
[单元] 描述=基本系统 需要=sysinit.target Wants=sockets.targettimers.targetpaths.targetslices.target After=sysinit.targetsockets.targettimers.targetpaths.targetslices.target
我不确定是否需要对不作为文件存在的目标的引用。它们被描述在systemd.special(7)
手册页。
console-getty.service
: (控制台上agetty的特殊情况)
[单元] 描述=控制台 Getty After=systemd-user-sessions.service plymouth-quit-wait.service 之前=getty.target [服务] ExecStart=-/sbin/agetty --noclear --keep-baud console 115200,38400,9600 $TERM 类型=空闲 重新启动=始终 重启秒=0 UtmpIdentifier=缺点 TTYPath=/dev/console TTY重置=是 TTYV挂断=是 KillMode=进程 忽略SIGPIPE=否 发送SIGHUP=是 [安装] WantedBy=getty.target
[email protected]
:(除控制台外所有 getty 服务的通用配置)
[单元] 描述=%I 上的 Getty After=systemd-user-sessions.service plymouth-quit-wait.service 之前=getty.target 忽略隔离=是 条件路径存在=/dev/tty0 [服务] ExecStart=-/sbin/agetty --noclear %I $TERM 类型=空闲 重新启动=始终 重启秒=0 UtmpIdentifier=%I TTYPath=/dev/%I TTY重置=是 TTYV挂断=是 TTYVTDisallocate=否 KillMode=进程 忽略SIGPIPE=否 发送SIGHUP=是 [安装] WantedBy=getty.target 默认实例=tty1
最后,您可能需要一些特殊的二进制文件(我还没有尝试哪些是至关重要的):
/lib/systemd/systemd (/sbin/init 通常指向此) /lib/systemd/systemd-logind /lib/systemd/systemd-cgroups-agent /lib/systemd/systemd-用户会话 /lib/systemd/systemd-vconsole-setup /lib/systemd/systemd-update-utmp /lib/systemd/systemd-sleep /lib/systemd/systemd-sysctl /lib/systemd/systemd-initctl /lib/systemd/systemd-回复密码 /lib/systemd/systemd-ac-power /lib/systemd/systemd-activate /lib/systemd/systemd-背光 /lib/systemd/systemd-binfmt /lib/systemd/systemd-bootchart /lib/systemd/systemd-bus-proxyd /lib/systemd/systemd-coredump /lib/systemd/systemd-cryptsetup /lib/systemd/systemd-fsck /lib/systemd/systemd-主机名 /lib/systemd/systemd-journald /lib/systemd/systemd-journal-gatewayd /lib/systemd/systemd-journal-remote /lib/systemd/systemd-localed /lib/systemd/systemd-machined /lib/systemd/systemd-modules-load /lib/systemd/systemd-multi-seat-x /lib/systemd/systemd-networkd /lib/systemd/systemd-networkd-wait-online /lib/systemd/systemd-quotacheck /lib/systemd/systemd-随机种子 /lib/systemd/systemd-readahead /lib/systemd/systemd-remount-fs /lib/systemd/systemd-resolved /lib/systemd/systemd-rfkill /lib/systemd/systemd-shutdown /lib/systemd/systemd-shutdownd /lib/systemd/systemd-socket-proxyd /lib/systemd/systemd-timedated /lib/systemd/systemd-timesyncd /lib/systemd/systemd-udevd /lib/systemd/systemd-update-done
总结一下systemd的启动过程,我认为它的工作原理是这样的:
- systemd 定位
basic.target
(或所有*.target
文件?) - 依赖项根据和配置文件部分中的
WantedBy=
、Wants=
、Before=
、After=
... 指令来解析。[Install]
*.service
*.target
*.service
应该启动的服务(不是“特殊”服务),有一个[Service]
带有指令的部分ExecStart=
,指出要启动的可执行文件。
答案2
systemd
当您切换到终端时,会自动创建一个 getty,最多可达一定的最大数量。默认值为 6(因此您会自动获得 alt+f1 到 alt+f6 的 getty)。如果您想更改此参数,您可以编辑/etc/systemd/logind.conf
将参数更改NAutoVTs
为其他数字(最多 12)
如果您希望生成 getty,即使您不手动切换,您也可以向该目录添加符号链接:/usr/lib/systemd/system/[email protected]
/etc/systemd/system/getty.target.wants/
ln -sf /usr/lib/systemd/system/[email protected] /etc/systemd/system/getty.target.wants/[email protected]
这将导致getty.target
需要再提供一项getty@
服务。目标是需要生成的服务的集合,替换支持依赖项的运行级别。默认目标取决于getty.target
编辑: 我又研究了一些文档。
启动时,systemd
守护进程会加载目标中的所有系统default
及其依赖项。目标由文件定义
/etc/systemd/system/default.target
/usr/lib/systemd/system/default.target
目标具有由目录中的符号链接指定的附加服务列表
/etc/systemd/system/default.target.wants
/usr/lib/systemd/system/default.target.wants
该/etc
版本覆盖/usr/lib
.仅需要其中一个文件.target
,而不需要任何目录
getty
只是可以由 init 脚本运行的服务之一。在我检查的发行版(fedora、arch)中,getty
以两种不同的方式运行:
- 由每个终端的特定脚本启动(链接到其中的文件
/usr/lib/systemd/system/[email protected]
tty 名称被替换为systemd
链接文件名中的) logind
当用户切换到虚拟终端时,根据需要自动启动(类似于旧的inetd
仅在请求到达时启动服务的方式)。logind
是随 一起分发的不同守护进程systemd
,并从文件中读取其配置/etc/systemd/logind.conf
。
希望这令人满意。
答案3
经过一些实验,我发现一对目标服务就足以启动。复制自emergency.service
:
[Unit]
DefaultDependencies=no
Description=shell.service: Console and Login
[Service]
Environment=HOME=/root
WorkingDirectory=-/root
ExecStart=-/usr/lib/systemd/systemd-sulogin-shell
ExecStartPost=/usr/bin/openvt -f -c 16 agetty tty16
ExecStartPost=/usr/bin/openvt -f -c 17 -- agetty -p tty17
ExecStartPost=/usr/bin/openvt -f -c 18 -- agetty -p -a USER tty18
Type=idle
StandardInput=tty-force
StandardOutput=inherit
StandardError=inherit
#KillMode=process
KillMode=control-group
IgnoreSIGPIPE=no
SendSIGHUP=yes
用于测试:将发行版的单元目录重命名为/lib/systemd/systemDEACT
是一种简单但彻底的方法,可以将单元/单元文件的数量从 200 个减少到 10 个;还是有一些假的:
UNIT LOAD ACTIVE SUB DESCRIPTION
dev-sda3.device loaded activating tentative /dev/sda3
-.mount loaded active mounted Root Mount
tmp.mount loaded active mounted /tmp
init.scope loaded active running System and Service Manager
io.service loaded inactive dead io: usbhid kmod for keyboard
remount.service loaded inactive dead remount: rw for / and tmpfs for /tmp
shell.service loaded active running shell.service: Console and Login
-.slice loaded active active Root Slice
system.slice loaded active active System Slice
* systemd-journald.socket not-found inactive dead systemd-journald.socket
* local-fs-pre.target not-found inactive dead local-fs-pre.target
* local-fs.target not-found inactive dead local-fs.target
mini.target loaded active active "mini": Minimal Boot and Shell
* swap.target not-found inactive dead swap.target
* umount.target not-found inactive dead umount.target
在旁边shell.service
(见顶部)我做了一个remount.service
和io.service
;这modprobe usbhid
对于我的(任何?)USB 键盘至关重要。重新挂载服务需要与 arch 的 initrd 脚本中的 fsck 同步以进行重新挂载,并与 tmp.mount 进行同步/tmp
。我还必须找出将其rw
正确放置在 KCL 上的位置...同时,我[OK]
在启动时从两个一次性和一个闲置的服务。
依赖树是:
mini.target
* |-io.service
* |-remount.service
* `-shell.service
由于我remount
与 KCL 的冗余/冲突并且io
只是执行modprobe usbhid
(也可以通过ExecStart...
in完成shell.service
),这只是一个目标/服务对。default.target
如果不添加systemd.unit=mini.target
内核 CL,请加上链接。
我花了几个小时追逐暂定的 dev-sdaX.device
(唯一的,根分区);现在我认为这已经是正常的一半了。
-.mount
和是内在的-.slice
并且init.scope
有意义。
tmp.mount
我认为是在 中生成的/run
。
Journald not-found
、local-fs、swap 和 umount 单元似乎不会损害 systemd;与--state loaded
他们没有显示。它们可能应该被创建为第一个附加单元。但是如何定义local-fs
根分区何时已经从 initrd 检查过呢?可以用 initrd 启动吗最小的?
systemctl status
也是最小的。有一个切片,但只有一个(没有 user-X 切片):
* archlinux
State: running
Jobs: 0 queued
Failed: 0 units
Since: Fri 2021-10-01 15:24:16 UTC; 3min 2s ago
CGroup: /
|-init.scope
| `-1 /sbin/init arch\x5cvmlinuz-linux
`-system.slice
`-shell.service
|-215 /usr/lib/systemd/systemd-sulogin-shell
|-219 bash
|-220 agetty tty16
|-222 agetty -p tty17
|-225 agetty -p -a USER tty18
`-238 systemctl status
您KillMode
可以控制 shell.service 内进程发生的情况。对应的ps axf
是:
1 ? Ss 0:00 /sbin/init arch\vmlinuz-linux
215 tty1 Ss 0:00 /usr/lib/systemd/systemd-sulogin-shell
219 tty1 S 0:00 \_ bash
245 tty1 R+ 0:00 \_ ps axf
246 tty1 S+ 0:00 \_ tail -8
220 tty16 Ss+ 0:00 agetty tty16
222 tty17 Ss+ 0:00 agetty -p tty17
225 tty18 Ss+ 0:00 agetty -p -a USER tty18
sagetty
没有父母 - 感谢openvt
? - 但 PID1/init/systemd 仍然跟踪 pid。我能够shell.service
用不同的KillMode
s 重新启动。
不建议在 sulogin-shell 上使用Actrl-D
或......exit
我怎样才能阻止这一切呢?
之后,激进的目录重命名reboot
命令“无法与 init 守护进程对话”等等。reboot.service
具有操作(不重新启动,不立即重新启动)的(副本)reboot-force
是最直接的出路,并且足以用于此测试启动(没有日志运行等)。 Sysvinit 关闭也不是很优雅,也不是很快。systemctl start reboot
然后执行 PID 信号发送和终止,以及sync
(我猜),但没有其他命令关闭。这将是一个“最终”或“关闭”目标,从那里您可以转到CPUreboot
或poweroff
。halt
带或不带 shutdown-initramfs。
因此systemd
可以在没有journald、udevd 和dbus 以及所有这些单元文件和--user
实例的情况下启动和运行(和停止!)。但是很难“超级屏蔽”(即消失)这 200 个发行版单元,而且仍然存在一些内置单元和内置逻辑的痕迹。
长话短说: emergency.target
, DefaultDependencies=no
,openvt