From 3a6f7a60acf49f727e647f56dbf3342b805230fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Sat, 7 Mar 2026 18:26:04 +0300 Subject: [PATCH] nixos/envfs: fix compatibility with systemd in initrd This module disables the activation scripts that would normally create `/usr/bin/env` and `/bin/sh` (and their parent directories). When systemd is used in the initrd, the absence of these directories causes 2 problems: - During switch-root, base_filesystem_create_fd() creates an empty /usr directory. Later at stage2, systemd's initialize_runtime() aborts booting with "Refusing to run in unsupported environment where /usr/ is not populated." - Once /usr/bin is restored (by the fix above), base_filesystem_create_fd() creates a symlink /bin -> /usr/bin. systemd-fstab-generator then canonicalizes the /bin fstab entry through this symlink, producing a duplicate usr-bin.mount. We create both /sysroot/usr/bin and /sysroot/bin via initrd tmpfiles to prevent both issues. Resolves NixOS#462556 Co-authored-by: Lin Yinfeng --- nixos/modules/tasks/filesystems/envfs.nix | 34 +++++++++++++++++++++++ nixos/tests/all-tests.nix | 9 +++++- nixos/tests/envfs.nix | 13 +++++++-- pkgs/by-name/en/envfs/package.nix | 2 +- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/nixos/modules/tasks/filesystems/envfs.nix b/nixos/modules/tasks/filesystems/envfs.nix index 1e821277b614..4b1846f5c1a8 100644 --- a/nixos/modules/tasks/filesystems/envfs.nix +++ b/nixos/modules/tasks/filesystems/envfs.nix @@ -74,5 +74,39 @@ in # We no longer need those when using envfs system.activationScripts.usrbinenv = lib.mkForce ""; system.activationScripts.binsh = lib.mkForce ""; + + # Disabling the activation scripts above prevents the creation of 2 + # directories, which would normally be created just before switch-root at + # stage1. This causes problems when systemd is used in the initrd. + # + # This only affects fresh installations or systems using impermanence/tmpfs + # root, where these directories don't persist from a previous activation. + boot.initrd.systemd.tmpfiles.settings = lib.mkIf config.boot.initrd.systemd.enable { + "50-envfs" = { + # During switch-root, systemd's base_filesystem_create_fd() creates an + # empty /usr. Later at stage2, systemd initialize_runtime() checks + # dir_is_empty("/usr/"), which returns 1 for an empty but existing + # directory causing a fatal boot failure: "Refusing to run in + # unsupported environment where /usr/ is not populated." + "/sysroot/usr/bin" = { + d = { + group = "root"; + mode = "0755"; + user = "root"; + }; + }; + # During switch-root, base_filesystem_create_fd() creates a symlink + # /bin -> /usr/bin if /bin does not exist. systemd-fstab-generator then + # canonicalizes the /bin fstab entry through this symlink, producing a + # duplicate usr-bin.mount. Create /bin to avoid this behaviour. + "/sysroot/bin" = { + d = { + group = "root"; + mode = "0755"; + user = "root"; + }; + }; + }; + }; }; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 7892274095aa..99c1d26f6f34 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -518,7 +518,14 @@ in enlightenment = runTest ./enlightenment.nix; ente = runTest ./ente; env = runTest ./env.nix; - envfs = runTest ./envfs.nix; + envfs = runTest { + imports = [ ./envfs.nix ]; + _module.args.systemdStage1 = false; + }; + envfs-systemd-stage-1 = runTest { + imports = [ ./envfs.nix ]; + _module.args.systemdStage1 = true; + }; envoy = runTest { imports = [ ./envoy.nix ]; _module.args.envoyPackage = pkgs.envoy; diff --git a/nixos/tests/envfs.nix b/nixos/tests/envfs.nix index 6e8ee7e55aea..78946285ed68 100644 --- a/nixos/tests/envfs.nix +++ b/nixos/tests/envfs.nix @@ -1,4 +1,9 @@ -{ lib, pkgs, ... }: +{ + pkgs, + systemdStage1 ? false, + ... +}: + let pythonShebang = pkgs.writeScript "python-shebang" '' #!/usr/bin/python @@ -12,7 +17,11 @@ let in { name = "envfs"; - nodes.machine.services.envfs.enable = true; + + nodes.machine = { + services.envfs.enable = true; + boot.initrd.systemd.enable = systemdStage1; + }; testScript = '' start_all() diff --git a/pkgs/by-name/en/envfs/package.nix b/pkgs/by-name/en/envfs/package.nix index 7e2fbd3127d3..f1601aa562bc 100644 --- a/pkgs/by-name/en/envfs/package.nix +++ b/pkgs/by-name/en/envfs/package.nix @@ -25,7 +25,7 @@ rustPlatform.buildRustPackage (finalAttrs: { passthru = { tests = { - envfs = nixosTests.envfs; + inherit (nixosTests) envfs envfs-systemd-stage-1; }; updateScript = nix-update-script { };