Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]: initialRamdisk: Use systemd for initrd's /init #74842

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 1 addition & 20 deletions nixos/modules/system/boot/stage-1-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,6 @@ waitDevice() {
fi
}

# Mount special file systems.
specialMount() {
local device="$1"
local mountPoint="$2"
local options="$3"
local fsType="$4"

mkdir -m 0755 -p "$mountPoint"
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
}
source @earlyMountScript@

# Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
mkdir -p /tmp
mkfifo /tmp/stage-1-init.log.fifo
Expand Down Expand Up @@ -589,11 +577,4 @@ fi

mkdir -m 0755 -p $targetRoot/proc $targetRoot/sys $targetRoot/dev $targetRoot/run

mount --move /proc $targetRoot/proc
mount --move /sys $targetRoot/sys
mount --move /dev $targetRoot/dev
mount --move /run $targetRoot/run

exec env -i $(type -P switch_root) "$targetRoot" "$stage2Init"

fail # should never be reached
exec env -i $(type -P systemctl) switch-root --no-block "$targetRoot" "$stage2Init"
83 changes: 73 additions & 10 deletions nixos/modules/system/boot/stage-1.nix
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,23 @@ let
done
'';

busybox = (pkgs.busybox.override { enableStatic = true; }).overrideAttrs (old: {
postInstall = ''
${old.postInstall or ""}
${pkgs.nukeReferences}/bin/nuke-refs -e $out $out/bin/busybox
'';
allowedReferences = ["out"];
});
systemd = config.systemd.package.override { utillinux = busybox; };

# Some additional utilities needed in stage 1, like mount, lvm, fsck
# etc. We don't want to bring in all of those packages, so we just
# copy what we need. Instead of using statically linked binaries,
# we just copy what we need from Glibc and use patchelf to make it
# work.
extraUtils = pkgs.runCommandCC "extra-utils"
{ nativeBuildInputs = [pkgs.buildPackages.nukeReferences];
allowedReferences = [ "out" ]; # prevent accidents like glibc being included in the initrd
allowedReferences = [ "out" busybox ]; # prevent accidents like glibc being included in the initrd
}
''
set +o pipefail
Expand All @@ -103,8 +112,18 @@ let
}

# Copy BusyBox.
for BIN in ${pkgs.busybox}/{s,}bin/*; do
copy_bin_and_libs $BIN
for BIN in ${busybox}/{s,}bin/*; do
ln -sf $BIN $out/bin/
done

# Copy systemd
mkdir $out/lib/systemd
for b in $(find ${systemd}/lib/systemd -type f -executable -maxdepth 1 -not -name "*.so*"); do
copy_bin_and_libs $b
ln -s ../../bin/$(basename $b) $out/lib/systemd/$(basename $b)
done
for b in ${systemd}/bin/*; do
copy_bin_and_libs $b
done

# Copy some utillinux stuff.
Expand Down Expand Up @@ -170,14 +189,17 @@ let
# Run patchelf to make the programs refer to the copied libraries.
find $out/bin $out/lib -type f | while read i; do
if ! test -L $i; then
nuke-refs -e $out $i
nuke-refs -e $out -e ${busybox} $i
fi
done

find $out/bin -type f | while read i; do
find $out/bin $out/lib -type f | while read i; do
case $i in
$out/lib/ld*.so.?) continue;;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A default that nothing should happen would be a good idea.

esac
if ! test -L $i; then
echo "patching $i..."
patchelf --set-interpreter $out/lib/ld*.so.? --set-rpath $out/lib $i || true
patchelf $([ $(dirname $i) = $out/bin ] && echo --set-interpreter $out/lib/ld*.so.?) --set-rpath $out/lib $i || true
fi
done

Expand Down Expand Up @@ -261,8 +283,6 @@ let

inherit (config.boot) resumeDevice;

inherit (config.system.build) earlyMountScript;

inherit (config.boot.initrd) checkJournalingFS
preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules;

Expand All @@ -286,6 +306,40 @@ let
'';
};

switchRootService = pkgs.writeText "initrd-switch-root.service" ''
[Unit]
Description=Switch Root
DefaultDependencies=no
ConditionPathExists=/etc/initrd-release
OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
AllowIsolate=yes

[Service]
Type=oneshot
ExecStart=${bootStage1}
'';

systemdEtc = pkgs.runCommand "systemd-initrd-etc" {
allowedReferences = ["out" extraUtils switchRootService];
} ''
mkdir -p $out/system
for u in ${systemd}/example/systemd/system/*; do
if [ -d $u ]; then
cp -Pr $u $out/system/
else
substitute $u $out/system/$(basename $u) \
--replace ${systemd} ${extraUtils} \
--replace ${pkgs.kmod} ${extraUtils} \
--replace ${pkgs.bashInteractive}/bin/bash ${extraUtils}/bin/ash
fi
done
rm $out/system/default.target $out/system/initrd-switch-root.service
ln -s initrd.target $out/system/default.target
ln -s ${switchRootService} $out/system/initrd-switch-root.service
'';

initrdRelease = config.environment.etc."os-release".source;

# The closure of the init script of boot stage 1 is what we put in
# the initial RAM disk.
Expand All @@ -294,9 +348,18 @@ let
inherit (config.boot.initrd) compressor prepend;

contents =
[ { object = bootStage1;
[ { object = "${extraUtils}/bin/systemd";
symlink = "/init";
}
{ object = initrdRelease;
symlink = "/etc/initrd-release";
}
{ object = initrdRelease;
symlink = "/etc/os-release";
}
{ object = systemdEtc;
symlink = "/etc/systemd";
}
{ object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf;
symlink = "/etc/mdadm.conf";
}
Expand Down Expand Up @@ -557,7 +620,7 @@ in
];

system.build =
{ inherit bootStage1 initialRamdisk initialRamdiskSecretAppender extraUtils; };
{ inherit bootStage1 initialRamdisk initialRamdiskSecretAppender extraUtils systemdEtc; };

system.requiredKernelConfig = with config.lib.kernelConfig; [
(isYes "TMPFS")
Expand Down