push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.apfs or false;
in
{
config = mkIf (config.boot.supportedFilesystems.apfs or false) {
system.fsPackages = [ pkgs.apfsprogs ];
boot.extraModulePackages = [ config.boot.kernelPackages.apfs ];
boot.initrd.kernelModules = mkIf inInitrd [ "apfs" ];
# Don't copy apfsck into the initramfs since it does not support repairing the filesystem
};
}

View File

@@ -0,0 +1,398 @@
{
config,
lib,
pkgs,
utils,
...
}:
let
cfg = config.boot.bcachefs;
cfgScrub = config.services.bcachefs.autoScrub;
bootFs = lib.filterAttrs (
n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)
) config.fileSystems;
commonFunctions = ''
prompt() {
local name="$1"
printf "enter passphrase for $name: "
}
tryUnlock() {
local name="$1"
local path="$2"
local success=false
local target
local uuid=$(echo -n $path | sed -e 's,UUID=\(.*\),\1,g')
printf "waiting for device to appear $path"
for try in $(seq 10); do
if [ -e $path ]; then
target=$(readlink -f $path)
success=true
break
else
target=$(blkid --uuid $uuid)
if [ $? == 0 ]; then
success=true
break
fi
fi
echo -n "."
sleep 1
done
printf "\n"
if [ $success == true ]; then
path=$target
fi
if bcachefs unlock -c $path > /dev/null 2> /dev/null; then # test for encryption
prompt $name
until bcachefs unlock $path 2> /dev/null; do # repeat until successfully unlocked
printf "unlocking failed!\n"
prompt $name
done
printf "unlocking successful.\n"
else
echo "Cannot unlock device $uuid with path $path" >&2
fi
}
'';
# we need only unlock one device manually, and cannot pass multiple at once
# remove this adaptation when bcachefs implements mounting by filesystem uuid
# also, implement automatic waiting for the constituent devices when that happens
# bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671)
firstDevice = fs: lib.head (lib.splitString ":" fs.device);
useClevis =
fs:
config.boot.initrd.clevis.enable
&& (lib.hasAttr (firstDevice fs) config.boot.initrd.clevis.devices);
openCommand =
name: fs:
if useClevis fs then
''
if clevis decrypt < /etc/clevis/${firstDevice fs}.jwe | bcachefs unlock ${firstDevice fs}
then
printf "unlocked ${name} using clevis\n"
else
printf "falling back to interactive unlocking...\n"
tryUnlock ${name} ${firstDevice fs}
fi
''
else
''
tryUnlock ${name} ${firstDevice fs}
'';
mkUnits =
prefix: name: fs:
let
parseTags =
device:
if lib.hasPrefix "LABEL=" device then
"/dev/disk/by-label/" + lib.removePrefix "LABEL=" device
else if lib.hasPrefix "UUID=" device then
"/dev/disk/by-uuid/" + lib.removePrefix "UUID=" device
else if lib.hasPrefix "PARTLABEL=" device then
"/dev/disk/by-partlabel/" + lib.removePrefix "PARTLABEL=" device
else if lib.hasPrefix "PARTUUID=" device then
"/dev/disk/by-partuuid/" + lib.removePrefix "PARTUUID=" device
else if lib.hasPrefix "ID=" device then
"/dev/disk/by-id/" + lib.removePrefix "ID=" device
else
device;
device = parseTags (firstDevice fs);
mkDeviceUnit = device: "${utils.escapeSystemdPath device}.device";
mkMountUnit = path: "${utils.escapeSystemdPath (lib.removeSuffix "/" path)}.mount";
deviceUnit = mkDeviceUnit device;
mountUnit = mkMountUnit (prefix + fs.mountPoint);
extractProperty =
prop: options: (map (lib.removePrefix prop) (builtins.filter (lib.hasPrefix prop) options));
normalizeUnits =
unit:
if lib.hasPrefix "/dev/" unit then
mkDeviceUnit unit
else if lib.hasPrefix "/" unit then
mkMountUnit unit
else
unit;
requiredUnits = map normalizeUnits (extractProperty "x-systemd.requires=" fs.options);
wantedUnits = map normalizeUnits (extractProperty "x-systemd.wants=" fs.options);
requiredMounts = extractProperty "x-systemd.requires-mounts-for=" fs.options;
wantedMounts = extractProperty "x-systemd.wants-mounts-for=" fs.options;
in
{
name = "unlock-bcachefs-${utils.escapeSystemdPath fs.mountPoint}";
value = {
description = "Unlock bcachefs for ${fs.mountPoint}";
requiredBy = [ mountUnit ];
after = [ deviceUnit ] ++ requiredUnits ++ wantedUnits;
before = [
mountUnit
"shutdown.target"
];
bindsTo = [ deviceUnit ];
requires = requiredUnits;
wants = wantedUnits;
unitConfig = {
RequiresMountsFor = requiredMounts;
WantsMountsFor = wantedMounts;
};
conflicts = [ "shutdown.target" ];
unitConfig.DefaultDependencies = false;
serviceConfig = {
Type = "oneshot";
ExecCondition = "${cfg.package}/bin/bcachefs unlock -c \"${device}\"";
Restart = "on-failure";
RestartMode = "direct";
# Ideally, this service would lock the key on stop.
# As is, RemainAfterExit doesn't accomplish anything.
RemainAfterExit = true;
};
script =
let
unlock = ''${cfg.package}/bin/bcachefs unlock "${device}"'';
unlockInteractively = ''${config.boot.initrd.systemd.package}/bin/systemd-ask-password --timeout=0 "enter passphrase for ${name}" | exec ${unlock}'';
in
if useClevis fs then
''
if ${config.boot.initrd.clevis.package}/bin/clevis decrypt < "/etc/clevis/${device}.jwe" | ${unlock}
then
printf "unlocked ${name} using clevis\n"
else
printf "falling back to interactive unlocking...\n"
${unlockInteractively}
fi
''
else
''
${unlockInteractively}
'';
};
};
in
{
options.boot.bcachefs = {
package = lib.mkPackageOption pkgs "bcachefs-tools" {
extraDescription = ''
This package should also provide a passthru 'kernelModule'
attribute to build the out-of-tree kernel module.
'';
};
modulePackage = lib.mkOption {
type = lib.types.package;
# See NOTE in linux-kernels.nix
default = config.boot.kernelPackages.callPackage cfg.package.kernelModule { };
internal = true;
};
};
options.services.bcachefs.autoScrub = {
enable = lib.mkEnableOption "regular bcachefs scrub";
fileSystems = lib.mkOption {
type = lib.types.listOf lib.types.path;
example = [ "/" ];
description = ''
List of paths to bcachefs filesystems to regularly call {command}`bcachefs scrub` on.
Defaults to all mount points with bcachefs filesystems.
'';
};
interval = lib.mkOption {
default = "monthly";
type = lib.types.str;
example = "weekly";
description = ''
Systemd calendar expression for when to scrub bcachefs filesystems.
The recommended period is a month but could be less.
See
{manpage}`systemd.time(7)`
for more information on the syntax.
'';
};
};
config = lib.mkIf (config.boot.supportedFilesystems.bcachefs or false) (
lib.mkMerge [
{
assertions = [
{
assertion =
let
kernel = config.boot.kernelPackages.kernel;
in
(
kernel.kernelAtLeast "6.7"
|| (lib.elem (kernel.structuredExtraConfig.BCACHEFS_FS or null) [
lib.kernel.module
lib.kernel.yes
(lib.kernel.option lib.kernel.yes)
])
);
message = "Linux 6.7-rc1 at minimum or a custom linux kernel with bcachefs support is required";
}
];
warnings = lib.mkIf cfg.modulePackage.meta.broken [
''
Using unmaintained in-tree bcachefs kernel module. This
will be removed in 26.05. Please use a kernel supported
by the out-of-tree module package.
''
];
# Bcachefs upstream recommends using the latest kernel
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
# needed for systemd-remount-fs
system.fsPackages = [ cfg.package ];
services.udev.packages = [ cfg.package ];
boot.extraModulePackages = lib.optionals (!cfg.modulePackage.meta.broken) [
cfg.modulePackage
];
systemd = {
packages = [ cfg.package ];
services = lib.mapAttrs' (mkUnits "") (
lib.filterAttrs (n: fs: (fs.fsType == "bcachefs") && (!utils.fsNeededForBoot fs)) config.fileSystems
);
};
}
(lib.mkIf ((config.boot.initrd.supportedFilesystems.bcachefs or false) || (bootFs != { })) {
boot.initrd.availableKernelModules = [
"bcachefs"
"sha256"
]
++ lib.optionals (config.boot.kernelPackages.kernel.kernelOlder "6.15") [
# chacha20 and poly1305 are required only for decryption attempts
# kernel 6.15 uses kernel api libraries for poly1305/chacha20: 4bf4b5046de0ef7f9dc50f3a9ef8a6dcda178a6d
# kernel 6.16 removes poly1305: ceef731b0e22df80a13d67773ae9afd55a971f9e
"poly1305"
"chacha20"
];
boot.initrd.systemd.extraBin = {
# do we need this? boot/systemd.nix:566 & boot/systemd/initrd.nix:357
"bcachefs" = "${cfg.package}/bin/bcachefs";
"mount.bcachefs" = "${cfg.package}/bin/mount.bcachefs";
};
boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${cfg.package}/bin/bcachefs
copy_bin_and_libs ${cfg.package}/bin/mount.bcachefs
'';
boot.initrd.extraUtilsCommandsTest = lib.mkIf (!config.boot.initrd.systemd.enable) ''
$out/bin/bcachefs version
'';
boot.initrd.postDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) (
commonFunctions + lib.concatStrings (lib.mapAttrsToList openCommand bootFs)
);
boot.initrd.systemd.services = lib.mapAttrs' (mkUnits "/sysroot") bootFs;
})
(lib.mkIf (cfgScrub.enable) {
assertions = [
{
assertion = lib.versionAtLeast config.boot.kernelPackages.kernel.version "6.14";
message = "Bcachefs scrubbing is supported from kernel version 6.14 or later.";
}
{
assertion = cfgScrub.enable -> (cfgScrub.fileSystems != [ ]);
message = ''
If 'services.bcachefs.autoScrub' is enabled, you need to have at least one
bcachefs file system mounted via 'fileSystems' or specify a list manually
in 'services.bcachefs.autoScrub.fileSystems'.
'';
}
];
# This will remove duplicated units from either having a filesystem mounted multiple
# time, or additionally mounted subvolumes, as well as having a filesystem span
# multiple devices (provided the same device is used to mount said filesystem).
services.bcachefs.autoScrub.fileSystems =
let
isDeviceInList = list: device: builtins.filter (e: e.device == device) list != [ ];
uniqueDeviceList = lib.foldl' (
acc: e: if isDeviceInList acc e.device then acc else acc ++ [ e ]
) [ ];
in
lib.mkDefault (
map (e: e.mountPoint) (
uniqueDeviceList (
lib.mapAttrsToList (name: fs: {
mountPoint = fs.mountPoint;
device = fs.device;
}) (lib.filterAttrs (name: fs: fs.fsType == "bcachefs") config.fileSystems)
)
)
);
systemd.timers =
let
scrubTimer =
fs:
let
fs' = if fs == "/" then "root" else utils.escapeSystemdPath fs;
in
lib.nameValuePair "bcachefs-scrub-${fs'}" {
description = "regular bcachefs scrub timer on ${fs}";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfgScrub.interval;
AccuracySec = "1d";
Persistent = true;
};
};
in
lib.listToAttrs (map scrubTimer cfgScrub.fileSystems);
systemd.services =
let
scrubService =
fs:
let
fs' = if fs == "/" then "root" else utils.escapeSystemdPath fs;
in
lib.nameValuePair "bcachefs-scrub-${fs'}" {
description = "bcachefs scrub on ${fs}";
# scrub prevents suspend2ram or proper shutdown
conflicts = [
"shutdown.target"
"sleep.target"
];
before = [
"shutdown.target"
"sleep.target"
];
script = "${lib.getExe cfg.package} data scrub ${fs}";
serviceConfig = {
Type = "oneshot";
Nice = 19;
IOSchedulingClass = "idle";
};
};
in
lib.listToAttrs (map scrubService cfgScrub.fileSystems);
})
]
);
meta = {
inherit (pkgs.bcachefs-tools.meta) maintainers;
};
}

