Loading nixos/modules/system/activation/top-level.nix +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,12 @@ let ''} ln -s ${config.system.build.etc}/etc $out/etc ${lib.optionalString config.system.etc.overlay.enable '' ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image ln -s ${config.system.build.etcBasedir} $out/etc-basedir ''} ln -s ${config.system.path} $out/sw ln -s "$systemd" $out/systemd Loading nixos/modules/system/boot/systemd/initrd.nix +55 −9 Original line number Diff line number Diff line Loading @@ -507,12 +507,20 @@ in { in nameValuePair "${n}.automount" (automountToUnit v)) cfg.automounts); services.initrd-nixos-activation = { after = [ "initrd-fs.target" ]; services.initrd-find-nixos-closure = { description = "Find NixOS closure"; unitConfig = { RequiresMountsFor = "/sysroot/nix/store"; DefaultDependencies = false; }; before = [ "shutdown.target" ]; conflicts = [ "shutdown.target" ]; requiredBy = [ "initrd.target" ]; unitConfig.AssertPathExists = "/etc/initrd-release"; serviceConfig.Type = "oneshot"; description = "NixOS Activation"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = /* bash */ '' set -uo pipefail Loading Loading @@ -542,6 +550,8 @@ in { # Assume the directory containing the init script is the closure. closure="$(dirname "$closure")" ln --symbolic "$closure" /nixos-closure # 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$(readlink "/sysroot$closure/prepare-root" || echo "$closure/prepare-root")" ]; then Loading @@ -550,12 +560,48 @@ in { 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 mounts = [ { where = "/sysroot/run"; what = "/run"; options = "bind"; unitConfig = { # See the comment on the mount unit for /run/etc-metadata DefaultDependencies = false; }; requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; } ]; services.initrd-nixos-activation = { requires = [ config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; after = [ "initrd-fs.target" config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; requiredBy = [ "initrd.target" ]; unitConfig = { AssertPathExists = "/etc/initrd-release"; RequiresMountsFor = [ "/sysroot/run" ]; }; serviceConfig.Type = "oneshot"; description = "NixOS Activation"; script = /* bash */ '' set -uo pipefail export PATH="/bin:${cfg.package.util-linux}/bin" closure="$(realpath /nixos-closure)" # Initialize the system export IN_NIXOS_SYSTEMD_STAGE1=true Loading nixos/modules/system/etc/etc-activation.nix +88 −21 Original line number Diff line number Diff line { config, lib, ... }: { config, lib, pkgs, ... }: { Loading Loading @@ -34,12 +34,30 @@ mounts = [ { where = "/run/etc-metadata"; what = "/sysroot${config.system.build.etcMetadataImage}"; what = "/etc-metadata-image"; type = "erofs"; options = "loop"; unitConfig.RequiresMountsFor = [ unitConfig = { # Since this unit depends on the nix store being mounted, it cannot # be a dependency of local-fs.target, because if it did, we'd have # local-fs.target ordered after the nix store mount which would cause # things like network.target to only become active after the nix store # has been mounted. # This breaks for instance setups where sshd needs to be up before # any encrypted disks can be mounted. DefaultDependencies = false; RequiresMountsFor = [ "/sysroot/nix/store" ]; }; requires = [ config.boot.initrd.systemd.services.initrd-find-etc.name ]; after = [ config.boot.initrd.systemd.services.initrd-find-etc.name ]; requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; } { where = "/sysroot/etc"; Loading @@ -49,7 +67,7 @@ "relatime" "redirect_dir=on" "metacopy=on" "lowerdir=/run/etc-metadata::/sysroot${config.system.build.etcBasedir}" "lowerdir=/run/etc-metadata::/etc-basedir" ] ++ lib.optionals config.system.etc.overlay.mutable [ "rw" "upperdir=/sysroot/.rw-etc/upper" Loading @@ -59,16 +77,30 @@ ]); requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; requires = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ]; after = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ]; unitConfig.RequiresMountsFor = [ requires = [ config.boot.initrd.systemd.services.initrd-find-etc.name ] ++ lib.optionals config.system.etc.overlay.mutable [ config.boot.initrd.systemd.services."rw-etc".name ]; after = [ config.boot.initrd.systemd.services.initrd-find-etc.name ] ++ lib.optionals config.system.etc.overlay.mutable [ config.boot.initrd.systemd.services."rw-etc".name ]; unitConfig = { RequiresMountsFor = [ "/sysroot/nix/store" "/run/etc-metadata" ]; DefaultDependencies = false; }; } ]; services = lib.mkIf config.system.etc.overlay.mutable { services = lib.mkMerge [ (lib.mkIf config.system.etc.overlay.mutable { rw-etc = { requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; unitConfig = { DefaultDependencies = false; RequiresMountsFor = "/sysroot"; Loading @@ -80,7 +112,42 @@ ''; }; }; }) { initrd-find-etc = { description = "Find the path to the etc metadata image and based dir"; requires = [ config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; after = [ config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; before = [ "shutdown.target" ]; conflicts = [ "shutdown.target" ]; requiredBy = [ "initrd.target" ]; unitConfig = { DefaultDependencies = false; RequiresMountsFor = "/sysroot/nix/store"; }; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = /* bash */ '' set -uo pipefail closure="$(realpath /nixos-closure)" metadata_image="$(chroot /sysroot ${lib.getExe' pkgs.coreutils "realpath"} "$closure/etc-metadata-image")" ln -s "/sysroot$metadata_image" /etc-metadata-image basedir="$(chroot /sysroot ${lib.getExe' pkgs.coreutils "realpath"} "$closure/etc-basedir")" ln -s "/sysroot$basedir" /etc-basedir ''; }; } ]; }; }) Loading nixos/tests/activation/etc-overlay-immutable.nix +14 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ boot.kernelPackages = pkgs.linuxPackages_latest; time.timeZone = "Utc"; # The standard resolvconf service tries to write to /etc and crashes, # which makes nixos-rebuild exit uncleanly when switching into the new generation services.resolved.enable = true; environment.etc = { "mountpoint/.keep".text = "keep"; "filemount".text = "keep"; Loading @@ -26,6 +30,13 @@ }; testScript = '' with subtest("/run/etc-metadata/ is mounted"): print(machine.succeed("mountpoint /run/etc-metadata")) with subtest("No temporary files leaked into stage 2"): machine.succeed("[ ! -e /etc-metadata-image ]") machine.succeed("[ ! -e /etc-basedir ]") with subtest("/etc is mounted as an overlay"): machine.succeed("findmnt --kernel --type overlay /etc") Loading @@ -50,6 +61,9 @@ with subtest("switching to the same generation"): machine.succeed("/run/current-system/bin/switch-to-configuration test") with subtest("the initrd didn't get rebuilt"): machine.succeed("test /run/current-system/initrd -ef /run/current-system/specialisation/new-generation/initrd") with subtest("switching to a new generation"): machine.fail("stat /etc/newgen") Loading nixos/tests/activation/etc-overlay-mutable.nix +10 −0 Original line number Diff line number Diff line Loading @@ -18,12 +18,22 @@ }; testScript = '' with subtest("/run/etc-metadata/ is mounted"): print(machine.succeed("mountpoint /run/etc-metadata")) with subtest("No temporary files leaked into stage 2"): machine.succeed("[ ! -e /etc-metadata-image ]") machine.succeed("[ ! -e /etc-basedir ]") with subtest("/etc is mounted as an overlay"): machine.succeed("findmnt --kernel --type overlay /etc") with subtest("switching to the same generation"): machine.succeed("/run/current-system/bin/switch-to-configuration test") with subtest("the initrd didn't get rebuilt"): machine.succeed("test /run/current-system/initrd -ef /run/current-system/specialisation/new-generation/initrd") with subtest("switching to a new generation"): machine.fail("stat /etc/newgen") machine.succeed("echo -n 'mutable' > /etc/mutable") Loading Loading
nixos/modules/system/activation/top-level.nix +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,12 @@ let ''} ln -s ${config.system.build.etc}/etc $out/etc ${lib.optionalString config.system.etc.overlay.enable '' ln -s ${config.system.build.etcMetadataImage} $out/etc-metadata-image ln -s ${config.system.build.etcBasedir} $out/etc-basedir ''} ln -s ${config.system.path} $out/sw ln -s "$systemd" $out/systemd Loading
nixos/modules/system/boot/systemd/initrd.nix +55 −9 Original line number Diff line number Diff line Loading @@ -507,12 +507,20 @@ in { in nameValuePair "${n}.automount" (automountToUnit v)) cfg.automounts); services.initrd-nixos-activation = { after = [ "initrd-fs.target" ]; services.initrd-find-nixos-closure = { description = "Find NixOS closure"; unitConfig = { RequiresMountsFor = "/sysroot/nix/store"; DefaultDependencies = false; }; before = [ "shutdown.target" ]; conflicts = [ "shutdown.target" ]; requiredBy = [ "initrd.target" ]; unitConfig.AssertPathExists = "/etc/initrd-release"; serviceConfig.Type = "oneshot"; description = "NixOS Activation"; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = /* bash */ '' set -uo pipefail Loading Loading @@ -542,6 +550,8 @@ in { # Assume the directory containing the init script is the closure. closure="$(dirname "$closure")" ln --symbolic "$closure" /nixos-closure # 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$(readlink "/sysroot$closure/prepare-root" || echo "$closure/prepare-root")" ]; then Loading @@ -550,12 +560,48 @@ in { 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 mounts = [ { where = "/sysroot/run"; what = "/run"; options = "bind"; unitConfig = { # See the comment on the mount unit for /run/etc-metadata DefaultDependencies = false; }; requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; } ]; services.initrd-nixos-activation = { requires = [ config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; after = [ "initrd-fs.target" config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; requiredBy = [ "initrd.target" ]; unitConfig = { AssertPathExists = "/etc/initrd-release"; RequiresMountsFor = [ "/sysroot/run" ]; }; serviceConfig.Type = "oneshot"; description = "NixOS Activation"; script = /* bash */ '' set -uo pipefail export PATH="/bin:${cfg.package.util-linux}/bin" closure="$(realpath /nixos-closure)" # Initialize the system export IN_NIXOS_SYSTEMD_STAGE1=true Loading
nixos/modules/system/etc/etc-activation.nix +88 −21 Original line number Diff line number Diff line { config, lib, ... }: { config, lib, pkgs, ... }: { Loading Loading @@ -34,12 +34,30 @@ mounts = [ { where = "/run/etc-metadata"; what = "/sysroot${config.system.build.etcMetadataImage}"; what = "/etc-metadata-image"; type = "erofs"; options = "loop"; unitConfig.RequiresMountsFor = [ unitConfig = { # Since this unit depends on the nix store being mounted, it cannot # be a dependency of local-fs.target, because if it did, we'd have # local-fs.target ordered after the nix store mount which would cause # things like network.target to only become active after the nix store # has been mounted. # This breaks for instance setups where sshd needs to be up before # any encrypted disks can be mounted. DefaultDependencies = false; RequiresMountsFor = [ "/sysroot/nix/store" ]; }; requires = [ config.boot.initrd.systemd.services.initrd-find-etc.name ]; after = [ config.boot.initrd.systemd.services.initrd-find-etc.name ]; requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; } { where = "/sysroot/etc"; Loading @@ -49,7 +67,7 @@ "relatime" "redirect_dir=on" "metacopy=on" "lowerdir=/run/etc-metadata::/sysroot${config.system.build.etcBasedir}" "lowerdir=/run/etc-metadata::/etc-basedir" ] ++ lib.optionals config.system.etc.overlay.mutable [ "rw" "upperdir=/sysroot/.rw-etc/upper" Loading @@ -59,16 +77,30 @@ ]); requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; requires = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ]; after = lib.mkIf config.system.etc.overlay.mutable [ "rw-etc.service" ]; unitConfig.RequiresMountsFor = [ requires = [ config.boot.initrd.systemd.services.initrd-find-etc.name ] ++ lib.optionals config.system.etc.overlay.mutable [ config.boot.initrd.systemd.services."rw-etc".name ]; after = [ config.boot.initrd.systemd.services.initrd-find-etc.name ] ++ lib.optionals config.system.etc.overlay.mutable [ config.boot.initrd.systemd.services."rw-etc".name ]; unitConfig = { RequiresMountsFor = [ "/sysroot/nix/store" "/run/etc-metadata" ]; DefaultDependencies = false; }; } ]; services = lib.mkIf config.system.etc.overlay.mutable { services = lib.mkMerge [ (lib.mkIf config.system.etc.overlay.mutable { rw-etc = { requiredBy = [ "initrd-fs.target" ]; before = [ "initrd-fs.target" ]; unitConfig = { DefaultDependencies = false; RequiresMountsFor = "/sysroot"; Loading @@ -80,7 +112,42 @@ ''; }; }; }) { initrd-find-etc = { description = "Find the path to the etc metadata image and based dir"; requires = [ config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; after = [ config.boot.initrd.systemd.services.initrd-find-nixos-closure.name ]; before = [ "shutdown.target" ]; conflicts = [ "shutdown.target" ]; requiredBy = [ "initrd.target" ]; unitConfig = { DefaultDependencies = false; RequiresMountsFor = "/sysroot/nix/store"; }; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = /* bash */ '' set -uo pipefail closure="$(realpath /nixos-closure)" metadata_image="$(chroot /sysroot ${lib.getExe' pkgs.coreutils "realpath"} "$closure/etc-metadata-image")" ln -s "/sysroot$metadata_image" /etc-metadata-image basedir="$(chroot /sysroot ${lib.getExe' pkgs.coreutils "realpath"} "$closure/etc-basedir")" ln -s "/sysroot$basedir" /etc-basedir ''; }; } ]; }; }) Loading
nixos/tests/activation/etc-overlay-immutable.nix +14 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ boot.kernelPackages = pkgs.linuxPackages_latest; time.timeZone = "Utc"; # The standard resolvconf service tries to write to /etc and crashes, # which makes nixos-rebuild exit uncleanly when switching into the new generation services.resolved.enable = true; environment.etc = { "mountpoint/.keep".text = "keep"; "filemount".text = "keep"; Loading @@ -26,6 +30,13 @@ }; testScript = '' with subtest("/run/etc-metadata/ is mounted"): print(machine.succeed("mountpoint /run/etc-metadata")) with subtest("No temporary files leaked into stage 2"): machine.succeed("[ ! -e /etc-metadata-image ]") machine.succeed("[ ! -e /etc-basedir ]") with subtest("/etc is mounted as an overlay"): machine.succeed("findmnt --kernel --type overlay /etc") Loading @@ -50,6 +61,9 @@ with subtest("switching to the same generation"): machine.succeed("/run/current-system/bin/switch-to-configuration test") with subtest("the initrd didn't get rebuilt"): machine.succeed("test /run/current-system/initrd -ef /run/current-system/specialisation/new-generation/initrd") with subtest("switching to a new generation"): machine.fail("stat /etc/newgen") Loading
nixos/tests/activation/etc-overlay-mutable.nix +10 −0 Original line number Diff line number Diff line Loading @@ -18,12 +18,22 @@ }; testScript = '' with subtest("/run/etc-metadata/ is mounted"): print(machine.succeed("mountpoint /run/etc-metadata")) with subtest("No temporary files leaked into stage 2"): machine.succeed("[ ! -e /etc-metadata-image ]") machine.succeed("[ ! -e /etc-basedir ]") with subtest("/etc is mounted as an overlay"): machine.succeed("findmnt --kernel --type overlay /etc") with subtest("switching to the same generation"): machine.succeed("/run/current-system/bin/switch-to-configuration test") with subtest("the initrd didn't get rebuilt"): machine.succeed("test /run/current-system/initrd -ef /run/current-system/specialisation/new-generation/initrd") with subtest("switching to a new generation"): machine.fail("stat /etc/newgen") machine.succeed("echo -n 'mutable' > /etc/mutable") Loading