Unverified Commit 7cdc4dd5 authored by Janne Heß's avatar Janne Heß Committed by GitHub
Browse files

Merge pull request #164943 from ElvishJerricco/systemd-initrd-reuse-systemd-module

initrd: Opt-in bare bones systemd-based initrd
parents 803c1abb 7ebb4ebe
Loading
Loading
Loading
Loading
+34 −50
Original line number Diff line number Diff line
@@ -122,10 +122,15 @@ in rec {
        (if isList value then value else [value]))
        as));

  generateUnits = generateUnits' true;

  generateUnits' = allowCollisions: type: units: upstreamUnits: upstreamWants:
    pkgs.runCommand "${type}-units"
  generateUnits = { allowCollisions ? true, type, units, upstreamUnits, upstreamWants, packages ? cfg.packages, package ? cfg.package }:
    let
      typeDir = ({
        system = "system";
        initrd = "system";
        user = "user";
        nspawn = "nspawn";
      }).${type};
    in pkgs.runCommand "${type}-units"
      { preferLocalBuild = true;
        allowSubstitutes = false;
      } ''
@@ -133,7 +138,7 @@ in rec {

      # Copy the upstream systemd units we're interested in.
      for i in ${toString upstreamUnits}; do
        fn=${cfg.package}/example/systemd/${type}/$i
        fn=${package}/example/systemd/${typeDir}/$i
        if ! [ -e $fn ]; then echo "missing $fn"; false; fi
        if [ -L $fn ]; then
          target="$(readlink "$fn")"
@@ -150,7 +155,7 @@ in rec {
      # Copy .wants links, but only those that point to units that
      # we're interested in.
      for i in ${toString upstreamWants}; do
        fn=${cfg.package}/example/systemd/${type}/$i
        fn=${package}/example/systemd/${typeDir}/$i
        if ! [ -e $fn ]; then echo "missing $fn"; false; fi
        x=$out/$(basename $fn)
        mkdir $x
@@ -162,14 +167,14 @@ in rec {
      done

      # Symlink all units provided listed in systemd.packages.
      packages="${toString cfg.packages}"
      packages="${toString packages}"

      # Filter duplicate directories
      declare -A unique_packages
      for k in $packages ; do unique_packages[$k]=1 ; done

      for i in ''${!unique_packages[@]}; do
        for fn in $i/etc/systemd/${type}/* $i/lib/systemd/${type}/*; do
        for fn in $i/etc/systemd/${typeDir}/* $i/lib/systemd/${typeDir}/*; do
          if ! [[ "$fn" =~ .wants$ ]]; then
            if [[ -d "$fn" ]]; then
              targetDir="$out/$(basename "$fn")"
@@ -270,9 +275,9 @@ in rec {
          { Conflicts = toString config.conflicts; }
        // optionalAttrs (config.requisite != [])
          { Requisite = toString config.requisite; }
        // optionalAttrs (config.restartTriggers != [])
        // optionalAttrs (config ? restartTriggers && config.restartTriggers != [])
          { X-Restart-Triggers = toString config.restartTriggers; }
        // optionalAttrs (config.reloadTriggers != [])
        // optionalAttrs (config ? reloadTriggers && config.reloadTriggers != [])
          { X-Reload-Triggers = toString config.reloadTriggers; }
        // optionalAttrs (config.description != "") {
          Description = config.description; }
@@ -288,45 +293,24 @@ in rec {
    };
  };

  serviceConfig = { name, config, ... }: {
    config = mkMerge
      [ { # Default path for systemd services.  Should be quite minimal.
          path = mkAfter
            [ pkgs.coreutils
  serviceConfig = { config, ... }: {
    config.environment.PATH = mkIf (config.path != []) "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
  };

  stage2ServiceConfig = {
    imports = [ serviceConfig ];
    # Default path for systemd services. Should be quite minimal.
    config.path = mkAfter [
      pkgs.coreutils
      pkgs.findutils
      pkgs.gnugrep
      pkgs.gnused
      systemd
    ];
          environment.PATH = "${makeBinPath config.path}:${makeSearchPathOutput "bin" "sbin" config.path}";
        }
        (mkIf (config.preStart != "")
          { serviceConfig.ExecStartPre =
              [ (makeJobScript "${name}-pre-start" config.preStart) ];
          })
        (mkIf (config.script != "")
          { serviceConfig.ExecStart =
              makeJobScript "${name}-start" config.script + " " + config.scriptArgs;
          })
        (mkIf (config.postStart != "")
          { serviceConfig.ExecStartPost =
              [ (makeJobScript "${name}-post-start" config.postStart) ];
          })
        (mkIf (config.reload != "")
          { serviceConfig.ExecReload =
              makeJobScript "${name}-reload" config.reload;
          })
        (mkIf (config.preStop != "")
          { serviceConfig.ExecStop =
              makeJobScript "${name}-pre-stop" config.preStop;
          })
        (mkIf (config.postStop != "")
          { serviceConfig.ExecStopPost =
              makeJobScript "${name}-post-stop" config.postStop;
          })
      ];
  };

  stage1ServiceConfig = serviceConfig;

  mountConfig = { config, ... }: {
    config = {
      mountConfig =
@@ -374,12 +358,12 @@ in rec {
              # systemd max line length is now 1MiB
              # https://github.com/systemd/systemd/commit/e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af
              in if stringLength s >= 1048576 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
          ${if def.reloadIfChanged then ''
          ${if def ? reloadIfChanged && def.reloadIfChanged then ''
            X-ReloadIfChanged=true
          '' else if !def.restartIfChanged then ''
          '' else if (def ? restartIfChanged && !def.restartIfChanged) then ''
            X-RestartIfChanged=false
          '' else ""}
          ${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
          ${optionalString (def ? stopIfChanged && !def.stopIfChanged) "X-StopIfChanged=false"}
          ${attrsToSection def.serviceConfig}
        '';
    };
+37 −0
Original line number Diff line number Diff line
{ lib, systemdUtils }:

with systemdUtils.lib;
with systemdUtils.unitOptions;
with lib;

rec {
  units = with types;
    attrsOf (submodule ({ name, config, ... }: {
      options = concreteUnitOptions;
      config = { unit = mkDefault (systemdUtils.lib.makeUnit name config); };
    }));

  services = with types; attrsOf (submodule [ stage2ServiceOptions unitConfig stage2ServiceConfig ]);
  initrdServices = with types; attrsOf (submodule [ stage1ServiceOptions unitConfig stage1ServiceConfig ]);

  targets = with types; attrsOf (submodule [ stage2CommonUnitOptions unitConfig ]);
  initrdTargets = with types; attrsOf (submodule [ stage1CommonUnitOptions unitConfig ]);

  sockets = with types; attrsOf (submodule [ stage2SocketOptions unitConfig ]);
  initrdSockets = with types; attrsOf (submodule [ stage1SocketOptions unitConfig ]);

  timers = with types; attrsOf (submodule [ stage2TimerOptions unitConfig ]);
  initrdTimers = with types; attrsOf (submodule [ stage1TimerOptions unitConfig ]);

  paths = with types; attrsOf (submodule [ stage2PathOptions unitConfig ]);
  initrdPaths = with types; attrsOf (submodule [ stage1PathOptions unitConfig ]);

  slices = with types; attrsOf (submodule [ stage2SliceOptions unitConfig ]);
  initrdSlices = with types; attrsOf (submodule [ stage1SliceOptions unitConfig ]);

  mounts = with types; listOf (submodule [ stage2MountOptions unitConfig mountConfig ]);
  initrdMounts = with types; listOf (submodule [ stage1MountOptions unitConfig mountConfig ]);

  automounts = with types; listOf (submodule [ stage2AutomountOptions unitConfig automountConfig ]);
  initrdAutomounts = with types; attrsOf (submodule [ stage1AutomountOptions unitConfig automountConfig ]);
}
+274 −141
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ in rec {

  };

  commonUnitOptions = sharedOptions // {
  commonUnitOptions = { options = (sharedOptions // {

    description = mkOption {
      default = "";
@@ -191,27 +191,6 @@ in rec {
      '';
    };

    restartTriggers = mkOption {
      default = [];
      type = types.listOf types.unspecified;
      description = ''
        An arbitrary list of items such as derivations.  If any item
        in the list changes between reconfigurations, the service will
        be restarted.
      '';
    };

    reloadTriggers = mkOption {
      default = [];
      type = types.listOf unitOption;
      description = ''
        An arbitrary list of items such as derivations.  If any item
        in the list changes between reconfigurations, the service will
        be reloaded.  If anything but a reload trigger changes in the
        unit file, the unit will be restarted instead.
      '';
    };

    onFailure = mkOption {
      default = [];
      type = types.listOf unitNameType;
@@ -239,10 +218,39 @@ in rec {
       '';
    };

  }); };

  stage2CommonUnitOptions = {
    imports = [
      commonUnitOptions
    ];

    options = {
      restartTriggers = mkOption {
        default = [];
        type = types.listOf types.unspecified;
        description = ''
          An arbitrary list of items such as derivations.  If any item
          in the list changes between reconfigurations, the service will
          be restarted.
        '';
      };

      reloadTriggers = mkOption {
        default = [];
        type = types.listOf unitOption;
        description = ''
          An arbitrary list of items such as derivations.  If any item
          in the list changes between reconfigurations, the service will
          be reloaded.  If anything but a reload trigger changes in the
          unit file, the unit will be restarted instead.
        '';
      };
    };
  };
  stage1CommonUnitOptions = commonUnitOptions;

  serviceOptions = commonUnitOptions // {
  serviceOptions = { options = {

    environment = mkOption {
      default = {};
@@ -276,6 +284,15 @@ in rec {
      '';
    };

  }; };

  stage2ServiceOptions = { name, config, ... }: {
    imports = [
      stage2CommonUnitOptions
      serviceOptions
    ];

    options = {
      script = mkOption {
        type = types.lines;
        default = "";
@@ -386,11 +403,45 @@ in rec {
        '';
        apply = v: if isList v then v else [ v ];
      };
    };

    config = mkMerge
      [ (mkIf (config.preStart != "")
          { serviceConfig.ExecStartPre =
              [ (makeJobScript "${name}-pre-start" config.preStart) ];
          })
        (mkIf (config.script != "")
          { serviceConfig.ExecStart =
              makeJobScript "${name}-start" config.script + " " + config.scriptArgs;
          })
        (mkIf (config.postStart != "")
          { serviceConfig.ExecStartPost =
              [ (makeJobScript "${name}-post-start" config.postStart) ];
          })
        (mkIf (config.reload != "")
          { serviceConfig.ExecReload =
              makeJobScript "${name}-reload" config.reload;
          })
        (mkIf (config.preStop != "")
          { serviceConfig.ExecStop =
              makeJobScript "${name}-pre-stop" config.preStop;
          })
        (mkIf (config.postStop != "")
          { serviceConfig.ExecStopPost =
              makeJobScript "${name}-post-stop" config.postStop;
          })
      ];
  };

  stage1ServiceOptions = {
    imports = [
      stage1CommonUnitOptions
      serviceOptions
    ];
  };


  socketOptions = commonUnitOptions // {
  socketOptions = { options = {

    listenStreams = mkOption {
      default = [];
@@ -424,10 +475,24 @@ in rec {
      '';
    };

  }; };

  stage2SocketOptions = {
    imports = [
      stage2CommonUnitOptions
      socketOptions
    ];
  };

  stage1SocketOptions = {
    imports = [
      stage1CommonUnitOptions
      socketOptions
    ];
  };


  timerOptions = commonUnitOptions // {
  timerOptions = { options = {

    timerConfig = mkOption {
      default = {};
@@ -443,10 +508,24 @@ in rec {
      '';
    };

  }; };

  stage2TimerOptions = {
    imports = [
      stage2CommonUnitOptions
      timerOptions
    ];
  };

  stage1TimerOptions = {
    imports = [
      stage1CommonUnitOptions
      timerOptions
    ];
  };


  pathOptions = commonUnitOptions // {
  pathOptions = { options = {

    pathConfig = mkOption {
      default = {};
@@ -460,10 +539,24 @@ in rec {
      '';
    };

  }; };

  stage2PathOptions = {
    imports = [
      stage2CommonUnitOptions
      pathOptions
    ];
  };

  stage1PathOptions = {
    imports = [
      stage1CommonUnitOptions
      pathOptions
    ];
  };


  mountOptions = commonUnitOptions // {
  mountOptions = { options = {

    what = mkOption {
      example = "/dev/sda1";
@@ -505,9 +598,23 @@ in rec {
        <manvolnum>5</manvolnum></citerefentry> for details.
      '';
    };
  }; };

  stage2MountOptions = {
    imports = [
      stage2CommonUnitOptions
      mountOptions
    ];
  };

  stage1MountOptions = {
    imports = [
      stage1CommonUnitOptions
      mountOptions
    ];
  };

  automountOptions = commonUnitOptions // {
  automountOptions = { options = {

    where = mkOption {
      example = "/mnt";
@@ -529,11 +636,23 @@ in rec {
        <manvolnum>5</manvolnum></citerefentry> for details.
      '';
    };
  }; };

  stage2AutomountOptions = {
    imports = [
      stage2CommonUnitOptions
      automountOptions
    ];
  };

  targetOptions = commonUnitOptions;
  stage1AutomountOptions = {
    imports = [
      stage1CommonUnitOptions
      automountOptions
    ];
  };

  sliceOptions = commonUnitOptions // {
  sliceOptions = { options = {

    sliceConfig = mkOption {
      default = {};
@@ -547,6 +666,20 @@ in rec {
      '';
    };

  }; };

  stage2SliceOptions = {
    imports = [
      stage2CommonUnitOptions
      sliceOptions
    ];
  };

  stage1SliceOptions = {
    imports = [
      stage1CommonUnitOptions
      sliceOptions
    ];
  };

}
+1 −0
Original line number Diff line number Diff line
@@ -197,5 +197,6 @@ rec {
  systemdUtils = {
    lib = import ./systemd-lib.nix { inherit lib config pkgs; };
    unitOptions = import ./systemd-unit-options.nix { inherit lib systemdUtils; };
    types = import ./systemd-types.nix { inherit lib systemdUtils; };
  };
}
+26 −14
Original line number Diff line number Diff line
@@ -15,6 +15,26 @@ let
      mapAttrsToList (n: v: ''${n}=${escapeIfNeccessary (toString v)}'') attrs
    );

  osReleaseContents = {
    NAME = "NixOS";
    ID = "nixos";
    VERSION = "${cfg.release} (${cfg.codeName})";
    VERSION_CODENAME = toLower cfg.codeName;
    VERSION_ID = cfg.release;
    BUILD_ID = cfg.version;
    PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})";
    LOGO = "nix-snowflake";
    HOME_URL = "https://nixos.org/";
    DOCUMENTATION_URL = "https://nixos.org/learn.html";
    SUPPORT_URL = "https://nixos.org/community.html";
    BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues";
  };

  initrdReleaseContents = osReleaseContents // {
    PRETTY_NAME = "${osReleaseContents.PRETTY_NAME} (Initrd)";
  };
  initrdRelease = pkgs.writeText "initrd-release" (attrsToText initrdReleaseContents);

in
{
  imports = [
@@ -119,20 +139,12 @@ in
        DISTRIB_DESCRIPTION = "NixOS ${cfg.release} (${cfg.codeName})";
      };

      "os-release".text = attrsToText {
        NAME = "NixOS";
        ID = "nixos";
        VERSION = "${cfg.release} (${cfg.codeName})";
        VERSION_CODENAME = toLower cfg.codeName;
        VERSION_ID = cfg.release;
        BUILD_ID = cfg.version;
        PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})";
        LOGO = "nix-snowflake";
        HOME_URL = "https://nixos.org/";
        DOCUMENTATION_URL = "https://nixos.org/learn.html";
        SUPPORT_URL = "https://nixos.org/community.html";
        BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues";
      "os-release".text = attrsToText osReleaseContents;
    };

    boot.initrd.systemd.contents = {
      "/etc/os-release".source = initrdRelease;
      "/etc/initrd-release".source = initrdRelease;
    };
  };

Loading