View File

@@ -0,0 +1,15 @@
{
config,
lib,
pkgs,
...
}:
{
config = lib.mkIf (config.boot.supportedFilesystems."fuse.bindfs" or false) {
system.fsPackages = [ pkgs.bindfs ];
};
meta = {
maintainers = with lib.maintainers; [ Luflosi ];
};
}

View File

@@ -0,0 +1,199 @@
{
config,
lib,
pkgs,
utils,
...
}:
let
inherit (lib)
mkEnableOption
mkOption
types
mkMerge
mkIf
optionals
mkDefault
nameValuePair
listToAttrs
filterAttrs
mapAttrsToList
foldl'
;
inInitrd = config.boot.initrd.supportedFilesystems.btrfs or false;
inSystem = config.boot.supportedFilesystems.btrfs or false;
cfgScrub = config.services.btrfs.autoScrub;
enableAutoScrub = cfgScrub.enable;
enableBtrfs = inInitrd || inSystem || enableAutoScrub;
in
{
options = {
# One could also do regular btrfs balances, but that shouldn't be necessary
# during normal usage and as long as the filesystems aren't filled near capacity
services.btrfs.autoScrub = {
enable = mkEnableOption "regular btrfs scrub";
fileSystems = mkOption {
type = types.listOf types.path;
example = [ "/" ];
description = ''
List of paths to btrfs filesystems to regularly call {command}`btrfs scrub` on.
Defaults to all mount points with btrfs filesystems.
Note that if you have filesystems that span multiple devices (e.g. RAID), you should
take care to use the same device for any given mount point and let btrfs take care
of automatically mounting the rest, in order to avoid scrubbing the same data multiple times.
'';
};
interval = mkOption {
default = "monthly";
type = types.str;
example = "weekly";
description = ''
Systemd calendar expression for when to scrub btrfs filesystems.
The recommended period is a month but could be less
({manpage}`btrfs-scrub(8)`).
See
{manpage}`systemd.time(7)`
for more information on the syntax.
'';
};
};
};
config = mkMerge [
(mkIf enableBtrfs {
system.fsPackages = [ pkgs.btrfs-progs ];
})
(mkIf inInitrd {
boot.initrd.kernelModules = [ "btrfs" ];
boot.initrd.availableKernelModules = [
"crc32c"
]
++ optionals (config.boot.kernelPackages.kernel.kernelAtLeast "5.5") [
# Needed for mounting filesystems with new checksums
"xxhash_generic"
"blake2b_generic"
# `sha256` is always available, whereas `sha256_generic` is not available from 6.17 onwards
"sha256" # Should be baked into our kernel, just to be sure
];
boot.initrd.extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.btrfs-progs}/bin/btrfs
ln -sv btrfs $out/bin/btrfsck
ln -sv btrfsck $out/bin/fsck.btrfs
'';
boot.initrd.extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable) ''
$out/bin/btrfs --version
'';
boot.initrd.postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) ''
btrfs device scan
'';
boot.initrd.systemd.initrdBin = [ pkgs.btrfs-progs ];
})
(mkIf enableAutoScrub {
assertions = [
{
assertion = cfgScrub.enable -> (cfgScrub.fileSystems != [ ]);
message = ''
If 'services.btrfs.autoScrub' is enabled, you need to have at least one
btrfs file system mounted via 'fileSystems' or specify a list manually
in 'services.btrfs.autoScrub.fileSystems'.
'';
}
];
# This will remove duplicated units from either having a filesystem mounted multiple
# time, or additionally mounted subvolumes, as well as having a filesystem span
# multiple devices (provided the same device is used to mount said filesystem).
services.btrfs.autoScrub.fileSystems =
let
isDeviceInList = list: device: builtins.filter (e: e.device == device) list != [ ];
uniqueDeviceList = foldl' (acc: e: if isDeviceInList acc e.device then acc else acc ++ [ e ]) [ ];
in
mkDefault (
map (e: e.mountPoint) (
uniqueDeviceList (
mapAttrsToList (name: fs: {
mountPoint = fs.mountPoint;
device = fs.device;
}) (filterAttrs (name: fs: fs.fsType == "btrfs") config.fileSystems)
)
)
);
# TODO: Did not manage to do it via the usual btrfs-scrub@.timer/.service
# template units due to problems enabling the parameterized units,
# so settled with many units and templating via nix for now.
# https://github.com/NixOS/nixpkgs/pull/32496#discussion_r156527544
systemd.timers =
let
scrubTimer =
fs:
let
fs' = utils.escapeSystemdPath fs;
in
nameValuePair "btrfs-scrub-${fs'}" {
description = "regular btrfs scrub timer on ${fs}";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfgScrub.interval;
AccuracySec = "1d";
Persistent = true;
};
};
in
listToAttrs (map scrubTimer cfgScrub.fileSystems);
systemd.services =
let
scrubService =
fs:
let
fs' = utils.escapeSystemdPath fs;
in
nameValuePair "btrfs-scrub-${fs'}" {
description = "btrfs scrub on ${fs}";
documentation = [ "man:btrfs-scrub(8)" ];
# scrub prevents suspend2ram or proper shutdown
conflicts = [
"shutdown.target"
"sleep.target"
];
before = [
"shutdown.target"
"sleep.target"
];
serviceConfig = {
# simple and not oneshot, otherwise ExecStop is not used
Type = "simple";
Nice = 19;
IOSchedulingClass = "idle";
ExecStart = "${pkgs.btrfs-progs}/bin/btrfs scrub start -B ${fs}";
# if the service is stopped before scrub end, cancel it
ExecStop = pkgs.writeShellScript "btrfs-scrub-maybe-cancel" ''
(${pkgs.btrfs-progs}/bin/btrfs scrub status ${fs} | ${pkgs.gnugrep}/bin/grep finished) || ${pkgs.btrfs-progs}/bin/btrfs scrub cancel ${fs}
'';
};
};
in
listToAttrs (map scrubService cfgScrub.fileSystems);
})
];
}

