at 24.11-pre 5.7 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3let 4 cfg = config.systemd.repart; 5 initrdCfg = config.boot.initrd.systemd.repart; 6 7 format = pkgs.formats.ini { }; 8 9 definitionsDirectory = utils.systemdUtils.lib.definitions 10 "repart.d" 11 format 12 (lib.mapAttrs (_n: v: { Partition = v; }) cfg.partitions); 13 14 partitionAssertions = lib.mapAttrsToList (fileName: definition: 15 let 16 inherit (utils.systemdUtils.lib) GPTMaxLabelLength; 17 labelLength = builtins.stringLength definition.Label; 18 in 19 { 20 assertion = definition ? Label -> GPTMaxLabelLength >= labelLength; 21 message = '' 22 The partition label '${definition.Label}' defined for '${fileName}' is ${toString labelLength} 23 characters long, but the maximum label length supported by systemd is ${toString GPTMaxLabelLength}. 24 ''; 25 } 26 ) cfg.partitions; 27in 28{ 29 options = { 30 boot.initrd.systemd.repart = { 31 enable = lib.mkEnableOption "systemd-repart" // { 32 description = '' 33 Grow and add partitions to a partition table at boot time in the initrd. 34 systemd-repart only works with GPT partition tables. 35 36 To run systemd-repart after the initrd, see 37 `options.systemd.repart.enable`. 38 ''; 39 }; 40 41 device = lib.mkOption { 42 type = with lib.types; nullOr str; 43 description = '' 44 The device to operate on. 45 46 If `device == null`, systemd-repart will operate on the device 47 backing the root partition. So in order to dynamically *create* the 48 root partition in the initrd you need to set a device. 49 ''; 50 default = null; 51 example = "/dev/vda"; 52 }; 53 }; 54 55 systemd.repart = { 56 enable = lib.mkEnableOption "systemd-repart" // { 57 description = '' 58 Grow and add partitions to a partition table. 59 systemd-repart only works with GPT partition tables. 60 61 To run systemd-repart while in the initrd, see 62 `options.boot.initrd.systemd.repart.enable`. 63 ''; 64 }; 65 66 partitions = lib.mkOption { 67 type = with lib.types; attrsOf (attrsOf (oneOf [ str int bool ])); 68 default = { }; 69 example = { 70 "10-root" = { 71 Type = "root"; 72 }; 73 "20-home" = { 74 Type = "home"; 75 SizeMinBytes = "512M"; 76 SizeMaxBytes = "2G"; 77 }; 78 }; 79 description = '' 80 Specify partitions as a set of the names of the definition files as the 81 key and the partition configuration as its value. The partition 82 configuration can use all upstream options. See <link 83 xlink:href="https://www.freedesktop.org/software/systemd/man/repart.d.html"/> 84 for all available options. 85 ''; 86 }; 87 }; 88 }; 89 90 config = lib.mkIf (cfg.enable || initrdCfg.enable) { 91 assertions = [ 92 { 93 assertion = initrdCfg.enable -> config.boot.initrd.systemd.enable; 94 message = '' 95 'boot.initrd.systemd.repart.enable' requires 'boot.initrd.systemd.enable' to be enabled. 96 ''; 97 } 98 ] ++ partitionAssertions; 99 100 # systemd-repart uses loopback devices for partition creation 101 boot.initrd.availableKernelModules = lib.optional initrdCfg.enable "loop"; 102 103 boot.initrd.systemd = lib.mkIf initrdCfg.enable { 104 additionalUpstreamUnits = [ 105 "systemd-repart.service" 106 ]; 107 108 storePaths = [ 109 "${config.boot.initrd.systemd.package}/bin/systemd-repart" 110 ]; 111 112 contents."/etc/repart.d".source = definitionsDirectory; 113 114 # Override defaults in upstream unit. 115 services.systemd-repart = 116 let 117 deviceUnit = "${utils.escapeSystemdPath initrdCfg.device}.device"; 118 in 119 { 120 # systemd-repart tries to create directories in /var/tmp by default to 121 # store large temporary files that benefit from persistence on disk. In 122 # the initrd, however, /var/tmp does not provide more persistence than 123 # /tmp, so we re-use it here. 124 environment."TMPDIR" = "/tmp"; 125 serviceConfig = { 126 ExecStart = [ 127 " " # required to unset the previous value. 128 # When running in the initrd, systemd-repart by default searches 129 # for definition files in /sysroot or /sysusr. We tell it to look 130 # in the initrd itself. 131 ''${config.boot.initrd.systemd.package}/bin/systemd-repart \ 132 --definitions=/etc/repart.d \ 133 --dry-run=no ${lib.optionalString (initrdCfg.device != null) initrdCfg.device} 134 '' 135 ]; 136 }; 137 # systemd-repart needs to run after /sysroot (or /sysuser, but we 138 # don't have it) has been mounted because otherwise it cannot 139 # determine the device (i.e disk) to operate on. If you want to run 140 # systemd-repart without /sysroot (i.e. to create the root 141 # partition), you have to explicitly tell it which device to operate 142 # on. The service then needs to be ordered to run after this device 143 # is available. 144 requires = lib.mkIf (initrdCfg.device != null) [ deviceUnit ]; 145 after = 146 if initrdCfg.device == null then 147 [ "sysroot.mount" ] 148 else 149 [ deviceUnit ]; 150 }; 151 }; 152 153 environment.etc = lib.mkIf cfg.enable { 154 "repart.d".source = definitionsDirectory; 155 }; 156 157 systemd = lib.mkIf cfg.enable { 158 additionalUpstreamSystemUnits = [ 159 "systemd-repart.service" 160 ]; 161 }; 162 }; 163 164 meta.maintainers = with lib.maintainers; [ nikstur ]; 165}