mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-06 17:13:24 -05:00
find-etc verified the init= was inside a NixOS toplevel and bailed otherwise, failing initrd-find-etc.service. The etc-overlay mounts require it, so for a non-NixOS init= (e.g. init=/bin/sh) the initrd dropped to emergency mode before initrd-init could switch-root into the target. Make find-etc skip silently for a non-NixOS init=, leaving the /etc-basedir and /etc-metadata-image symlinks uncreated, and gate the etc-metadata mount, the /sysroot/etc overlay and the rw-etc service on those symlinks with ConditionPathExists so they skip instead of fail. initrd-init then switch-roots into the non-NixOS init directly. The NixOS path is unchanged: the symlinks exist, so the conditions hold. Extend the systemd-initrd-non-nixos test with a second node enabling system.nixos-init.enable, so both the bash initrd-nixos-activation path and the nixos-init path are covered. Assisted-by: Claude:claude-opus-4-8
198 lines
7 KiB
Nix
198 lines
7 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
...
|
|
}:
|
|
|
|
{
|
|
|
|
imports = [ ./etc.nix ];
|
|
|
|
config = lib.mkMerge [
|
|
|
|
{
|
|
system.activationScripts.etc = lib.stringAfter [
|
|
"users"
|
|
"groups"
|
|
"specialfs"
|
|
] config.system.build.etcActivationCommands;
|
|
}
|
|
|
|
(lib.mkIf config.system.etc.overlay.enable {
|
|
|
|
assertions = [
|
|
{
|
|
assertion = config.boot.initrd.systemd.enable;
|
|
message = "`system.etc.overlay.enable` requires `boot.initrd.systemd.enable`";
|
|
}
|
|
{
|
|
assertion =
|
|
(!config.system.etc.overlay.mutable)
|
|
-> (config.systemd.sysusers.enable || config.services.userborn.enable);
|
|
message = "`!system.etc.overlay.mutable` requires `systemd.sysusers.enable` or `services.userborn.enable`";
|
|
}
|
|
{
|
|
assertion =
|
|
(config.system.switch.enable)
|
|
-> (lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.6");
|
|
message = "switchable systems with `system.etc.overlay.enable` require a newer kernel, at least version 6.6";
|
|
}
|
|
];
|
|
|
|
boot.initrd.availableKernelModules = [
|
|
"loop"
|
|
"erofs"
|
|
"overlay"
|
|
];
|
|
|
|
system.requiredKernelConfig = with config.lib.kernelConfig; [
|
|
(isEnabled "EROFS_FS")
|
|
];
|
|
|
|
boot.initrd.systemd = {
|
|
storePaths = lib.mkIf config.system.etc.overlay.mutable [
|
|
"${config.system.nixos-init.package}/bin/clear-etc-opaque"
|
|
];
|
|
mounts = [
|
|
{
|
|
where = "/run/nixos-etc-metadata";
|
|
what = "/etc-metadata-image";
|
|
type = "erofs";
|
|
options = "loop,ro,nodev,nosuid";
|
|
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"
|
|
];
|
|
# find-etc only creates this symlink for a NixOS init. For a
|
|
# non-NixOS init= (e.g. init=/bin/sh) it is absent, so skip the
|
|
# mount instead of failing the whole initrd.
|
|
ConditionPathExists = "/etc-metadata-image";
|
|
};
|
|
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";
|
|
what = "overlay";
|
|
type = "overlay";
|
|
options = lib.concatStringsSep "," (
|
|
[
|
|
"nodev"
|
|
"nosuid"
|
|
"relatime"
|
|
"redirect_dir=on"
|
|
"metacopy=on"
|
|
"lowerdir=/run/nixos-etc-metadata::/etc-basedir"
|
|
]
|
|
++ lib.optionals config.system.etc.overlay.mutable [
|
|
"rw"
|
|
"upperdir=/sysroot/.rw-etc/upper"
|
|
"workdir=/sysroot/.rw-etc/work"
|
|
]
|
|
++ lib.optionals (!config.system.etc.overlay.mutable) [
|
|
"ro"
|
|
]
|
|
);
|
|
requiredBy = [ "initrd-fs.target" ];
|
|
before = [ "initrd-fs.target" ];
|
|
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/nixos-etc-metadata"
|
|
];
|
|
DefaultDependencies = false;
|
|
# Skip for a non-NixOS init=, see the metadata mount above.
|
|
ConditionPathExists = "/etc-basedir";
|
|
};
|
|
}
|
|
];
|
|
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"
|
|
# Needed so we can clear stale opaque markers from the
|
|
# upperdir based on the contents of the new metadata layer
|
|
# before the overlay is mounted.
|
|
"/run/nixos-etc-metadata"
|
|
];
|
|
# Skip for a non-NixOS init=, see the metadata mount above.
|
|
ConditionPathExists = "/etc-metadata-image";
|
|
};
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
ExecStart = [
|
|
"/bin/mkdir -p -m 0755 /sysroot/.rw-etc/upper /sysroot/.rw-etc/work"
|
|
"${config.system.nixos-init.package}/bin/clear-etc-opaque /run/nixos-etc-metadata /sysroot/.rw-etc/upper"
|
|
];
|
|
};
|
|
};
|
|
})
|
|
{
|
|
initrd-find-etc = {
|
|
description = "Find the path to the etc metadata image and based dir";
|
|
before = [ "shutdown.target" ];
|
|
conflicts = [ "shutdown.target" ];
|
|
requiredBy = [ "initrd.target" ];
|
|
path = [ config.system.nixos-init.package ];
|
|
unitConfig = {
|
|
DefaultDependencies = false;
|
|
RequiresMountsFor = "/sysroot/nix/store";
|
|
};
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = "${config.system.nixos-init.package}/bin/find-etc";
|
|
};
|
|
};
|
|
}
|
|
];
|
|
};
|
|
|
|
})
|
|
|
|
(lib.mkIf (config.system.etc.overlay.enable && !config.system.etc.overlay.mutable) {
|
|
# Systemd requires /etc/machine-id exists or can be initialized on first
|
|
# boot. This file should not be part of an image or system config because
|
|
# it is unique to the machine, so it is initialized at first boot and
|
|
# persisted in the system state directory, /var/lib/nixos.
|
|
environment.etc."machine-id".source = lib.mkDefault "/var/lib/nixos/machine-id";
|
|
boot.initrd.systemd.tmpfiles.settings.machine-id."/sysroot/var/lib/nixos/machine-id".f =
|
|
lib.mkDefault
|
|
{
|
|
argument = "uninitialized";
|
|
};
|
|
})
|
|
|
|
];
|
|
}
|