View File

@@ -0,0 +1,38 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.cifs or false;
in
{
config = {
system.fsPackages = mkIf (config.boot.supportedFilesystems.cifs or false) [ pkgs.cifs-utils ];
boot.initrd.availableKernelModules = mkIf inInitrd [
"cifs"
"nls_utf8"
"hmac"
"md4"
"ecb"
"des_generic"
"sha256"
];
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.cifs-utils}/sbin/mount.cifs
'';
boot.initrd.systemd.extraBin."mount.cifs" = mkIf inInitrd "${pkgs.cifs-utils}/sbin/mount.cifs";
};
}

View File

@@ -0,0 +1,29 @@
{
config,
lib,
pkgs,
...
}:
# TODO: make ecryptfs work in initramfs?
with lib;
{
config = mkIf (config.boot.supportedFilesystems.ecryptfs or false) {
system.fsPackages = [ pkgs.ecryptfs ];
security.wrappers = {
"mount.ecryptfs_private" = {
setuid = true;
owner = "root";
group = "root";
source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private";
};
"umount.ecryptfs_private" = {
setuid = true;
owner = "root";
group = "root";
source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private";
};
};
};
}

View File

@@ -0,0 +1,78 @@
{
pkgs,
config,
lib,
...
}:
let
cfg = config.services.envfs;
mounts = {
"/usr/bin" = {
device = "none";
fsType = "envfs";
options = [
"bind-mount=/bin"
"fallback-path=${
pkgs.runCommand "fallback-path" { } (
''
mkdir -p $out
ln -s ${config.environment.usrbinenv} $out/env
ln -s ${config.environment.binsh} $out/sh
''
+ cfg.extraFallbackPathCommands
)
}"
"nofail"
];
};
# We need to bind-mount /bin to /usr/bin, because otherwise upgrading
# from envfs < 1.0.5 will cause having the old envs with no /bin bind mount.
# Systemd is smart enough to not mount /bin if it's already mounted.
"/bin" = {
device = "/usr/bin";
fsType = "none";
options = [
"bind"
"nofail"
];
};
};
in
{
options = {
services.envfs = {
enable = lib.mkEnableOption "Envfs filesystem" // {
description = ''
Fuse filesystem that returns symlinks to executables based on the PATH
of the requesting process. This is useful to execute shebangs on NixOS
that assume hard coded locations in locations like /bin or /usr/bin
etc.
'';
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.envfs;
defaultText = lib.literalExpression "pkgs.envfs";
description = "Which package to use for the envfs.";
};
extraFallbackPathCommands = lib.mkOption {
type = lib.types.lines;
default = "";
example = "ln -s $''{pkgs.bash}/bin/bash $out/bash";
description = "Extra commands to run in the package that contains fallback executables in case not other executable is found";
};
};
};
config = lib.mkIf (cfg.enable) {
environment.systemPackages = [ cfg.package ];
# we also want these mounts in virtual machines.
fileSystems = if config.virtualisation ? qemu then lib.mkVMOverride mounts else mounts;
# We no longer need those when using envfs
system.activationScripts.usrbinenv = lib.mkForce "";
system.activationScripts.binsh = lib.mkForce "";
};
}

