[arch-projects] [mkinitcpio][PATCH] [WIP] systemd: add systemd hook and needed files
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). 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 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 + 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 + 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 + 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" + + + 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" + 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 + +[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 -- 1.8.0
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
On Thu, Nov 22, 2012 at 7:32 PM, Dave Reisner <d@falconindy.com> wrote:
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.
Yeah, that makes sense. I thought I'd reuse the old hooks for now until it is clear exactly what we need. As you note below, the lack of dependencies between hooks means we'll get quite a bit of duplication.
None of this stuff is ever installed aside from the install hook.
Yeah, I forgot about changes to the Makefile. I was hoping that all of this stuff would anyway live in the systemd repo, but we'll see.
You have /bin/ash from busybox.
Good catch, would have to add a symlink from bash though as that's what debug-shell.service calls.
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.
Not sure what the best way to go is. I'm tempted to say that all the things that are needed by this hook should be part of it (as we don't have deps). Whether or not a separate stand-alone udev hook makes sense in the long-term, I will leave open...
+ # 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?
"systemctl switch-root" is not happy without them. I don't understand 1) why not and 2) why the libs are not pulled in. This <http://randombitsofuselessinformation.blogspot.fr/2007/12/dbus-could-not-get-password-database.html> outlines the problem.
+ 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.
Anything marked with "wtf?" should hopefully go away before we ship this ;-)
Not sure this proposed name is long enough ;P
Hehe, suggestions welcome :-)
+[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?
PostExecStop I guess? I don't see why it would not work, except that it would obviously not be specific to the iniramfs, if that matters I don't know. If I go ahead and submit this upstream I'll suggest the PostExecStop approach first to see if there are objections. Thanks for the comments. -t
participants (2)
-
Dave Reisner
-
Tom Gundersen