forked from mirrors/nixpkgs
Merge pull request #177273 from dali99/escape-systemd
Make escapeSystemdPath implement the correct systemd escaping algorithm
This commit is contained in:
commit
91a3819bad
96
lib/ascii-table.nix
Normal file
96
lib/ascii-table.nix
Normal file
|
@ -0,0 +1,96 @@
|
|||
{ " " = 32;
|
||||
"!" = 33;
|
||||
"\"" = 34;
|
||||
"#" = 35;
|
||||
"$" = 36;
|
||||
"%" = 37;
|
||||
"&" = 38;
|
||||
"'" = 39;
|
||||
"(" = 40;
|
||||
")" = 41;
|
||||
"*" = 42;
|
||||
"+" = 43;
|
||||
"," = 44;
|
||||
"-" = 45;
|
||||
"." = 46;
|
||||
"/" = 47;
|
||||
"0" = 48;
|
||||
"1" = 49;
|
||||
"2" = 50;
|
||||
"3" = 51;
|
||||
"4" = 52;
|
||||
"5" = 53;
|
||||
"6" = 54;
|
||||
"7" = 55;
|
||||
"8" = 56;
|
||||
"9" = 57;
|
||||
":" = 58;
|
||||
";" = 59;
|
||||
"<" = 60;
|
||||
"=" = 61;
|
||||
">" = 62;
|
||||
"?" = 63;
|
||||
"@" = 64;
|
||||
"A" = 65;
|
||||
"B" = 66;
|
||||
"C" = 67;
|
||||
"D" = 68;
|
||||
"E" = 69;
|
||||
"F" = 70;
|
||||
"G" = 71;
|
||||
"H" = 72;
|
||||
"I" = 73;
|
||||
"J" = 74;
|
||||
"K" = 75;
|
||||
"L" = 76;
|
||||
"M" = 77;
|
||||
"N" = 78;
|
||||
"O" = 79;
|
||||
"P" = 80;
|
||||
"Q" = 81;
|
||||
"R" = 82;
|
||||
"S" = 83;
|
||||
"T" = 84;
|
||||
"U" = 85;
|
||||
"V" = 86;
|
||||
"W" = 87;
|
||||
"X" = 88;
|
||||
"Y" = 89;
|
||||
"Z" = 90;
|
||||
"[" = 91;
|
||||
"\\" = 92;
|
||||
"]" = 93;
|
||||
"^" = 94;
|
||||
"_" = 95;
|
||||
"`" = 96;
|
||||
"a" = 97;
|
||||
"b" = 98;
|
||||
"c" = 99;
|
||||
"d" = 100;
|
||||
"e" = 101;
|
||||
"f" = 102;
|
||||
"g" = 103;
|
||||
"h" = 104;
|
||||
"i" = 105;
|
||||
"j" = 106;
|
||||
"k" = 107;
|
||||
"l" = 108;
|
||||
"m" = 109;
|
||||
"n" = 110;
|
||||
"o" = 111;
|
||||
"p" = 112;
|
||||
"q" = 113;
|
||||
"r" = 114;
|
||||
"s" = 115;
|
||||
"t" = 116;
|
||||
"u" = 117;
|
||||
"v" = 118;
|
||||
"w" = 119;
|
||||
"x" = 120;
|
||||
"y" = 121;
|
||||
"z" = 122;
|
||||
"{" = 123;
|
||||
"|" = 124;
|
||||
"}" = 125;
|
||||
"~" = 126;
|
||||
}
|
|
@ -185,6 +185,16 @@ rec {
|
|||
*/
|
||||
makeBinPath = makeSearchPathOutput "bin" "bin";
|
||||
|
||||
/* Normalize path, removing extranous /s
|
||||
|
||||
Type: normalizePath :: string -> string
|
||||
|
||||
Example:
|
||||
normalizePath "/a//b///c/"
|
||||
=> "/a/b/c/"
|
||||
*/
|
||||
normalizePath = s: (builtins.foldl' (x: y: if y == "/" && hasSuffix "/" x then x else x+y) "" (splitString "" s));
|
||||
|
||||
/* Depending on the boolean `cond', return either the given string
|
||||
or the empty string. Useful to concatenate against a bigger string.
|
||||
|
||||
|
@ -294,6 +304,21 @@ rec {
|
|||
map f (stringToCharacters s)
|
||||
);
|
||||
|
||||
/* Convert char to ascii value, must be in printable range
|
||||
|
||||
Type: charToInt :: string -> int
|
||||
|
||||
Example:
|
||||
charToInt "A"
|
||||
=> 65
|
||||
charToInt "("
|
||||
=> 40
|
||||
|
||||
*/
|
||||
charToInt = let
|
||||
table = import ./ascii-table.nix;
|
||||
in c: builtins.getAttr c table;
|
||||
|
||||
/* Escape occurrence of the elements of `list` in `string` by
|
||||
prefixing it with a backslash.
|
||||
|
||||
|
@ -305,6 +330,19 @@ rec {
|
|||
*/
|
||||
escape = list: replaceChars list (map (c: "\\${c}") list);
|
||||
|
||||
/* Escape occurence of the element of `list` in `string` by
|
||||
converting to its ASCII value and prefixing it with \\x.
|
||||
Only works for printable ascii characters.
|
||||
|
||||
Type: escapeC = [string] -> string -> string
|
||||
|
||||
Example:
|
||||
escapeC [" "] "foo bar"
|
||||
=> "foo\\x20bar"
|
||||
|
||||
*/
|
||||
escapeC = list: replaceChars list (map (c: "\\x${ toLower (lib.toHexString (charToInt c))}") list);
|
||||
|
||||
/* Quote string to be used safely within the Bourne shell.
|
||||
|
||||
Type: escapeShellArg :: string -> string
|
||||
|
|
|
@ -312,6 +312,21 @@ runTests {
|
|||
expected = true;
|
||||
};
|
||||
|
||||
testNormalizePath = {
|
||||
expr = strings.normalizePath "//a/b//c////d/";
|
||||
expected = "/a/b/c/d/";
|
||||
};
|
||||
|
||||
testCharToInt = {
|
||||
expr = strings.charToInt "A";
|
||||
expected = 65;
|
||||
};
|
||||
|
||||
testEscapeC = {
|
||||
expr = strings.escapeC [ " " ] "Hello World";
|
||||
expected = "Hello\\x20World";
|
||||
};
|
||||
|
||||
# LISTS
|
||||
|
||||
testFilter = {
|
||||
|
|
|
@ -39,11 +39,19 @@ rec {
|
|||
|| hasPrefix a'.mountPoint b'.mountPoint
|
||||
|| any (hasPrefix a'.mountPoint) b'.depends;
|
||||
|
||||
# Escape a path according to the systemd rules, e.g. /dev/xyzzy
|
||||
# becomes dev-xyzzy. FIXME: slow.
|
||||
escapeSystemdPath = s:
|
||||
replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"]
|
||||
(removePrefix "/" s);
|
||||
# Escape a path according to the systemd rules. FIXME: slow
|
||||
# The rules are described in systemd.unit(5) as follows:
|
||||
# The escaping algorithm operates as follows: given a string, any "/" character is replaced by "-", and all other characters which are not ASCII alphanumerics, ":", "_" or "." are replaced by C-style "\x2d" escapes. In addition, "." is replaced with such a C-style escape when it would appear as the first character in the escaped string.
|
||||
# When the input qualifies as absolute file system path, this algorithm is extended slightly: the path to the root directory "/" is encoded as single dash "-". In addition, any leading, trailing or duplicate "/" characters are removed from the string before transformation. Example: /foo//bar/baz/ becomes "foo-bar-baz".
|
||||
escapeSystemdPath = s: let
|
||||
replacePrefix = p: r: s: (if (hasPrefix p s) then r + (removePrefix p s) else s);
|
||||
trim = s: removeSuffix "/" (removePrefix "/" s);
|
||||
normalizedPath = strings.normalizePath s;
|
||||
in
|
||||
replaceChars ["/"] ["-"]
|
||||
(replacePrefix "." (strings.escapeC ["."] ".")
|
||||
(strings.escapeC (stringToCharacters " !\"#$%&'()*+,;<=>=@[\\]^`{|}~-")
|
||||
(if normalizedPath == "/" then normalizedPath else trim normalizedPath)));
|
||||
|
||||
# Quotes an argument for use in Exec* service lines.
|
||||
# systemd accepts "-quoted strings with escape sequences, toJSON produces
|
||||
|
|
Loading…
Reference in a new issue