[arch-projects] [mkinitcpio][PATCH] [WIP] systemd: add systemd hook and needed files

Dave Reisner d at falconindy.com
Thu Nov 22 13:32:17 EST 2012


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 at .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
> 


More information about the arch-projects mailing list