View File

@@ -0,0 +1,26 @@
{
config,
lib,
pkgs,
...
}:
let
inInitrd = config.boot.initrd.supportedFilesystems.erofs or false;
inSystem = config.boot.supportedFilesystems.erofs or false;
in
{
config = lib.mkIf (inInitrd || inSystem) {
system.fsPackages = [ pkgs.erofs-utils ];
boot.initrd.availableKernelModules = lib.mkIf inInitrd [ "erofs" ];
# fsck.erofs is currently experimental and should not be run as a
# privileged user. Thus, it is not included in the initrd.
};
}

View File

@@ -0,0 +1,22 @@
{
config,
lib,
pkgs,
...
}:
with lib;
{
config = mkIf (config.boot.supportedFilesystems.exfat or false) {
system.fsPackages =
if config.boot.kernelPackages.kernelOlder "5.7" then
[
pkgs.exfat # FUSE
]
else
[
pkgs.exfatprogs # non-FUSE
];
};
}

View File

@@ -0,0 +1,42 @@
{
config,
lib,
pkgs,
...
}:
let
hasExtX = s: s.ext2 or s.ext3 or s.ext4 or false;
inInitrd = hasExtX config.boot.initrd.supportedFilesystems;
inSystem = hasExtX config.boot.supportedFilesystems;
in
{
config = {
system.fsPackages = lib.mkIf (config.boot.initrd.systemd.enable -> (inInitrd || inSystem)) [
pkgs.e2fsprogs
];
# As of kernel 4.3, there is no separate ext3 driver (they're also handled by ext4.ko)
boot.initrd.availableKernelModules = lib.mkIf (config.boot.initrd.systemd.enable -> inInitrd) [
"ext2"
"ext4"
];
boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
# Copy e2fsck and friends.
copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/e2fsck
copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/tune2fs
ln -sv e2fsck $out/bin/fsck.ext2
ln -sv e2fsck $out/bin/fsck.ext3
ln -sv e2fsck $out/bin/fsck.ext4
'';
boot.initrd.systemd.initrdBin = lib.mkIf inInitrd [ pkgs.e2fsprogs ];
};
}

