From 6efcfe03ae4ef426b77a6827243433b5296613a4 Mon Sep 17 00:00:00 2001 From: Nikolay Amiantov Date: Sat, 27 Aug 2016 13:29:38 +0300 Subject: nixos filesystems: unify early filesystems handling A new internal config option `fileSystems..early` is added to indicate that the filesystem needs to be loaded very early (i.e. in initrd). They are transformed to a shell script in `system.build.earlyMountScript` with calls to an undefined `specialMount` function, which is expected to be caller-specific. This option is used by stage-1, stage-2 and activation script to set up and remount those filesystems. Options for them are updated according to systemd defaults. --- nixos/modules/security/hidepid.nix | 19 +--------- .../system/activation/activation-script.nix | 12 +++++-- nixos/modules/system/boot/stage-1-init.sh | 26 +++++++------- nixos/modules/system/boot/stage-1.nix | 4 ++- nixos/modules/system/boot/stage-2-init.sh | 29 ++++++--------- nixos/modules/system/boot/stage-2.nix | 3 +- nixos/modules/tasks/filesystems.nix | 41 +++++++++++++++++++--- 7 files changed, 75 insertions(+), 59 deletions(-) diff --git a/nixos/modules/security/hidepid.nix b/nixos/modules/security/hidepid.nix index 8271578c55d6..4917327d617c 100644 --- a/nixos/modules/security/hidepid.nix +++ b/nixos/modules/security/hidepid.nix @@ -20,23 +20,6 @@ with lib; 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"; - }; - }; + fileSystems."/proc".options = [ "hidepid=2" "gid=${toString config.ids.gids.proc}" ]; }; } diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix index 4489e34831da..1c587413121e 100644 --- a/nixos/modules/system/activation/activation-script.nix +++ b/nixos/modules/system/activation/activation-script.nix @@ -154,9 +154,15 @@ in 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 + 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} ''; }; diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 65d1dcb61681..abab5f20baac 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -59,22 +59,24 @@ echo echo "<<< NixOS Stage 1 >>>" echo - -# Mount special file systems. +# Make several required directories. mkdir -p /etc/udev touch /etc/fstab # to shut up mount -touch /etc/mtab # to shut up mke2fs +ln -s /proc/mounts /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 + +# 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 diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index a5c05f3dbbaf..513c121347b1 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -190,7 +190,9 @@ let inherit udevRules extraUtils modulesClosure; - inherit (config.boot) resumeDevice devSize runSize; + inherit (config.boot) resumeDevice; + + inherit (config.system.build) earlyMountScript; inherit (config.boot.initrd) checkJournalingFS preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules; diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index c5a14f0766d5..7de85209a159 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -37,12 +37,16 @@ fi # 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 + 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 @@ -87,11 +91,6 @@ done # 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 @@ -112,14 +111,6 @@ rm -f /etc/{group,passwd,shadow}.lock 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). if ! mountpoint -q /run/keys; then diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix index b67f42a017e6..7e4ec2a4a670 100644 --- a/nixos/modules/system/boot/stage-2.nix +++ b/nixos/modules/system/boot/stage-2.nix @@ -20,10 +20,9 @@ let 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; + inherit (config.system.build) earlyMountScript; path = [ pkgs.coreutils pkgs.utillinux diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index f146448200f9..d69284a75323 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -18,6 +18,8 @@ let prioOption = prio: optionalString (prio != null) " pri=${toString prio}"; + specialFSTypes = [ "proc" "sysfs" "tmpfs" "devtmpfs" "devpts" ]; + fileSystemOpts = { name, config, ... }: { options = { @@ -97,11 +99,22 @@ let 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 (config.fsType == "tmpfs") (mkDefault config.fsType); + 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 @@ -110,6 +123,13 @@ let }; + # 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 { @@ -131,8 +151,7 @@ in "/bigdisk".label = "bigdisk"; } ''; - type = types.loaOf types.optionSet; - options = [ fileSystemOpts ]; + type = types.loaOf (types.submodule fileSystemOpts); description = '' The file systems to be mounted. It must include an entry for the root directory (mountPoint = "/"). Each @@ -177,10 +196,14 @@ in { 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; @@ -211,7 +234,7 @@ in + " " + (if skipCheck fs then "0" else if fs.mountPoint == "/" then "1" else "2") + "\n" - ) fileSystems} + ) (filter (fs: !fs.early) fileSystems)} # Swap devices. ${flip concatMapStrings config.swapDevices (sw: @@ -258,6 +281,16 @@ in 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}" ]; }; + }; + }; } -- cgit 1.4.1