diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index fbb32901f64..65d1dcb6168 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -312,8 +312,50 @@ mountFS() { echo "retrying..." n=$((n + 1)) done + + [ "$mountPoint" == "/" ] && + [ -f "/mnt-root/etc/NIXOS_LUSTRATE" ] && + lustrateRoot "/mnt-root" } +lustrateRoot () { + local root="$1" + + echo + echo -e "\e[1;33m<<< NixOS is now lustrating the root filesystem (cruft goes to /old-root) >>>\e[0m" + echo + + mkdir -m 0755 -p "$root/old-root.tmp" + + echo + echo "Moving impurities out of the way:" + for d in "$root"/* + do + [ "$d" == "$root/nix" ] && continue + [ "$d" == "$root/boot" ] && continue # Don't render the system unbootable + [ "$d" == "$root/old-root.tmp" ] && continue + + mv -v "$d" "$root/old-root.tmp" + done + + # Use .tmp to make sure subsequent invokations don't clash + mv -v "$root/old-root.tmp" "$root/old-root" + + mkdir -m 0755 -p "$root/etc" + touch "$root/etc/NIXOS" + + exec 4< "$root/old-root/etc/NIXOS_LUSTRATE" + + echo + echo "Restoring selected impurities:" + while read -u 4 keeper; do + dirname="$(dirname "$keeper")" + mkdir -m 0755 -p "$root/$dirname" + cp -av "$root/old-root/$keeper" "$root/$keeper" + done + + exec 4>&- +} # Function for waiting a device to appear. waitDevice() { diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index baeba1d6b31..9be7ad4ae07 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -131,9 +131,16 @@ let # The initrd only has to mount / or any FS marked as necessary for # booting (such as the FS containing /nix/store, or an FS needed for # mounting /, like / on a loopback). - fileSystems = filter - (fs: fs.neededForBoot || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ]) - (attrValues config.fileSystems); + # + # We need to guarantee that / is the first filesystem in the list so + # that if and when lustrateRoot is invoked, nothing else is mounted + fileSystems = let + filterNeeded = filter + (fs: fs.mountPoint != "/" && (fs.neededForBoot || elem fs.mountPoint [ "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ])); + filterRoot = filter + (fs: fs.mountPoint == "/"); + allFileSystems = attrValues config.fileSystems; + in (filterRoot allFileSystems) ++ (filterNeeded allFileSystems); udevRules = pkgs.stdenv.mkDerivation {