View File

@@ -0,0 +1,29 @@
{
config,
pkgs,
lib,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.f2fs or false;
in
{
config = mkIf (config.boot.supportedFilesystems.f2fs or false) {
system.fsPackages = [ pkgs.f2fs-tools ];
boot.initrd.availableKernelModules = mkIf inInitrd [
"f2fs"
"crc32"
];
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/fsck.f2fs
'';
boot.initrd.systemd.initrdBin = mkIf inInitrd [ pkgs.f2fs-tools ];
};
}

View File

@@ -0,0 +1,16 @@
{
config,
lib,
pkgs,
...
}:
with lib;
{
config = mkIf (config.boot.supportedFilesystems.glusterfs or false) {
system.fsPackages = [ pkgs.glusterfs ];
};
}

View File

@@ -0,0 +1,26 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.jfs or false;
in
{
config = mkIf (config.boot.supportedFilesystems.jfs or false) {
system.fsPackages = [ pkgs.jfsutils ];
boot.initrd.kernelModules = mkIf inInitrd [ "jfs" ];
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.jfsutils}/sbin/fsck.jfs
'';
boot.initrd.systemd.initrdBin = mkIf inInitrd [ pkgs.jfsutils ];
};
}

View File

@@ -0,0 +1,217 @@
{
config,
lib,
pkgs,
...
}:
let
inInitrd = config.boot.initrd.supportedFilesystems.nfs or false;
nfsStateDir = "/var/lib/nfs";
rpcMountpoint = "${nfsStateDir}/rpc_pipefs";
format = pkgs.formats.ini { };
idmapdConfFile = format.generate "idmapd.conf" cfg.idmapd.settings;
# merge parameters from services.nfs.server
nfsConfSettings =
lib.optionalAttrs (cfg.server.nproc != null) {
nfsd.threads = cfg.server.nproc;
}
// lib.optionalAttrs (cfg.server.hostName != null) {
nfsd.host = cfg.server.hostName;
}
// lib.optionalAttrs (cfg.server.mountdPort != null) {
mountd.port = cfg.server.mountdPort;
}
// lib.optionalAttrs (cfg.server.statdPort != null) {
statd.port = cfg.server.statdPort;
}
// lib.optionalAttrs (cfg.server.lockdPort != null) {
lockd.port = cfg.server.lockdPort;
lockd.udp-port = cfg.server.lockdPort;
};
nfsConfDeprecated = cfg.extraConfig + ''
[nfsd]
threads=${toString cfg.server.nproc}
${lib.optionalString (cfg.server.hostName != null) "host=${cfg.server.hostName}"}
${cfg.server.extraNfsdConfig}
[mountd]
${lib.optionalString (cfg.server.mountdPort != null) "port=${toString cfg.server.mountdPort}"}
[statd]
${lib.optionalString (cfg.server.statdPort != null) "port=${toString cfg.server.statdPort}"}
[lockd]
${lib.optionalString (cfg.server.lockdPort != null) ''
port=${toString cfg.server.lockdPort}
udp-port=${toString cfg.server.lockdPort}
''}
'';
nfsConfFile =
if cfg.settings != { } then
format.generate "nfs.conf" (lib.recursiveUpdate nfsConfSettings cfg.settings)
else
pkgs.writeText "nfs.conf" nfsConfDeprecated;
requestKeyConfFile = pkgs.writeText "request-key.conf" ''
create id_resolver * * ${pkgs.nfs-utils}/bin/nfsidmap -t 600 %k %d
'';
cfg = config.services.nfs;
in
{
###### interface
options = {
services.nfs = {
idmapd.settings = lib.mkOption {
type = format.type;
default = { };
description = ''
libnfsidmap configuration. Refer to
<https://linux.die.net/man/5/idmapd.conf>
for details.
'';
example = lib.literalExpression ''
{
Translation = {
GSS-Methods = "static,nsswitch";
};
Static = {
"root/hostname.domain.com@REALM.COM" = "root";
};
}
'';
};
settings = lib.mkOption {
type = format.type;
default = { };
description = ''
General configuration for NFS daemons and tools.
See {manpage}`nfs.conf(5)` and related man pages for details.
'';
example = lib.literalExpression ''
{
mountd.manage-gids = true;
}
'';
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Extra nfs-utils configuration.
'';
};
};
};
###### implementation
config =
lib.mkIf (config.boot.supportedFilesystems.nfs or config.boot.supportedFilesystems.nfs4 or false)
{
warnings =
(lib.optional (cfg.extraConfig != "") ''
`services.nfs.extraConfig` is deprecated. Use `services.nfs.settings` instead.
'')
++ (lib.optional (cfg.server.extraNfsdConfig != "") ''
`services.nfs.server.extraNfsdConfig` is deprecated. Use `services.nfs.settings` instead.
'');
assertions = [
{
assertion = cfg.settings != { } -> cfg.extraConfig == "" && cfg.server.extraNfsdConfig == "";
message = "`services.nfs.settings` cannot be used together with `services.nfs.extraConfig` and `services.nfs.server.extraNfsdConfig`.";
}
];
services.rpcbind.enable = true;
services.nfs.idmapd.settings = {
General = lib.mkMerge [
{ Pipefs-Directory = rpcMountpoint; }
(lib.mkIf (config.networking.domain != null) { Domain = config.networking.domain; })
];
Mapping = {
Nobody-User = "nobody";
Nobody-Group = "nogroup";
};
Translation = {
Method = "nsswitch";
};
};
system.fsPackages = [ pkgs.nfs-utils ];
boot.initrd.kernelModules = lib.mkIf inInitrd [ "nfs" ];
systemd.packages = [ pkgs.nfs-utils ];
environment.systemPackages = [ pkgs.keyutils ];
environment.etc = {
"idmapd.conf".source = idmapdConfFile;
"nfs.conf".source = nfsConfFile;
"request-key.conf".source = requestKeyConfFile;
};
systemd.services.nfs-blkmap = {
restartTriggers = [ nfsConfFile ];
};
systemd.targets.nfs-client = {
wantedBy = [
"multi-user.target"
"remote-fs.target"
];
};
systemd.services.nfs-idmapd = {
restartTriggers = [ idmapdConfFile ];
};
systemd.services.nfs-mountd = {
restartTriggers = [ nfsConfFile ];
enable = lib.mkDefault false;
};
systemd.services.nfs-server = {
restartTriggers = [ nfsConfFile ];
enable = lib.mkDefault false;
};
systemd.services.auth-rpcgss-module = {
unitConfig.ConditionPathExists = [
""
"/etc/krb5.keytab"
];
};
systemd.services.rpc-gssd = {
restartTriggers = [ nfsConfFile ];
unitConfig.ConditionPathExists = [
""
"/etc/krb5.keytab"
];
};
systemd.services.rpc-statd = {
restartTriggers = [ nfsConfFile ];
preStart = ''
mkdir -p /var/lib/nfs/{sm,sm.bak}
'';
};
};
}

