587713944a
GitOrigin-RevId: 6143fc5eeb9c4f00163267708e26191d1e918932
165 lines
5.5 KiB
Nix
165 lines
5.5 KiB
Nix
{ 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
|
|
inherit (utils.systemdUtils.lib) GPTMaxLabelLength;
|
|
labelLength = builtins.stringLength definition.Label;
|
|
in
|
|
{
|
|
assertion = definition ? Label -> GPTMaxLabelLength >= 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 GPTMaxLabelLength}.
|
|
'';
|
|
}
|
|
) cfg.partitions;
|
|
in
|
|
{
|
|
options = {
|
|
boot.initrd.systemd.repart = {
|
|
enable = lib.mkEnableOption "systemd-repart" // {
|
|
description = ''
|
|
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 = ''
|
|
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 "systemd-repart" // {
|
|
description = ''
|
|
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 = ''
|
|
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 ];
|
|
}
|