improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
/*
2024-02-27 16:36:01 +01:00
# `fileSystems.*.preMountCommands`/`.postUnmountCommands`
improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
## Implementation
```nix
#*/# end of MarkDown, beginning of NixOS module:
2023-06-16 02:14:51 +02:00
dirname: inputs: moduleArgs@{ config, pkgs, lib, utils, ... }: let lib = inputs.self.lib.__internal__; in let
improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
in {
options = {
fileSystems = lib.mkOption { type = lib.types.attrsOf (lib.types.submodule [ { options = {
2023-11-27 17:15:44 +01:00
preMountCommands = lib.mkOption { description = ''
2023-09-01 17:01:13 +02:00
Commands to be run as root every time before mounting this filesystem **via systemd** , but after all its dependents were mounted.
2023-05-02 02:13:24 +02:00
This does not order itself before or after `systemd-fsck@''${utils.escapeSystemdPath device}.service` .
2023-11-27 17:15:44 +01:00
Note that if a symlink exists at a mount point when systemd's fstab-generator runs, it will read/resolve the symlink and use the link's target as the mount point, resulting in mismatching unit names for that mount, effectively disabling its `.preMountCommands` .
2023-09-01 17:01:13 +02:00
This does not (apparently and unfortunately) run when mounting via the `mount` command (and probably not with the `mount` system call either).
2024-02-01 13:30:57 +01:00
''; type = lib.types.lines; default = ""; };
2024-07-24 16:58:03 +02:00
postMountCommands = lib.mkOption { description = ''
Like `.preMountCommands` , but runs after mounting the filesystem.
''; type = lib.types.lines; default = ""; };
preUnmountCommands = lib.mkOption { description = ''
Like `.preMountCommands` , but runs before unmounting the filesystem.
This will only run before unmounting when the FS is unmounted by systemd before the FS is unmounted
''; type = lib.types.lines; default = ""; };
2024-02-01 13:30:57 +01:00
postUnmountCommands = lib.mkOption { description = ''
Like `.preMountCommands` , but runs after unmounting the filesystem.
2023-05-02 02:13:24 +02:00
''; type = lib.types.lines; default = ""; };
2023-11-27 17:15:44 +01:00
#Also , trying to create the "device" of a "nofail" mount will not work with `mount` , as it will not even attempt to mount anything (and thus not run the `.preMountCommands` ) if the "device" is missing.
improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
}; } ]);
}; };
config = let
2024-02-27 16:36:01 +01:00
assertions = lib.mkIf (!config.boot.initrd.systemd.enable) (lib.mapAttrsToList (name: fs: {
2023-11-27 17:15:44 +01:00
assertion = (fs.preMountCommands == "") || (!utils.fsNeededForBoot fs);
2024-02-27 16:36:01 +01:00
message = ''The filesystem "${name}" has `.preMountCommands` but is also (possibly implicitly) `.neededForBoot` . This is not supported without `boot.initrd.systemd.enable` .'';
}) config.fileSystems);
2023-06-16 02:14:51 +02:00
2022-12-27 15:37:27 +01:00
# The implementation is derived from the "mkfs-${device'}" service in nixpkgs.
2024-07-24 16:58:03 +02:00
mkServices = inInitrd: lib.fun.mapMergeUnique (_: fs@{ mountPoint, device, depends, ... }: let
2023-06-16 02:14:51 +02:00
isDevice = lib.fun.startsWith "/dev/" device;
2024-07-24 16:58:03 +02:00
mountPoint' = utils.escapeSystemdPath mountPoint; mountPointDep = [ "${mountPoint'}.mount" ];
improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
device' = utils.escapeSystemdPath device;
2024-07-24 16:58:03 +02:00
mkService = when: { # TODO: in initrd (or during installation), how to deal with the fact that the system is mounted at "/sysroot"?
description = "Prepare mounting ${device} at ${mountPoint}";
wantedBy = mountPointDep; ${if when != "after" then when else null} = mountPointDep; partOf = mountPointDep;
requires = lib.optional isDevice "${device'}.device"; after = (lib.optionals (when == "after") mountPointDep) ++ (lib.optional isDevice "${device'}.device");
unitConfig.RequiresMountsFor = map utils.escapeSystemdExecArg (depends ++ (lib.optional (lib.hasPrefix "/" device) device) ++ [ (builtins.dirOf mountPoint) ]);
unitConfig.DefaultDependencies = false; restartIfChanged = false;
serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true;
};
prepare = ''
#set -x
'';
in lib.optionalAttrs (inInitrd == utils.fsNeededForBoot fs) (
(lib.optionalAttrs (
fs.preMountCommands != "" || fs.postUnmountCommands != ""
) { "${mountPoint'}-before" = (mkService "before") // {
script = lib.mkIf (fs.preMountCommands != "") (prepare + fs.preMountCommands);
preStop = lib.mkIf (fs.postUnmountCommands != "") (prepare + fs.postUnmountCommands); # ("preStop" still runs post unmount)
}; })
// (lib.optionalAttrs (
fs.postMountCommands != "" || fs.preUnmountCommands != ""
) { "${mountPoint'}-after" = (mkService "after") // {
script = lib.mkIf (fs.postMountCommands != "") (prepare + fs.postMountCommands);
preStop = lib.mkIf (fs.preUnmountCommands != "") (prepare + fs.preUnmountCommands);
}; })
)) config.fileSystems;
improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
2024-02-27 16:36:01 +01:00
in {
inherit assertions;
2024-07-24 16:58:03 +02:00
systemd.services = mkServices false;
boot.initrd.systemd.services = lib.mkIf (config.boot.initrd.systemd.enable) (mkServices true);
2024-02-27 16:36:01 +01:00
};
improve installation, add support for:
ZFS, encryption (keys, keystore, LUKS), bootFS, ephemeral root (tmpfs, ZFS, F2FS, ...), testing in qemu, options & debugging, ... and many small things
2022-05-31 03:41:28 +02:00
}