View File

@@ -0,0 +1,18 @@
{
config,
lib,
pkgs,
...
}:
with lib;
{
config =
mkIf (config.boot.supportedFilesystems.ntfs or config.boot.supportedFilesystems.ntfs-3g or false)
{
system.fsPackages = [ pkgs.ntfs3g ];
};
}

View File

@@ -0,0 +1,200 @@
{
config,
lib,
pkgs,
utils,
...
}:
let
# The scripted initrd contains some magic to add the prefix to the
# paths just in time, so we don't add it here.
sysrootPrefix =
fs:
if
config.boot.initrd.systemd.enable
&& fs.overlay.useStage1BaseDirectories
&& (utils.fsNeededForBoot fs)
then
"/sysroot"
else
"";
# Returns a service that creates the required directories before the mount is
# created.
preMountService =
_name: fs:
let
prefix = sysrootPrefix fs;
escapedMountpoint = utils.escapeSystemdPath (prefix + fs.mountPoint);
mountUnit = "${escapedMountpoint}.mount";
upperdir = prefix + fs.overlay.upperdir;
workdir = prefix + fs.overlay.workdir;
in
lib.mkIf (fs.overlay.upperdir != null) {
"rw-${escapedMountpoint}" = {
requiredBy = [ mountUnit ];
before = [ mountUnit ];
unitConfig = {
DefaultDependencies = false;
RequiresMountsFor = "${upperdir} ${workdir}";
};
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.coreutils}/bin/mkdir -p -m 0755 ${upperdir} ${workdir}";
};
};
};
overlayOpts =
{
config,
...
}:
{
options.overlay = {
lowerdir = lib.mkOption {
type = with lib.types; nullOr (nonEmptyListOf (either str pathInStore));
default = null;
description = ''
The list of path(s) to the lowerdir(s).
To create a writable overlay, you MUST provide an `upperdir` and a
`workdir`.
You can create a read-only overlay when you provide multiple (at
least 2!) lowerdirs and neither an `upperdir` nor a `workdir`.
'';
};
upperdir = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
The path to the upperdir.
If this is null, a read-only overlay is created using the lowerdir.
If the filesystem is `neededForBoot`, this will be prefixed with `/sysroot`,
unless `useStage1BaseDirectories` is set to `true`.
If you set this to some value you MUST also set `workdir`.
'';
};
workdir = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
The path to the workdir.
If the filesystem is `neededForBoot`, this will be prefixed with `/sysroot`,
unless `useStage1BaseDirectories` is set to `true`.
This MUST be set if you set `upperdir`.
'';
};
useStage1BaseDirectories = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
If enabled, `lowerdir`, `upperdir` and `workdir` will be prefixed with `/sysroot`.
Disabling this can be useful to create an overlay over directories which aren't on the real root.
Disabling this does not work with the scripted (i.e. non-systemd) initrd.
'';
};
};
config = lib.mkIf (config.overlay.lowerdir != null) {
fsType = "overlay";
device = lib.mkDefault "overlay";
depends = map (x: "${x}") (
config.overlay.lowerdir
++ lib.optionals (config.overlay.upperdir != null) [
config.overlay.upperdir
config.overlay.workdir
]
);
options =
let
prefix = sysrootPrefix config;
lowerdir = map (s: prefix + s) config.overlay.lowerdir;
upperdir = prefix + config.overlay.upperdir;
workdir = prefix + config.overlay.workdir;
in
[
"lowerdir=${lib.concatStringsSep ":" lowerdir}"
]
++ lib.optionals (config.overlay.upperdir != null) [
"upperdir=${upperdir}"
"workdir=${workdir}"
];
};
};
in
{
options = {
# Merge the overlay options into the fileSystems option.
fileSystems = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule [ overlayOpts ]);
};
};
config =
let
overlayFileSystems = lib.filterAttrs (_name: fs: (fs.overlay.lowerdir != null)) config.fileSystems;
initrdFileSystems = lib.filterAttrs (_name: utils.fsNeededForBoot) overlayFileSystems;
userspaceFileSystems = lib.filterAttrs (_name: fs: (!utils.fsNeededForBoot fs)) overlayFileSystems;
in
{
boot.initrd.availableKernelModules = lib.mkIf (initrdFileSystems != { }) [ "overlay" ];
assertions =
lib.concatLists (
lib.mapAttrsToList (_name: fs: [
{
assertion = (fs.overlay.upperdir == null) == (fs.overlay.workdir == null);
message = "You cannot define a `lowerdir` without a `workdir` and vice versa for mount point: ${fs.mountPoint}";
}
{
assertion =
(fs.overlay.lowerdir != null && fs.overlay.upperdir == null)
-> (lib.length fs.overlay.lowerdir) >= 2;
message = "A read-only overlay (without an `upperdir`) requires at least 2 `lowerdir`s: ${fs.mountPoint}";
}
{
assertion = !fs.overlay.useStage1BaseDirectories -> config.boot.initrd.systemd.enable;
message = ''
Stage 1 overlay file system ${fs.mountPoint} has 'useStage1BaseDirectories' set to false,
which is not supported with scripted initrd. Please enable 'boot.initrd.systemd.enable'.
'';
}
]) overlayFileSystems
)
++ lib.mapAttrsToList (_: fs: {
assertion = fs.overlay.upperdir == null -> config.boot.initrd.systemd.enable;
message = ''
Stage 1 overlay file system ${fs.mountPoint} has no upperdir,
which is not supported with scripted initrd. Please enable
'boot.initrd.systemd.enable'.
'';
}) initrdFileSystems;
boot.initrd.systemd.services = lib.mkMerge (lib.mapAttrsToList preMountService initrdFileSystems);
systemd.services = lib.mkMerge (lib.mapAttrsToList preMountService userspaceFileSystems);
};
}

