Merge pull request #167168 from helsinki-systems/feat/systemd-stage-1-proper-handover
nixos/stage-1-systemd: Handover between the systemds directly
This commit is contained in:
commit
c0139fe5c3
@ -55,11 +55,15 @@ let
|
|||||||
substituteInPlace $out/dry-activate --subst-var out
|
substituteInPlace $out/dry-activate --subst-var out
|
||||||
chmod u+x $out/activate $out/dry-activate
|
chmod u+x $out/activate $out/dry-activate
|
||||||
unset activationScript dryActivationScript
|
unset activationScript dryActivationScript
|
||||||
${pkgs.stdenv.shellDryRun} $out/activate
|
|
||||||
${pkgs.stdenv.shellDryRun} $out/dry-activate
|
|
||||||
|
|
||||||
|
${if config.boot.initrd.systemd.enable then ''
|
||||||
|
cp ${config.system.build.bootStage2} $out/prepare-root
|
||||||
|
substituteInPlace $out/prepare-root --subst-var-by systemConfig $out
|
||||||
|
ln -s "$systemd/lib/systemd/systemd" $out/init
|
||||||
|
'' else ''
|
||||||
cp ${config.system.build.bootStage2} $out/init
|
cp ${config.system.build.bootStage2} $out/init
|
||||||
substituteInPlace $out/init --subst-var-by systemConfig $out
|
substituteInPlace $out/init --subst-var-by systemConfig $out
|
||||||
|
''}
|
||||||
|
|
||||||
ln -s ${config.system.build.etc}/etc $out/etc
|
ln -s ${config.system.build.etc}/etc $out/etc
|
||||||
ln -s ${config.system.path} $out/sw
|
ln -s ${config.system.path} $out/sw
|
||||||
|
@ -5,28 +5,30 @@ systemConfig=@systemConfig@
|
|||||||
export HOME=/root PATH="@path@"
|
export HOME=/root PATH="@path@"
|
||||||
|
|
||||||
|
|
||||||
# Process the kernel command line.
|
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
|
||||||
for o in $(</proc/cmdline); do
|
# Process the kernel command line.
|
||||||
|
for o in $(</proc/cmdline); do
|
||||||
case $o in
|
case $o in
|
||||||
boot.debugtrace)
|
boot.debugtrace)
|
||||||
# Show each command.
|
# Show each command.
|
||||||
set -x
|
set -x
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
# Print a greeting.
|
# Print a greeting.
|
||||||
echo
|
echo
|
||||||
echo -e "\e[1;32m<<< NixOS Stage 2 >>>\e[0m"
|
echo -e "\e[1;32m<<< NixOS Stage 2 >>>\e[0m"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
|
||||||
# Normally, stage 1 mounts the root filesystem read/writable.
|
# Normally, stage 1 mounts the root filesystem read/writable.
|
||||||
# However, in some environments, stage 2 is executed directly, and the
|
# However, in some environments, stage 2 is executed directly, and the
|
||||||
# root is read-only. So make it writable here.
|
# root is read-only. So make it writable here.
|
||||||
if [ -z "$container" ]; then
|
if [ -z "$container" ]; then
|
||||||
mount -n -o remount,rw none /
|
mount -n -o remount,rw none /
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
@ -39,6 +41,12 @@ if [ ! -e /proc/1 ]; then
|
|||||||
local options="$3"
|
local options="$3"
|
||||||
local fsType="$4"
|
local fsType="$4"
|
||||||
|
|
||||||
|
# We must not overwrite this mount because it's bind-mounted
|
||||||
|
# from stage 1's /run
|
||||||
|
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" = true ] && [ "${mountPoint}" = /run ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
install -m 0755 -d "$mountPoint"
|
install -m 0755 -d "$mountPoint"
|
||||||
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
|
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
|
||||||
}
|
}
|
||||||
@ -46,7 +54,11 @@ if [ ! -e /proc/1 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
echo "booting system configuration $systemConfig" > /dev/kmsg
|
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" = true ]; then
|
||||||
|
echo "booting system configuration ${systemConfig}"
|
||||||
|
else
|
||||||
|
echo "booting system configuration $systemConfig" > /dev/kmsg
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Make /nix/store a read-only bind mount to enforce immutability of
|
# Make /nix/store a read-only bind mount to enforce immutability of
|
||||||
@ -68,24 +80,26 @@ if [ -n "@readOnlyStore@" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Use /etc/resolv.conf supplied by systemd-nspawn, if applicable.
|
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
|
||||||
if [ -n "@useHostResolvConf@" ] && [ -e /etc/resolv.conf ]; then
|
# Use /etc/resolv.conf supplied by systemd-nspawn, if applicable.
|
||||||
|
if [ -n "@useHostResolvConf@" ] && [ -e /etc/resolv.conf ]; then
|
||||||
resolvconf -m 1000 -a host </etc/resolv.conf
|
resolvconf -m 1000 -a host </etc/resolv.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
|
# Log the script output to /dev/kmsg or /run/log/stage-2-init.log.
|
||||||
# Only at this point are all the necessary prerequisites ready for these commands.
|
# Only at this point are all the necessary prerequisites ready for these commands.
|
||||||
exec {logOutFd}>&1 {logErrFd}>&2
|
exec {logOutFd}>&1 {logErrFd}>&2
|
||||||
if test -w /dev/kmsg; then
|
if test -w /dev/kmsg; then
|
||||||
exec > >(tee -i /proc/self/fd/"$logOutFd" | while read -r line; do
|
exec > >(tee -i /proc/self/fd/"$logOutFd" | while read -r line; do
|
||||||
if test -n "$line"; then
|
if test -n "$line"; then
|
||||||
echo "<7>stage-2-init: $line" > /dev/kmsg
|
echo "<7>stage-2-init: $line" > /dev/kmsg
|
||||||
fi
|
fi
|
||||||
done) 2>&1
|
done) 2>&1
|
||||||
else
|
else
|
||||||
mkdir -p /run/log
|
mkdir -p /run/log
|
||||||
exec > >(tee -i /run/log/stage-2-init.log) 2>&1
|
exec > >(tee -i /run/log/stage-2-init.log) 2>&1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
@ -116,11 +130,15 @@ ln -sfn "$systemConfig" /run/booted-system
|
|||||||
: >> /etc/machine-id
|
: >> /etc/machine-id
|
||||||
|
|
||||||
|
|
||||||
# Reset the logging file descriptors.
|
# No need to restore the stdout/stderr streams we never redirected and
|
||||||
exec 1>&$logOutFd 2>&$logErrFd
|
# especially no need to start systemd
|
||||||
exec {logOutFd}>&- {logErrFd}>&-
|
if [ "${IN_NIXOS_SYSTEMD_STAGE1:-}" != true ]; then
|
||||||
|
# Reset the logging file descriptors.
|
||||||
|
exec 1>&$logOutFd 2>&$logErrFd
|
||||||
|
exec {logOutFd}>&- {logErrFd}>&-
|
||||||
|
|
||||||
|
|
||||||
# Start systemd in a clean environment.
|
# Start systemd in a clean environment.
|
||||||
echo "starting systemd..."
|
echo "starting systemd..."
|
||||||
exec @systemdExecutable@ "$@"
|
exec @systemdExecutable@ "$@"
|
||||||
|
fi
|
||||||
|
@ -125,7 +125,7 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
initrdBinEnv = pkgs.buildEnv {
|
initrdBinEnv = pkgs.buildEnv {
|
||||||
name = "initrd-emergency-env";
|
name = "initrd-bin-env";
|
||||||
paths = map getBin cfg.initrdBin;
|
paths = map getBin cfg.initrdBin;
|
||||||
pathsToLink = ["/bin" "/sbin"];
|
pathsToLink = ["/bin" "/sbin"];
|
||||||
postBuild = concatStringsSep "\n" (mapAttrsToList (n: v: "ln -s '${v}' $out/bin/'${n}'") cfg.extraBin);
|
postBuild = concatStringsSep "\n" (mapAttrsToList (n: v: "ln -s '${v}' $out/bin/'${n}'") cfg.extraBin);
|
||||||
@ -355,8 +355,9 @@ in {
|
|||||||
boot.initrd.availableKernelModules = [ "autofs4" ]; # systemd needs this for some features
|
boot.initrd.availableKernelModules = [ "autofs4" ]; # systemd needs this for some features
|
||||||
|
|
||||||
boot.initrd.systemd = {
|
boot.initrd.systemd = {
|
||||||
initrdBin = [pkgs.bash pkgs.coreutils pkgs.kmod cfg.package] ++ config.system.fsPackages;
|
initrdBin = [pkgs.bash pkgs.coreutils cfg.package.kmod cfg.package] ++ config.system.fsPackages;
|
||||||
extraBin = {
|
extraBin = {
|
||||||
|
less = "${pkgs.less}/bin/less";
|
||||||
mount = "${cfg.package.util-linux}/bin/mount";
|
mount = "${cfg.package.util-linux}/bin/mount";
|
||||||
umount = "${cfg.package.util-linux}/bin/umount";
|
umount = "${cfg.package.util-linux}/bin/umount";
|
||||||
};
|
};
|
||||||
@ -367,7 +368,7 @@ in {
|
|||||||
|
|
||||||
"/etc/systemd/system.conf".text = ''
|
"/etc/systemd/system.conf".text = ''
|
||||||
[Manager]
|
[Manager]
|
||||||
DefaultEnvironment=PATH=/bin:/sbin
|
DefaultEnvironment=PATH=/bin:/sbin ${optionalString (isBool cfg.emergencyAccess && cfg.emergencyAccess) "SYSTEMD_SULOGIN_FORCE=1"}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
"/etc/fstab".source = fstab;
|
"/etc/fstab".source = fstab;
|
||||||
@ -394,7 +395,9 @@ in {
|
|||||||
"${cfg.package}/lib/systemd/systemd-journald"
|
"${cfg.package}/lib/systemd/systemd-journald"
|
||||||
"${cfg.package}/lib/systemd/systemd-makefs"
|
"${cfg.package}/lib/systemd/systemd-makefs"
|
||||||
"${cfg.package}/lib/systemd/systemd-modules-load"
|
"${cfg.package}/lib/systemd/systemd-modules-load"
|
||||||
|
"${cfg.package}/lib/systemd/systemd-random-seed"
|
||||||
"${cfg.package}/lib/systemd/systemd-remount-fs"
|
"${cfg.package}/lib/systemd/systemd-remount-fs"
|
||||||
|
"${cfg.package}/lib/systemd/systemd-shutdown"
|
||||||
"${cfg.package}/lib/systemd/systemd-sulogin-shell"
|
"${cfg.package}/lib/systemd/systemd-sulogin-shell"
|
||||||
"${cfg.package}/lib/systemd/systemd-sysctl"
|
"${cfg.package}/lib/systemd/systemd-sysctl"
|
||||||
"${cfg.package}/lib/systemd/systemd-udevd"
|
"${cfg.package}/lib/systemd/systemd-udevd"
|
||||||
@ -410,7 +413,7 @@ in {
|
|||||||
"${cfg.package.util-linux}/bin/sulogin"
|
"${cfg.package.util-linux}/bin/sulogin"
|
||||||
|
|
||||||
# so NSS can look up usernames
|
# so NSS can look up usernames
|
||||||
"${pkgs.glibc}/lib/libnss_files.so"
|
"${pkgs.glibc}/lib/libnss_files.so.2"
|
||||||
] ++ jobScripts;
|
] ++ jobScripts;
|
||||||
|
|
||||||
targets.initrd.aliases = ["default.target"];
|
targets.initrd.aliases = ["default.target"];
|
||||||
@ -428,9 +431,6 @@ in {
|
|||||||
(v: let n = escapeSystemdPath v.where;
|
(v: let n = escapeSystemdPath v.where;
|
||||||
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
|
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
|
||||||
|
|
||||||
services.emergency = mkIf (isBool cfg.emergencyAccess && cfg.emergencyAccess) {
|
|
||||||
environment.SYSTEMD_SULOGIN_FORCE = "1";
|
|
||||||
};
|
|
||||||
# The unit in /run/systemd/generator shadows the unit in
|
# The unit in /run/systemd/generator shadows the unit in
|
||||||
# /etc/systemd/system, but will still apply drop-ins from
|
# /etc/systemd/system, but will still apply drop-ins from
|
||||||
# /etc/systemd/system/foo.service.d/
|
# /etc/systemd/system/foo.service.d/
|
||||||
@ -445,6 +445,67 @@ in {
|
|||||||
'')];
|
'')];
|
||||||
services."systemd-makefs@".unitConfig.IgnoreOnIsolate = true;
|
services."systemd-makefs@".unitConfig.IgnoreOnIsolate = true;
|
||||||
services."systemd-growfs@".unitConfig.IgnoreOnIsolate = true;
|
services."systemd-growfs@".unitConfig.IgnoreOnIsolate = true;
|
||||||
|
|
||||||
|
services.initrd-nixos-activation = {
|
||||||
|
after = [ "initrd-fs.target" ];
|
||||||
|
requiredBy = [ "initrd.target" ];
|
||||||
|
unitConfig.AssertPathExists = "/etc/initrd-release";
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
description = "NixOS Activation";
|
||||||
|
|
||||||
|
script = /* bash */ ''
|
||||||
|
set -uo pipefail
|
||||||
|
export PATH="/bin:${cfg.package.util-linux}/bin"
|
||||||
|
|
||||||
|
# Figure out what closure to boot
|
||||||
|
closure=
|
||||||
|
for o in $(< /proc/cmdline); do
|
||||||
|
case $o in
|
||||||
|
init=*)
|
||||||
|
IFS== read -r -a initParam <<< "$o"
|
||||||
|
closure="$(dirname "''${initParam[1]}")"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Sanity check
|
||||||
|
if [ -z "''${closure:-}" ]; then
|
||||||
|
echo 'No init= parameter on the kernel command line' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we are not booting a NixOS closure (e.g. init=/bin/sh),
|
||||||
|
# we don't know what root to prepare so we don't do anything
|
||||||
|
if ! [ -x "/sysroot$closure/prepare-root" ]; then
|
||||||
|
echo "NEW_INIT=''${initParam[1]}" > /etc/switch-root.conf
|
||||||
|
echo "$closure does not look like a NixOS installation - not activating"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo 'NEW_INIT=' > /etc/switch-root.conf
|
||||||
|
|
||||||
|
|
||||||
|
# We need to propagate /run for things like /run/booted-system
|
||||||
|
# and /run/current-system.
|
||||||
|
mkdir -p /sysroot/run
|
||||||
|
mount --bind /run /sysroot/run
|
||||||
|
|
||||||
|
# Initialize the system
|
||||||
|
export IN_NIXOS_SYSTEMD_STAGE1=true
|
||||||
|
exec chroot /sysroot $closure/prepare-root
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# This will either call systemctl with the new init as the last parameter (which
|
||||||
|
# is the case when not booting a NixOS system) or with an empty string, causing
|
||||||
|
# systemd to bypass its verification code that checks whether the next file is a systemd
|
||||||
|
# and using its compiled-in value
|
||||||
|
services.initrd-switch-root.serviceConfig = {
|
||||||
|
EnvironmentFile = "-/etc/switch-root.conf";
|
||||||
|
ExecStart = [
|
||||||
|
""
|
||||||
|
''systemctl --no-block switch-root /sysroot "''${NEW_INIT}"''
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,23 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
|
|||||||
testScript = ''
|
testScript = ''
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
with subtest("handover to stage-2 systemd works"):
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
machine.succeed("systemd-analyze | grep -q '(initrd)'") # direct handover
|
||||||
|
machine.succeed("touch /testfile") # / is writable
|
||||||
|
machine.fail("touch /nix/store/testfile") # /nix/store is not writable
|
||||||
|
# Special filesystems are mounted by systemd
|
||||||
|
machine.succeed("[ -e /run/booted-system ]") # /run
|
||||||
|
machine.succeed("[ -e /sys/class ]") # /sys
|
||||||
|
machine.succeed("[ -e /dev/null ]") # /dev
|
||||||
|
machine.succeed("[ -e /proc/1 ]") # /proc
|
||||||
|
# stage-2-init mounted more special filesystems
|
||||||
|
machine.succeed("[ -e /dev/shm ]") # /dev/shm
|
||||||
|
machine.succeed("[ -e /dev/pts/ptmx ]") # /dev/pts
|
||||||
|
machine.succeed("[ -e /run/keys ]") # /run/keys
|
||||||
|
|
||||||
|
|
||||||
|
with subtest("growfs works"):
|
||||||
oldAvail = machine.succeed("df --output=avail / | sed 1d")
|
oldAvail = machine.succeed("df --output=avail / | sed 1d")
|
||||||
machine.shutdown()
|
machine.shutdown()
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ stdenv.mkDerivation rec {
|
|||||||
passthru.tests = {
|
passthru.tests = {
|
||||||
inherit (nixosTests) keymap kbd-setfont-decompress kbd-update-search-paths-patch;
|
inherit (nixosTests) keymap kbd-setfont-decompress kbd-update-search-paths-patch;
|
||||||
};
|
};
|
||||||
|
passthru.gzip = gzip;
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
homepage = "https://kbd-project.org/";
|
homepage = "https://kbd-project.org/";
|
||||||
|
@ -675,7 +675,7 @@ stdenv.mkDerivation {
|
|||||||
# runtime; otherwise we can't and we need to reboot.
|
# runtime; otherwise we can't and we need to reboot.
|
||||||
interfaceVersion = 2;
|
interfaceVersion = 2;
|
||||||
|
|
||||||
inherit withCryptsetup util-linux;
|
inherit withCryptsetup util-linux kmod kbd;
|
||||||
|
|
||||||
tests = {
|
tests = {
|
||||||
inherit (nixosTests) switchTest;
|
inherit (nixosTests) switchTest;
|
||||||
|
Loading…
Reference in New Issue
Block a user