diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix index 251e0460dd03..f0af7b30dec6 100644 --- a/nixos/lib/utils.nix +++ b/nixos/lib/utils.nix @@ -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 = diff --git a/pkgs/os-specific/linux/systemd/default.nix b/pkgs/os-specific/linux/systemd/default.nix index 10808bda7b27..bf0ae846cac2 100644 --- a/pkgs/os-specific/linux/systemd/default.nix +++ b/pkgs/os-specific/linux/systemd/default.nix @@ -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; + }; }; }; diff --git a/pkgs/os-specific/linux/systemd/functions/default.nix b/pkgs/os-specific/linux/systemd/functions/default.nix new file mode 100644 index 000000000000..a61670c1c9e5 --- /dev/null +++ b/pkgs/os-specific/linux/systemd/functions/default.nix @@ -0,0 +1,55 @@ +/** + 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 + ; +} diff --git a/pkgs/os-specific/linux/systemd/functions/test.nix b/pkgs/os-specific/linux/systemd/functions/test.nix new file mode 100644 index 000000000000..236c18545cb0 --- /dev/null +++ b/pkgs/os-specific/linux/systemd/functions/test.nix @@ -0,0 +1,23 @@ +{ + 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