View File

@@ -0,0 +1,31 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.reiserfs or false;
in
{
config = mkIf (config.boot.supportedFilesystems.reiserfs or false) {
system.fsPackages = [ pkgs.reiserfsprogs ];
boot.initrd.kernelModules = mkIf inInitrd [ "reiserfs" ];
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.reiserfsprogs}/sbin/reiserfsck
ln -s reiserfsck $out/bin/fsck.reiserfs
'';
boot.initrd.systemd.initrdBin = mkIf inInitrd [ pkgs.reiserfsprogs ];
};
}

View File

@@ -0,0 +1,13 @@
{ config, lib, ... }:
let
inInitrd = config.boot.initrd.supportedFilesystems.squashfs or false;
in
{
boot.initrd.availableKernelModules = lib.mkIf inInitrd [ "squashfs" ];
}

View File

@@ -0,0 +1,15 @@
{
config,
lib,
pkgs,
...
}:
{
config =
lib.mkIf
(config.boot.supportedFilesystems.sshfs or config.boot.supportedFilesystems."fuse.sshfs" or false)
{
system.fsPackages = [ pkgs.sshfs ];
};
}

View File

@@ -0,0 +1,48 @@
{
config,
pkgs,
lib,
...
}:
{
config = lib.mkMerge [
(lib.mkIf (config.boot.initrd.supportedFilesystems.unionfs-fuse or false) {
boot.initrd.kernelModules = [ "fuse" ];
boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.fuse}/sbin/mount.fuse
copy_bin_and_libs ${pkgs.unionfs-fuse}/bin/unionfs
substitute ${pkgs.unionfs-fuse}/sbin/mount.unionfs-fuse $out/bin/mount.unionfs-fuse \
--replace '${pkgs.bash}/bin/bash' /bin/sh \
--replace '${pkgs.fuse}/sbin' /bin \
--replace '${pkgs.unionfs-fuse}/bin' /bin
chmod +x $out/bin/mount.unionfs-fuse
'';
boot.initrd.postDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
# Hacky!!! fuse hard-codes the path to mount
mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.util-linux.name}-bin/bin
ln -s $(which mount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.util-linux.name}-bin/bin
ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.util-linux.name}-bin/bin
'';
boot.initrd.systemd.extraBin = {
"mount.fuse" = "${pkgs.fuse}/bin/mount.fuse";
"unionfs" = "${pkgs.unionfs-fuse}/bin/unionfs";
"mount.unionfs-fuse" = pkgs.runCommand "mount.unionfs-fuse" { } ''
substitute ${pkgs.unionfs-fuse}/sbin/mount.unionfs-fuse $out \
--replace '${pkgs.bash}/bin/bash' /bin/sh \
--replace '${pkgs.fuse}/sbin' /bin \
--replace '${pkgs.unionfs-fuse}/bin' /bin
'';
};
})
(lib.mkIf (config.boot.supportedFilesystems.unionfs-fuse or false) {
system.fsPackages = [ pkgs.unionfs-fuse ];
})
];
}

