{ config, pkgs, ... }:
with pkgs.lib;
let
# Packages that provide fsck backends.
fsPackages = [ pkgs.e2fsprogs pkgs.reiserfsprogs ];
in
{
###### interface
options = {
fileSystems = mkOption {
example = [
{ mountPoint = "/";
device = "/dev/hda1";
}
{ mountPoint = "/data";
device = "/dev/hda2";
fsType = "ext3";
options = "data=journal";
}
{ mountPoint = "/bigdisk";
label = "bigdisk";
}
];
description = "
The file systems to be mounted. It must include an entry for
the root directory (mountPoint = \"/\"). Each
entry in the list is an attribute set with the following fields:
mountPoint, device,
fsType (a file system type recognised by
mount; defaults to
\"auto\"), and options
(the mount options passed to mount using the
flag; defaults to \"defaults\").
Instead of specifying device, you can also
specify a volume label (label) for file
systems that support it, such as ext2/ext3 (see mke2fs
-L).
autocreate forces mountPoint to be created with
mkdir -p .
";
type = types.nullOr (types.list types.optionSet);
options = {
mountPoint = mkOption {
example = "/mnt/usb";
type = types.uniq types.string;
description = "
Location of the mounted the file system.
";
};
device = mkOption {
default = null;
example = "/dev/sda";
type = types.uniq (types.nullOr types.string);
description = "
Location of the device.
";
};
label = mkOption {
default = null;
example = "root-partition";
type = types.uniq (types.nullOr types.string);
description = "
Label of the device (if any).
";
};
fsType = mkOption {
default = "auto";
example = "ext3";
type = types.uniq types.string;
description = "
Type of the file system.
";
};
options = mkOption {
default = "defaults,relatime";
example = "data=journal";
type = types.string;
merge = pkgs.lib.concatStringsSep ",";
description = "
Option used to mount the file system.
";
};
autocreate = mkOption {
default = false;
type = types.bool;
description = "
Automatically create the mount point defined in
.
";
};
};
};
system.sbin.mount = mkOption {
internal = true;
default = pkgs.utillinuxng;
description = "
Package containing mount and umount.
";
};
};
###### implementation
config = {
# Add the mount helpers to the system path so that `mount' can find them.
environment.systemPackages =
[ pkgs.ntfs3g pkgs.cifs_utils pkgs.nfsUtils pkgs.mountall ]
++ fsPackages;
environment.etc = singleton
{ source = pkgs.writeText "fstab"
''
# This is a generated file. Do not edit!
# Filesystems.
${flip concatMapStrings config.fileSystems (fs:
(if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}")
+ " " + fs.mountPoint
+ " " + fs.fsType
+ " " + fs.options
+ " 0"
+ " " + (if fs.fsType == "none" then "0" else if fs.mountPoint == "/" then "1" else "2")
+ "\n"
)}
# Swap devices.
${flip concatMapStrings config.swapDevices (sw:
"${sw.device} none swap\n"
)}
'';
target = "fstab";
};
jobs.mountall =
{ startOn = "started udev";
task = true;
script =
''
exec > /dev/console 2>&1
echo "mounting filesystems..."
export PATH=${config.system.sbin.mount}/bin:${makeSearchPath "sbin" ([pkgs.utillinux] ++ fsPackages)}:$PATH
${pkgs.mountall}/sbin/mountall
'';
};
# The `mount-failed' event is emitted synchronously, but we don't
# want `mountall' to wait for the emergency shell. So use this
# intermediate job to make the event asynchronous.
jobs.mountFailed =
{ name = "mount-failed";
task = true;
startOn = "mount-failed";
script =
''
[ -n "$MOUNTPOINT" ] || exit 0
start --no-wait emergency-shell \
DEVICE="$DEVICE" MOUNTPOINT="$MOUNTPOINT"
'';
};
jobs.emergencyShell =
{ name = "emergency-shell";
task = true;
extraConfig = "console owner";
script =
''
[ -n "$MOUNTPOINT" ] || exit 0
exec < /dev/console > /dev/console 2>&1
cat <>>[0m
The filesystem \`$DEVICE' could not be mounted on \`$MOUNTPOINT'.
Please do one of the following:
- Repair the filesystem (\`fsck $DEVICE') and exit the emergency
shell to resume booting.
- Ignore any failed filesystems and continue booting by running
\`initctl emit filesystem'.
- Remove the failed filesystem from the system configuration in
/etc/nixos/configuration.nix and run \`nixos-rebuild switch'.
EOF
${pkgs.shadow}/bin/login root || false
initctl start --no-wait mountall
'';
};
};
}