On Thu, Nov 22, 2012 at 06:44:38PM +0100, Tom Gundersen wrote:
This is based on dracut, but with all the glue-scripts removed.
Idea is: * start systemd/udevd/journald * wait for the root device to appear * mount the rootfs * isolate the switch-root target * this shuts down/cleans up everything * then calls systemctl to switch to the new root and reexec systemd
Note: generate initramfs with HOOKS=('base' 'fsck' 'systemd') to get all the needed binaries (such as mount and fsck and busybox for debugging).
This is fine for now, but I think eventually, this should be an alterate "base" hook called sd-base, or similar. Some initial comments below, mostly about the install hook. I hacked around some of the problem you/I mention and it does boot a (very simple) VM of mine, but there's certainly a ways to go. Neat.
TODO:
* patch systemctl to read init= from /proc/cmdline if it is not given as an argument to switch-root (now it always reexecs systemd) * make a rootfs-mount-from-proc-cmdline generator instead of a hardcoded new_root.mount * include more systemd units and helpers, should reveiw them all * discuss with dracut/systemd people the possibility of putting something like this in the systemd repo so we don't have to duplicate work --- initrd-pre-switch-root.service | 19 ++++++++++++ initrd-switch-root.service | 20 +++++++++++++ initrd-switch-root.target | 16 ++++++++++ install/systemd | 68 ++++++++++++++++++++++++++++++++++++++++++ new_root.mount | 15 ++++++++++ udevadm-cleanup-db.service | 18 +++++++++++ 6 files changed, 156 insertions(+) create mode 100644 initrd-pre-switch-root.service create mode 100644 initrd-switch-root.service create mode 100644 initrd-switch-root.target create mode 100644 install/systemd create mode 100644 new_root.mount create mode 100644 udevadm-cleanup-db.service
None of this stuff is ever installed aside from the install hook.
diff --git a/initrd-pre-switch-root.service b/initrd-pre-switch-root.service new file mode 100644 index 0000000..ae6a731 --- /dev/null +++ b/initrd-pre-switch-root.service @@ -0,0 +1,19 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +# See systemd.special(7) for details + +[Unit] +Description=Waiting for new root device to appear +DefaultDependencies=no +Requires=new_root.mount +After=new_root.mount +ConditionPathExists=/etc/initrd-release + +[Service] +Type=oneshot +ExecStart=/usr/bin/systemctl --no-block isolate initrd-switch-root.target diff --git a/initrd-switch-root.service b/initrd-switch-root.service new file mode 100644 index 0000000..03ff9a8 --- /dev/null +++ b/initrd-switch-root.service @@ -0,0 +1,20 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Switch Root +DefaultDependencies=no +ConditionPathExists=/etc/initrd-release +OnFailure=emergency.service +After=initrd-switch-root.target new_root.mount +AllowIsolate=yes + +[Service] +Type=oneshot +# we have to use "--force" here, otherwise systemd would umount /run +ExecStart=/usr/bin/systemctl --no-block --force switch-root /new_root +KillMode=none diff --git a/initrd-switch-root.target b/initrd-switch-root.target new file mode 100644 index 0000000..fd23908 --- /dev/null +++ b/initrd-switch-root.target @@ -0,0 +1,16 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +# See systemd.special(7) for details + +[Unit] +Description=Switch Root +DefaultDependencies=no +Requires=initrd-switch-root.service +Before=initrd-switch-root.service +AllowIsolate=yes +ConditionPathExists=/etc/initrd-release diff --git a/install/systemd b/install/systemd new file mode 100644 index 0000000..9b38bdf --- /dev/null +++ b/install/systemd @@ -0,0 +1,68 @@ +#!/bin/bash + +build() { + local rules tool socket service + + add_binary /usr/lib/systemd/systemd /init + add_binary /usr/bin/systemctl + add_binary /bin/mount + add_binary /usr/bin/udevadm + add_binary /usr/lib/systemd/systemd-udevd + add_binary /usr/lib/systemd/systemd-journald + # for debugging + add_binary /bin/bash
You have /bin/ash from busybox.
+ add_binary /usr/bin/journalctl + + for rules in 50-udev-default.rules 60-persistent-storage.rules 64-btrfs.rules 80-drivers.rules 99-systemd.rules; do + add_file "/usr/lib/udev/rules.d/$rules" + done + for tool in ata_id scsi_id; do + add_file "/usr/lib/udev/$tool" + done
So I guess the goal here is that the systemd hook would replace the udev hook? That seems a little weird. We don't have any concept of hook dependencies or conflicts (though this part is perhaps intentional) which doesn't really help.
+ for socket in systemd-udevd-control systemd-udevd-kernel systemd-journald; do + add_file "/usr/lib/systemd/system/$socket.socket" + add_symlink "/usr/lib/systemd/system/sockets.target.wants/$socket.socket" "../$socket.socket" + done + for service in systemd-udevd systemd-udev-trigger systemd-journald debug-shell; do + add_file "/usr/lib/systemd/system/$service.service" + add_symlink "/usr/lib/systemd/system/sysinit.target.wants/$service.service" "../$service.service" + done + for target in sysinit sockets basic local-fs local-fs-pre remote-fs remote-fs-pre initrd-switch-root; do + add_file "/usr/lib/systemd/system/$target.target" + done + + # wtf? + add_file "/etc/passwd" + add_file "/etc/shadow" + add_file "/etc/group" + add_file "/etc/gshadow" + add_file "/etc/nsswitch.conf" + # (wtf?)^2
What is it that actually wants these things?
+ add_file "/lib/libnsl-2.16.so" + add_symlink "/lib/libnsl.so" "libnsl.so.1" + add_symlink "/lib/libnsl.so.1" "libnsl-2.16.so" + add_file "/lib/libnss_files-2.16.so" + add_symlink "/lib/libnss_files.so" "libnss_files.so.2" + add_symlink "/lib/libnss_files.so.2" "libnss_files-2.16.so"
This makes us need to move in lockstep with glibc. I'm way too lazy for that.
+ + + add_file "/usr/lib/systemd/system/systemd-fsck@.service" + add_file "/usr/lib/systemd/system/initrd-switch-root.service" + add_symlink "/usr/lib/systemd/system/initrd-switch-root.target.wants/initrd-switch-root.service" "../initrd-switch-root.service" + add_file "/usr/lib/systemd/system/initrd-pre-switch-root.service" + add_symlink "/usr/lib/systemd/system/basic.target.wants/initrd-pre-switch-root.service" "../initrd-pre-switch-root.service" + + add_symlink "/usr/lib/systemd/system/default.target" "basic.target" + + # this should be done by a generator (based on /proc/cmdline), and not be hardcoded for my machine... + add_file "/usr/lib/systemd/system/new_root.mount"
This never gets installed, despite being included.
+ add_symlink "/usr/lib/systemd/system/local-fs.target.wants/new_root.mount" "../new_root.mount" +} + +help() { + cat <<HELPEOF +This will install a basic systemd setup on your initrd, you might want to add more hooks to get more advanced functionality. +HELPEOF +} + +# vim: set ft=sh ts=4 sw=4 et: diff --git a/new_root.mount b/new_root.mount new file mode 100644 index 0000000..9cb8338 --- /dev/null +++ b/new_root.mount @@ -0,0 +1,15 @@ +# Automatically generated by systemd-root-proc-cmdline-generator
Not sure this proposed name is long enough ;P
+ +[Unit] +SourcePath=/proc/cmdline +DefaultDependencies=no +After=local-fs-pre.target +Wants=local-fs-pre.target +Before=local-fs.target + +[Mount] +What=/dev/sda3 +Where=/new_root +Type=btrfs +FsckPassNo=0 +Options=defaults diff --git a/udevadm-cleanup-db.service b/udevadm-cleanup-db.service new file mode 100644 index 0000000..983189e --- /dev/null +++ b/udevadm-cleanup-db.service @@ -0,0 +1,18 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Cleanup udevd DB +DefaultDependencies=no +ConditionPathExists=/etc/initrd-release +Conflicts=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket +After=systemd-udevd.service systemd-udevd-control.socket systemd-udevd-kernel.socket +Before=initrd-switch-root.target + +[Service] +Type=oneshot +ExecStart=-/usr/bin/udevadm info --cleanup-db
Why does this need to exist? Can't we just "fix" the systemd-udevd service file to do as a PreExecStop= and make initrd-switch-root.target provide the right conflicts to trigger that?
-- 1.8.0