View File

@@ -0,0 +1,28 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.vboxsf or false;
package = pkgs.runCommand "mount.vboxsf" { preferLocalBuild = true; } ''
mkdir -p $out/bin
cp ${pkgs.linuxPackages.virtualboxGuestAdditions}/bin/mount.vboxsf $out/bin
'';
in
{
config = mkIf (config.boot.supportedFilesystems.vboxsf or false) {
system.fsPackages = [ package ];
boot.initrd.kernelModules = mkIf inInitrd [ "vboxsf" ];
};
}

View File

@@ -0,0 +1,38 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.vfat or false;
in
{
config = mkIf (config.boot.supportedFilesystems.vfat or false) {
system.fsPackages = [
pkgs.dosfstools
pkgs.mtools
];
boot.initrd.kernelModules = mkIf inInitrd [
"vfat"
"nls_cp437"
"nls_iso8859-1"
];
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.dosfstools}/sbin/dosfsck
ln -sv dosfsck $out/bin/fsck.vfat
'';
boot.initrd.systemd.initrdBin = mkIf inInitrd [ pkgs.dosfstools ];
};
}

View File

@@ -0,0 +1,38 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
inInitrd = config.boot.initrd.supportedFilesystems.xfs or false;
in
{
config = mkIf (config.boot.supportedFilesystems.xfs or false) {
system.fsPackages = [ pkgs.xfsprogs.bin ];
boot.initrd.availableKernelModules = mkIf inInitrd [
"xfs"
"crc32c"
];
boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
copy_bin_and_libs ${pkgs.xfsprogs.bin}/bin/fsck.xfs
copy_bin_and_libs ${pkgs.xfsprogs.bin}/bin/xfs_repair
'';
# Trick just to set 'sh' after the extraUtils nuke-refs.
boot.initrd.extraUtilsCommandsTest = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
sed -i -e 's,^#!.*,#!'$out/bin/sh, $out/bin/fsck.xfs
'';
boot.initrd.systemd.initrdBin = mkIf inInitrd [ pkgs.xfsprogs.bin ];
};
}

File diff suppressed because it is too large Load Diff