about summary refs log tree commit diff
path: root/nixos/modules/system
diff options
context:
space:
mode:
authorArian van Putten <arian.vanputten@gmail.com>2023-02-10 20:03:09 +0100
committerGitHub <noreply@github.com>2023-02-10 20:03:09 +0100
commit5b23d0e51c440e717bec8cdf5fe695b03a12fe43 (patch)
treecf9e7a5eaf6afabca6a7233df0e6cfdc76f777ac /nixos/modules/system
parentc34c235192bb2827d979aaf728db7451a5baf57e (diff)
parent4700198654affcca0a76915e083b857e7e605cf5 (diff)
Merge pull request #214396 from nikstur/systemd-repart
systemd-repart
Diffstat (limited to 'nixos/modules/system')
-rw-r--r--nixos/modules/system/boot/systemd/repart.nix101
1 files changed, 101 insertions, 0 deletions
diff --git a/nixos/modules/system/boot/systemd/repart.nix b/nixos/modules/system/boot/systemd/repart.nix
new file mode 100644
index 0000000000000..33f1b247c5ede
--- /dev/null
+++ b/nixos/modules/system/boot/systemd/repart.nix
@@ -0,0 +1,101 @@
+{ config, pkgs, lib, ... }:
+
+let
+  cfg = config.boot.initrd.systemd.repart;
+
+  writeDefinition = name: partitionConfig: pkgs.writeText
+    "${name}.conf"
+    (lib.generators.toINI { } { Partition = partitionConfig; });
+
+  listOfDefinitions = lib.mapAttrsToList
+    writeDefinition
+    (lib.filterAttrs (k: _: !(lib.hasPrefix "_" k)) cfg.partitions);
+
+  # Create a directory in the store that contains a copy of all definition
+  # files. This is then passed to systemd-repart in the initrd so it can access
+  # the definition files after the sysroot has been mounted but before
+  # activation. This needs a hard copy of the files and not just symlinks
+  # because otherwise the files do not show up in the sysroot.
+  definitionsDirectory = pkgs.runCommand "systemd-repart-definitions" { } ''
+    mkdir -p $out
+    ${(lib.concatStringsSep "\n"
+      (map (pkg: "cp ${pkg} $out/${pkg.name}") listOfDefinitions)
+    )}
+  '';
+in
+{
+  options.boot.initrd.systemd.repart = {
+    enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
+      description = lib.mdDoc ''
+        Grow and add partitions to a partition table a boot time in the initrd.
+        systemd-repart only works with GPT partition tables.
+      '';
+    };
+
+    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 {
+    # Link the definitions into /etc so that they are included in the
+    # /nix/store of the sysroot. This also allows the user to run the
+    # systemd-repart binary after activation manually while automatically
+    # picking up the definition files.
+    environment.etc."repart.d".source = definitionsDirectory;
+
+    boot.initrd.systemd = {
+      additionalUpstreamUnits = [
+        "systemd-repart.service"
+      ];
+
+      storePaths = [
+        "${config.boot.initrd.systemd.package}/bin/systemd-repart"
+      ];
+
+      # Override defaults in upstream unit.
+      services.systemd-repart = {
+        # Unset the coniditions as they cannot be met before activation because
+        # the definition files are not stored in the expected locations.
+        unitConfig.ConditionDirectoryNotEmpty = [
+          " " # required to unset the previous value.
+        ];
+        serviceConfig = {
+          # systemd-repart runs before the activation script. Thus we cannot
+          # rely on them being linked in /etc already. Instead we have to
+          # explicitly pass their location in the sysroot to the binary.
+          ExecStart = [
+            " " # required to unset the previous value.
+            ''${config.boot.initrd.systemd.package}/bin/systemd-repart \
+                  --definitions=/sysroot${definitionsDirectory} \
+                  --dry-run=no
+            ''
+          ];
+        };
+        # Because the initrd does not have the `initrd-usr-fs.target` the
+        # upestream unit runs too early in the boot process, before the sysroot
+        # is available. However, systemd-repart needs access to the sysroot to
+        # find the definition files.
+        after = [ "sysroot.mount" ];
+      };
+    };
+  };
+}