Commit 121c0d9e authored by Robert Hensing's avatar Robert Hensing
Browse files

systemd: Add functions.escapeSystemdExecArg[s]

This makes it available outside the NixOS `utils` context.
parent 2cf55f4c
Loading
Loading
Loading
Loading
+1 −25
Original line number Diff line number Diff line
@@ -119,31 +119,7 @@ let
        )
      );

    # Quotes an argument for use in Exec* service lines.
    # systemd accepts "-quoted strings with escape sequences, toJSON produces
    # a subset of these.
    # Additionally we escape % to disallow expansion of % specifiers. Any lone ;
    # in the input will be turned it ";" and thus lose its special meaning.
    # Every $ is escaped to $$, this makes it unnecessary to disable environment
    # substitution for the directive.
    escapeSystemdExecArg =
      arg:
      let
        s =
          if isPath arg then
            "${arg}"
          else if isString arg then
            arg
          else if isInt arg || isFloat arg || isDerivation arg then
            toString arg
          else
            throw "escapeSystemdExecArg only allows strings, paths, numbers and derivations";
      in
      replaceStrings [ "%" "$" ] [ "%%" "$$" ] (toJSON s);

    # Quotes a list of arguments into a single string for use in a Exec*
    # line.
    escapeSystemdExecArgs = concatMapStringsSep " " escapeSystemdExecArg;
    inherit (config.systemd.package.functions) escapeSystemdExecArg escapeSystemdExecArgs;

    # Returns a system path for a given shell package
    toShellPath =
+11 −0
Original line number Diff line number Diff line
@@ -897,6 +897,11 @@ stdenv.mkDerivation (finalAttrs: {
    # needed - and therefore `interfaceVersion` should be incremented.
    interfaceVersion = 2;

    functions = import ./functions/default.nix {
      inherit lib;
      systemd = finalAttrs.finalPackage;
    };

    inherit
      withBootloader
      withCryptsetup
@@ -1022,6 +1027,12 @@ stdenv.mkDerivation (finalAttrs: {
          pkgsCross.${systemString}.systemd;

        pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;

        functions = import ./functions/test.nix {
          inherit lib;
          systemd = finalAttrs.finalPackage;
          ok = buildPackages.emptyFile;
        };
      };
  };

+55 −0
Original line number Diff line number Diff line
/**
  Build the `systemd.functions` library (where `systemd` is the package)
*/
{ lib, systemd }:
let
  inherit (lib)
    concatMapStringsSep
    isDerivation
    isFloat
    isInt
    isPath
    isString
    replaceStrings
    ;
  inherit (builtins)
    toJSON
    ;

  /**
    Quotes an argument for use in `Exec*` service lines.
    Additionally we escape `%` to disallow expansion of `%` specifiers. Any lone `;`
    in the input will be turned into `";"` and thus lose its special meaning.
    Every `$` is escaped to `$$`, this makes it unnecessary to disable environment
    substitution for the directive.
  */
  escapeSystemdExecArg =
    arg:
    let
      s =
        if isPath arg then
          "${arg}"
        else if isString arg then
          arg
        else if isInt arg || isFloat arg || isDerivation arg then
          toString arg
        else
          throw "escapeSystemdExecArg only allows strings, paths, numbers and derivations";
    in
    # systemd accepts "-quoted strings with escape sequences, toJSON produces
    # a subset of these.
    replaceStrings [ "%" "$" ] [ "%%" "$$" ] (toJSON s);

  /**
    Quotes a list of arguments into a single string for use in a Exec* line.
  */
  escapeSystemdExecArgs = concatMapStringsSep " " escapeSystemdExecArg;
in
# Instead of requiring v2, we can make this library conditional on the version as needed.
assert systemd.interfaceVersion == 2;
{
  inherit
    escapeSystemdExecArg
    escapeSystemdExecArgs
    ;
}
+23 −0
Original line number Diff line number Diff line
{
  lib,
  systemd,
  ok,
}:

# This function is also tested in nixosTests.systemd-escaping
assert systemd.functions.escapeSystemdExecArg "hi" == ''"hi"'';
assert systemd.functions.escapeSystemdExecArg "hi there" == ''"hi there"'';
assert systemd.functions.escapeSystemdExecArg ''"hi there"'' == ''"\"hi there\""'';
assert systemd.functions.escapeSystemdExecArg ''"%$'' == ''"\"%%$$"'';
assert
  systemd.functions.escapeSystemdExecArgs [
    "hi"
    "there"
  ] == ''"hi" "there"'';
assert
  systemd.functions.escapeSystemdExecArgs [
    "hi"
    "%"
    "there"
  ] == ''"hi" "%%" "there"'';
ok