破解 SystemD
我从事嵌入式 Linux 系统构建已有十多年了。这意味着我与 sysV 风格的 init 打过大量交道。它久经考验且非常稳健,但也有其局限性。目前有多个项目在努力挑战 sysinit 的主导地位,例如 Upstart 和 systemd。
我经常使用 Fedora 进行开发,既为无盘工作站构建 nfsroot 文件系统,也基于 Fedora 仓库构建嵌入式固件。Fedora 在这类工作中算是一个非主流选择;大多数人会选择 Debian 或 Ubuntu。
Fedora 早在 15 版本就迁移到了 systemd(译者注:systemd 的正式拼写即为 systemd,而非 SystemD,因文章标题如此保留)。由于 systemd 还很新,我决定暂缓脚步,不将所有的工具链升级到 Fedora 15。现在我们已更新到 17,情况看起来相当稳定。于是我决定试试看,用 Fedora 17 构建一个 nfsroot 系统。最终结果类似于 LTSP5/Meukow —— 只是所有的包都异常地新,感谢 Fedora 走在技术前沿。
关于 systemd 的文档比较匮乏,所以我在琢磨如何精简 systemd 时遇到了一些困难。对于 sysinit 来说,这要容易得多。你只需要剪切 rc.sysinit 文件,直到它看起来精简干练。你还可以用 chkconfig 来关闭无关的服务。当然还要禁用 selinux。Fedora 团队已经发布了一些关于调整和使用 systemd 的实用文档。他们还提供了 sysVinit 与 systemd 对照速查表 以及 调试指南。这些页面提供了很大的帮助。
当我第一次尝试启动 nfsroot 文件系统时,它无法启动。通过在内核命令行中添加:
systemd.confirm_spawn=true
我可以控制 systemd 中的每一个命令,并找出是哪个命令导致的崩溃。
systemd 的一个很棒的功能是,它可以在 chroot 文件系统上运行 chkconfig 风格的命令,而无需实际 chroot 进去。这和 yum 的 --installroot 功能类似 —— 我已用该功能来构建文件系统了。因此,要禁用新构建系统中的 crond 服务,你可以使用:
systemctl --system --root=$TARGET disable crond.service
其中 $TARGET 是你的 chroot 的路径。
systemd 会启动一些服务,这些服务无法使用上述命令来禁。链接到这些服务/命令的软链接也不存在于 /etc/systemd 目录中。我找到的唯一方法是从 /lib/systemd/system 中删除指向这些命令的符号链接。在我看来,对于嵌入式/桌面系统没什么用的一些命令和服务有:
/lib/systemd/system/sysinit.target.wants/*binfmt*
/lib/systemd/system/sysinit.target.wants/cryptsetup.target
/lib/systemd/system/sysinit.target.wants/dev-hugepages.target
/lib/systemd/system/basic.target.wants/fedora-configure.service
/lib/systemd/system/local-fs.target.wants/fedora-import-state.service
/lib/systemd/system/local-fs.target.wants/fedora-readonly.service
/lib/systemd/system/local-fs.target.wants/fedora-storage-init*.service