diff options
Diffstat (limited to 'nixpkgs/nixos/modules/system/boot/systemd/repart.nix')
-rw-r--r-- | nixpkgs/nixos/modules/system/boot/systemd/repart.nix | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/system/boot/systemd/repart.nix b/nixpkgs/nixos/modules/system/boot/systemd/repart.nix new file mode 100644 index 000000000000..6cc387cb6f43 --- /dev/null +++ b/nixpkgs/nixos/modules/system/boot/systemd/repart.nix @@ -0,0 +1,165 @@ +{ config, lib, pkgs, utils, ... }: + +let + cfg = config.systemd.repart; + initrdCfg = config.boot.initrd.systemd.repart; + + format = pkgs.formats.ini { }; + + definitionsDirectory = utils.systemdUtils.lib.definitions + "repart.d" + format + (lib.mapAttrs (_n: v: { Partition = v; }) cfg.partitions); + + partitionAssertions = lib.mapAttrsToList (fileName: definition: + let + maxLabelLength = 36; # GPT_LABEL_MAX defined in systemd's gpt.h + labelLength = builtins.stringLength definition.Label; + in + { + assertion = definition ? Label -> maxLabelLength >= labelLength; + message = '' + The partition label '${definition.Label}' defined for '${fileName}' is ${toString labelLength} + characters long, but the maximum label length supported by systemd is ${toString maxLabelLength}. + ''; + } + ) cfg.partitions; +in +{ + options = { + boot.initrd.systemd.repart = { + enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // { + description = lib.mdDoc '' + Grow and add partitions to a partition table at boot time in the initrd. + systemd-repart only works with GPT partition tables. + + To run systemd-repart after the initrd, see + `options.systemd.repart.enable`. + ''; + }; + + device = lib.mkOption { + type = with lib.types; nullOr str; + description = lib.mdDoc '' + The device to operate on. + + If `device == null`, systemd-repart will operate on the device + backing the root partition. So in order to dynamically *create* the + root partition in the initrd you need to set a device. + ''; + default = null; + example = "/dev/vda"; + }; + }; + + systemd.repart = { + enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // { + description = lib.mdDoc '' + Grow and add partitions to a partition table. + systemd-repart only works with GPT partition tables. + + To run systemd-repart while in the initrd, see + `options.boot.initrd.systemd.repart.enable`. + ''; + }; + + partitions = lib.mkOption { + type = with lib.types; attrsOf (attrsOf (oneOf [ str int bool ])); + default = { }; + example = { + "10-root" = { + Type = "root"; + }; + "20-home" = { + Type = "home"; + SizeMinBytes = "512M"; + SizeMaxBytes = "2G"; + }; + }; + description = lib.mdDoc '' + Specify partitions as a set of the names of the definition files as the + key and the partition configuration as its value. The partition + configuration can use all upstream options. See <link + xlink:href="https://www.freedesktop.org/software/systemd/man/repart.d.html"/> + for all available options. + ''; + }; + }; + }; + + config = lib.mkIf (cfg.enable || initrdCfg.enable) { + assertions = [ + { + assertion = initrdCfg.enable -> config.boot.initrd.systemd.enable; + message = '' + 'boot.initrd.systemd.repart.enable' requires 'boot.initrd.systemd.enable' to be enabled. + ''; + } + ] ++ partitionAssertions; + + # systemd-repart uses loopback devices for partition creation + boot.initrd.availableKernelModules = lib.optional initrdCfg.enable "loop"; + + boot.initrd.systemd = lib.mkIf initrdCfg.enable { + additionalUpstreamUnits = [ + "systemd-repart.service" + ]; + + storePaths = [ + "${config.boot.initrd.systemd.package}/bin/systemd-repart" + ]; + + contents."/etc/repart.d".source = definitionsDirectory; + + # Override defaults in upstream unit. + services.systemd-repart = + let + deviceUnit = "${utils.escapeSystemdPath initrdCfg.device}.device"; + in + { + # systemd-repart tries to create directories in /var/tmp by default to + # store large temporary files that benefit from persistence on disk. In + # the initrd, however, /var/tmp does not provide more persistence than + # /tmp, so we re-use it here. + environment."TMPDIR" = "/tmp"; + serviceConfig = { + ExecStart = [ + " " # required to unset the previous value. + # When running in the initrd, systemd-repart by default searches + # for definition files in /sysroot or /sysusr. We tell it to look + # in the initrd itself. + ''${config.boot.initrd.systemd.package}/bin/systemd-repart \ + --definitions=/etc/repart.d \ + --dry-run=no ${lib.optionalString (initrdCfg.device != null) initrdCfg.device} + '' + ]; + }; + # systemd-repart needs to run after /sysroot (or /sysuser, but we + # don't have it) has been mounted because otherwise it cannot + # determine the device (i.e disk) to operate on. If you want to run + # systemd-repart without /sysroot (i.e. to create the root + # partition), you have to explicitly tell it which device to operate + # on. The service then needs to be ordered to run after this device + # is available. + requires = lib.mkIf (initrdCfg.device != null) [ deviceUnit ]; + after = + if initrdCfg.device == null then + [ "sysroot.mount" ] + else + [ deviceUnit ]; + }; + }; + + environment.etc = lib.mkIf cfg.enable { + "repart.d".source = definitionsDirectory; + }; + + systemd = lib.mkIf cfg.enable { + additionalUpstreamSystemUnits = [ + "systemd-repart.service" + ]; + }; + }; + + meta.maintainers = with lib.maintainers; [ nikstur ]; +} |