Merge pull request #17822 from abbradar/systemd-mounts

nixos filesystems: unify special filesystems handling

Changed files
+75 -59
nixos
+1 -18
nixos/modules/security/hidepid.nix
···
config = mkIf config.security.hideProcessInformation {
users.groups.proc.gid = config.ids.gids.proc;
-
systemd.services.hidepid = {
-
wantedBy = [ "local-fs.target" ];
-
after = [ "systemd-remount-fs.service" ];
-
before = [ "local-fs-pre.target" "local-fs.target" "shutdown.target" ];
-
wants = [ "local-fs-pre.target" ];
-
-
serviceConfig = {
-
Type = "oneshot";
-
RemainAfterExit = true;
-
ExecStart = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=2,gid=${toString config.ids.gids.proc} /proc'';
-
ExecStop = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=0,gid=0 /proc'';
-
};
-
-
unitConfig = {
-
DefaultDependencies = false;
-
Conflicts = "shutdown.target";
-
};
-
};
};
}
···
config = mkIf config.security.hideProcessInformation {
users.groups.proc.gid = config.ids.gids.proc;
+
fileSystems."/proc".options = [ "hidepid=2" "gid=${toString config.ids.gids.proc}" ];
};
}
+9 -3
nixos/modules/system/activation/activation-script.nix
···
system.activationScripts.tmpfs =
''
-
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
-
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
-
${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
'';
};
···
system.activationScripts.tmpfs =
''
+
specialMount() {
+
local device="$1"
+
local mountPoint="$2"
+
local options="$3"
+
local fsType="$4"
+
+
${pkgs.utillinux}/bin/mount -t "$fsType" -o "remount,$options" "$device" "$mountPoint"
+
}
+
source ${config.system.build.earlyMountScript}
'';
};
+14 -12
nixos/modules/system/boot/stage-1-init.sh
···
echo "<<< NixOS Stage 1 >>>"
echo
-
-
# Mount special file systems.
mkdir -p /etc/udev
touch /etc/fstab # to shut up mount
-
touch /etc/mtab # to shut up mke2fs
touch /etc/udev/hwdb.bin # to shut up udev
touch /etc/initrd-release
-
mkdir -p /proc
-
mount -t proc proc /proc
-
mkdir -p /sys
-
mount -t sysfs sysfs /sys
-
mount -t devtmpfs -o "size=@devSize@" devtmpfs /dev
-
mkdir -p /run
-
mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
-
mkdir /dev/pts
-
mount -t devpts devpts /dev/pts
# Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
mkdir -p /tmp
···
echo "<<< NixOS Stage 1 >>>"
echo
+
# Make several required directories.
mkdir -p /etc/udev
touch /etc/fstab # to shut up mount
+
ln -s /proc/mounts /etc/mtab # to shut up mke2fs
touch /etc/udev/hwdb.bin # to shut up udev
touch /etc/initrd-release
+
+
# Mount special file systems.
+
specialMount() {
+
local device="$1"
+
local mountPoint="$2"
+
local options="$3"
+
local fsType="$4"
+
+
mkdir -m 0755 -p "$mountPoint"
+
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
+
}
+
source @earlyMountScript@
# Log the script output to /dev/kmsg or /run/log/stage-1-init.log.
mkdir -p /tmp
+3 -1
nixos/modules/system/boot/stage-1.nix
···
inherit udevRules extraUtils modulesClosure;
-
inherit (config.boot) resumeDevice devSize runSize;
inherit (config.boot.initrd) checkJournalingFS
preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules;
···
inherit udevRules extraUtils modulesClosure;
+
inherit (config.boot) resumeDevice;
+
+
inherit (config.system.build) earlyMountScript;
inherit (config.boot.initrd) checkJournalingFS
preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules;
+10 -19
nixos/modules/system/boot/stage-2-init.sh
···
# Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
# stage 1, we need to do that here.
if [ ! -e /proc/1 ]; then
-
mkdir -m 0755 -p /proc
-
mount -n -t proc proc /proc
-
mkdir -m 0755 -p /dev
-
mount -t devtmpfs devtmpfs /dev
-
mkdir -m 0755 -p /sys
-
mount -t sysfs sysfs /sys
fi
···
# More special file systems, initialise required directories.
-
if ! mountpoint -q /dev/shm; then
-
mkdir -m 0755 /dev/shm
-
mount -t tmpfs -o "rw,nosuid,nodev,size=@devShmSize@" tmpfs /dev/shm
-
fi
-
mkdir -m 0755 -p /dev/pts
[ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
mkdir -m 01777 -p /tmp
mkdir -m 0755 -p /var /var/log /var/lib /var/db
···
# Also get rid of temporary GC roots.
rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
-
-
# Create a tmpfs on /run to hold runtime state for programs such as
-
# udev (if stage 1 hasn't already done so).
-
if ! mountpoint -q /run; then
-
rm -rf /run
-
mkdir -m 0755 -p /run
-
mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run
-
fi
# Create a ramfs on /run/keys to hold secrets that shouldn't be
# written to disk (generally used for NixOps, harmless elsewhere).
···
# Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
# stage 1, we need to do that here.
if [ ! -e /proc/1 ]; then
+
specialMount() {
+
local device="$1"
+
local mountPoint="$2"
+
local options="$3"
+
local fsType="$4"
+
+
mkdir -m 0755 -p "$mountPoint"
+
mount -n -t "$fsType" -o "$options" "$device" "$mountPoint"
+
}
+
source @earlyMountScript@
fi
···
# More special file systems, initialise required directories.
[ -e /proc/bus/usb ] && mount -t usbfs usbfs /proc/bus/usb # UML doesn't have USB by default
mkdir -m 01777 -p /tmp
mkdir -m 0755 -p /var /var/log /var/lib /var/db
···
# Also get rid of temporary GC roots.
rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
# Create a ramfs on /run/keys to hold secrets that shouldn't be
# written to disk (generally used for NixOps, harmless elsewhere).
+1 -2
nixos/modules/system/boot/stage-2.nix
···
src = ./stage-2-init.sh;
shellDebug = "${pkgs.bashInteractive}/bin/bash";
isExecutable = true;
-
inherit (config.boot) devShmSize runSize;
inherit (config.nix) readOnlyStore;
inherit (config.networking) useHostResolvConf;
-
ttyGid = config.ids.gids.tty;
path =
[ pkgs.coreutils
pkgs.utillinux
···
src = ./stage-2-init.sh;
shellDebug = "${pkgs.bashInteractive}/bin/bash";
isExecutable = true;
inherit (config.nix) readOnlyStore;
inherit (config.networking) useHostResolvConf;
+
inherit (config.system.build) earlyMountScript;
path =
[ pkgs.coreutils
pkgs.utillinux
+37 -4
nixos/modules/tasks/filesystems.nix
···
prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
fileSystemOpts = { name, config, ... }: {
options = {
···
description = "Disable running fsck on this filesystem.";
};
};
config = {
mountPoint = mkDefault name;
-
device = mkIf (config.fsType == "tmpfs") (mkDefault config.fsType);
options = mkIf config.autoResize [ "x-nixos.autoresize" ];
# -F needed to allow bare block device without partitions
···
};
in
{
···
"/bigdisk".label = "bigdisk";
}
'';
-
type = types.loaOf types.optionSet;
-
options = [ fileSystemOpts ];
description = ''
The file systems to be mounted. It must include an entry for
the root directory (<literal>mountPoint = "/"</literal>). Each
···
{ assertion = ! (fileSystems' ? "cycle");
message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
}
];
# Export for use in other modules
system.build.fileSystems = fileSystems;
boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
···
+ " " + (if skipCheck fs then "0" else
if fs.mountPoint == "/" then "1" else "2")
+ "\n"
-
) fileSystems}
# Swap devices.
${flip concatMapStrings config.swapDevices (sw:
···
};
in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
};
···
prioOption = prio: optionalString (prio != null) " pri=${toString prio}";
+
specialFSTypes = [ "proc" "sysfs" "tmpfs" "devtmpfs" "devpts" ];
+
fileSystemOpts = { name, config, ... }: {
options = {
···
description = "Disable running fsck on this filesystem.";
};
+
early = mkOption {
+
default = false;
+
type = types.bool;
+
internal = true;
+
description = ''
+
Mount this filesystem very early during boot. At the moment of
+
mounting no disks are exposed, so this option is primarily for
+
special file systems.
+
'';
+
};
+
};
config = {
mountPoint = mkDefault name;
+
device = mkIf (elem config.fsType specialFSTypes) (mkDefault config.fsType);
options = mkIf config.autoResize [ "x-nixos.autoresize" ];
# -F needed to allow bare block device without partitions
···
};
+
# Makes sequence of `specialMount device mountPoint options fsType` commands.
+
# `systemMount` should be defined in the sourcing script.
+
makeSpecialMounts = mounts:
+
pkgs.writeText "mounts.sh" (concatMapStringsSep "\n" (mount: ''
+
specialMount "${mount.device}" "${mount.mountPoint}" "${concatStringsSep "," mount.options}" "${mount.fsType}"
+
'') mounts);
+
in
{
···
"/bigdisk".label = "bigdisk";
}
'';
+
type = types.loaOf (types.submodule fileSystemOpts);
description = ''
The file systems to be mounted. It must include an entry for
the root directory (<literal>mountPoint = "/"</literal>). Each
···
{ assertion = ! (fileSystems' ? "cycle");
message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";
}
+
{ assertion = all (x: !x.early || (x.label == null && !x.autoFormat && !x.autoResize)) fileSystems;
+
message = "Early filesystems don't support mounting by label, auto formatting and resizing";
+
}
];
# Export for use in other modules
system.build.fileSystems = fileSystems;
+
system.build.earlyMountScript = makeSpecialMounts (filter (fs: fs.early) fileSystems);
boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
···
+ " " + (if skipCheck fs then "0" else
if fs.mountPoint == "/" then "1" else "2")
+ "\n"
+
) (filter (fs: !fs.early) fileSystems)}
# Swap devices.
${flip concatMapStrings config.swapDevices (sw:
···
};
in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
+
+
# Sync mount options with systemd's src/core/mount-setup.c: mount_table.
+
fileSystems = mapAttrs (n: fs: fs // { early = true; }) {
+
"/proc" = { fsType = "proc"; options = [ "nosuid" "noexec" "nodev" ]; };
+
"/sys" = { fsType = "sysfs"; options = [ "nosuid" "noexec" "nodev" ]; };
+
"/run" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=755" "size=${config.boot.runSize}" ]; };
+
"/dev" = { fsType = "devtmpfs"; options = [ "nosuid" "strictatime" "mode=755" "size=${config.boot.devSize}" ]; };
+
"/dev/shm" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=1777" "size=${config.boot.devShmSize}" ]; };
+
"/dev/pts" = { fsType = "devpts"; options = [ "nosuid" "noexec" "mode=620" "gid=${toString config.ids.gids.tty}" ]; };
+
};
};