diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2023-04-03 14:45:46 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2023-04-24 10:02:30 +0200 |
commit | 8c41640a71fd03e4a2a45a28e311bbfd08e4c49a (patch) | |
tree | 7937691f56b96933f0026edba5d1d70cea7c3211 | |
parent | core/unit: rename UNIT_ESCAPE_EXEC_SYNTAX → *_ENV (diff) | |
download | systemd-8c41640a71fd03e4a2a45a28e311bbfd08e4c49a.tar.xz systemd-8c41640a71fd03e4a2a45a28e311bbfd08e4c49a.zip |
core/unit: add UNIT_ESCAPE_EXEC_SYNTAX
Unfortunately we can't escape $ when ':' is used to prohibit variable expansion:
ExecStart=:echo $$
is not the same as
ExecStart=:echo $
This just adds the functionality and the unittests, without using it anywhere
for real yet.
-rw-r--r-- | src/core/unit.c | 17 | ||||
-rw-r--r-- | src/core/unit.h | 5 | ||||
-rw-r--r-- | src/test/test-core-unit.c | 56 |
3 files changed, 52 insertions, 26 deletions
diff --git a/src/core/unit.c b/src/core/unit.c index a6a0328e4d..6e20e86a63 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -36,6 +36,7 @@ #include "load-dropin.h" #include "load-fragment.h" #include "log.h" +#include "logarithm.h" #include "macro.h" #include "missing_audit.h" #include "mkdir-label.h" @@ -4312,7 +4313,7 @@ static const char* unit_drop_in_dir(Unit *u, UnitWriteFlags flags) { const char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf) { assert(s); - assert(!FLAGS_SET(flags, UNIT_ESCAPE_EXEC_SYNTAX_ENV | UNIT_ESCAPE_C)); + assert(popcount(flags & (UNIT_ESCAPE_EXEC_SYNTAX_ENV | UNIT_ESCAPE_EXEC_SYNTAX | UNIT_ESCAPE_C)) <= 1); assert(buf); _cleanup_free_ char *t = NULL; @@ -4334,15 +4335,17 @@ const char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf) /* We either do C-escaping or shell-escaping, to additionally escape characters that we parse for * ExecStart= and friends, i.e. '$' and quotes. */ - if (flags & UNIT_ESCAPE_EXEC_SYNTAX_ENV) { + if (flags & (UNIT_ESCAPE_EXEC_SYNTAX_ENV | UNIT_ESCAPE_EXEC_SYNTAX)) { char *t2; - t2 = strreplace(s, "$", "$$"); - if (!t2) - return NULL; - free_and_replace(t, t2); + if (flags & UNIT_ESCAPE_EXEC_SYNTAX_ENV) { + t2 = strreplace(s, "$", "$$"); + if (!t2) + return NULL; + free_and_replace(t, t2); + } - t2 = shell_escape(t, "\""); + t2 = shell_escape(t ?: s, "\""); if (!t2) return NULL; free_and_replace(t, t2); diff --git a/src/core/unit.h b/src/core/unit.h index ff29b785bb..06e5237e2c 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -542,8 +542,11 @@ typedef enum UnitWriteFlags { /* Escape elements of ExecStart= syntax, incl. prevention of variable expansion */ UNIT_ESCAPE_EXEC_SYNTAX_ENV = 1 << 4, + /* Escape elements of ExecStart=: syntax (no variable expansion) */ + UNIT_ESCAPE_EXEC_SYNTAX = 1 << 5, + /* Apply C escaping before writing */ - UNIT_ESCAPE_C = 1 << 5, + UNIT_ESCAPE_C = 1 << 6, } UnitWriteFlags; /* Returns true if neither persistent, nor runtime storage is requested, i.e. this is a check invocation only */ diff --git a/src/test/test-core-unit.c b/src/test/test-core-unit.c index 91e6cdd6a3..1a08507d1d 100644 --- a/src/test/test-core-unit.c +++ b/src/test/test-core-unit.c @@ -7,15 +7,18 @@ static void test_unit_escape_setting_one( const char *s, + const char *expected_exec_env, const char *expected_exec, const char *expected_c) { - _cleanup_free_ char *a = NULL, *b, *c, - *s_esc, *a_esc, *b_esc, *c_esc; + _cleanup_free_ char *a = NULL, *b, *c, *d, + *s_esc, *a_esc, *b_esc, *c_esc, *d_esc; const char *t; + if (!expected_exec_env) + expected_exec_env = s; if (!expected_exec) - expected_exec = s; + expected_exec = expected_exec_env; if (!expected_c) expected_c = expected_exec; assert_se(s_esc = cescape(s)); @@ -30,37 +33,46 @@ static void test_unit_escape_setting_one( assert_se(b_esc = cescape(t)); log_debug("%s: [%s] → [%s]", __func__, s_esc, b_esc); assert_se(b == NULL || streq(b, t)); - assert_se(streq(t, expected_exec)); + assert_se(streq(t, expected_exec_env)); - assert_se(t = unit_escape_setting(s, UNIT_ESCAPE_C, &c)); + assert_se(t = unit_escape_setting(s, UNIT_ESCAPE_EXEC_SYNTAX, &c)); assert_se(c_esc = cescape(t)); log_debug("%s: [%s] → [%s]", __func__, s_esc, c_esc); assert_se(c == NULL || streq(c, t)); + assert_se(streq(t, expected_exec)); + + assert_se(t = unit_escape_setting(s, UNIT_ESCAPE_C, &d)); + assert_se(d_esc = cescape(t)); + log_debug("%s: [%s] → [%s]", __func__, s_esc, d_esc); + assert_se(d == NULL || streq(d, t)); assert_se(streq(t, expected_c)); } TEST(unit_escape_setting) { - test_unit_escape_setting_one("/sbin/sbash", NULL, NULL); - test_unit_escape_setting_one("$", "$$", "$"); - test_unit_escape_setting_one("$$", "$$$$", "$$"); - test_unit_escape_setting_one("'", "'", "\\'"); - test_unit_escape_setting_one("\"", "\\\"", NULL); - test_unit_escape_setting_one("\t", "\\t", NULL); - test_unit_escape_setting_one(" ", NULL, NULL); - test_unit_escape_setting_one("$;'\"\t\n", "$$;'\\\"\\t\\n", "$;\\'\\\"\\t\\n"); + test_unit_escape_setting_one("/sbin/sbash", NULL, NULL, NULL); + test_unit_escape_setting_one("$", "$$", "$", "$"); + test_unit_escape_setting_one("$$", "$$$$", "$$", "$$"); + test_unit_escape_setting_one("'", "'", NULL, "\\'"); + test_unit_escape_setting_one("\"", "\\\"", NULL, NULL); + test_unit_escape_setting_one("\t", "\\t", NULL, NULL); + test_unit_escape_setting_one(" ", NULL, NULL, NULL); + test_unit_escape_setting_one("$;'\"\t\n", "$$;'\\\"\\t\\n", "$;'\\\"\\t\\n", "$;\\'\\\"\\t\\n"); } static void test_unit_concat_strv_one( char **s, const char *expected_none, + const char *expected_exec_env, const char *expected_exec, const char *expected_c) { - _cleanup_free_ char *a, *b, *c, - *s_ser, *s_esc, *a_esc, *b_esc, *c_esc; + _cleanup_free_ char *a, *b, *c, *d, + *s_ser, *s_esc, *a_esc, *b_esc, *c_esc, *d_esc; assert_se(s_ser = strv_join(s, "_")); assert_se(s_esc = cescape(s_ser)); + if (!expected_exec_env) + expected_exec_env = expected_none; if (!expected_exec) expected_exec = expected_none; if (!expected_c) @@ -74,26 +86,34 @@ static void test_unit_concat_strv_one( assert_se(b = unit_concat_strv(s, UNIT_ESCAPE_EXEC_SYNTAX_ENV)); assert_se(b_esc = cescape(b)); log_debug("%s: [%s] → [%s]", __func__, s_esc, b_esc); - assert_se(streq(b, expected_exec)); + assert_se(streq(b, expected_exec_env)); - assert_se(c = unit_concat_strv(s, UNIT_ESCAPE_C)); + assert_se(c = unit_concat_strv(s, UNIT_ESCAPE_EXEC_SYNTAX)); assert_se(c_esc = cescape(c)); log_debug("%s: [%s] → [%s]", __func__, s_esc, c_esc); - assert_se(streq(c, expected_c)); + assert_se(streq(c, expected_exec)); + + assert_se(d = unit_concat_strv(s, UNIT_ESCAPE_C)); + assert_se(d_esc = cescape(d)); + log_debug("%s: [%s] → [%s]", __func__, s_esc, d_esc); + assert_se(streq(d, expected_c)); } TEST(unit_concat_strv) { test_unit_concat_strv_one(STRV_MAKE("a", "b", "c"), "\"a\" \"b\" \"c\"", NULL, + NULL, NULL); test_unit_concat_strv_one(STRV_MAKE("a", " ", "$", "$$", ""), "\"a\" \" \" \"$\" \"$$\" \"\"", "\"a\" \" \" \"$$\" \"$$$$\" \"\"", + NULL, NULL); test_unit_concat_strv_one(STRV_MAKE("\n", " ", "\t"), "\"\n\" \" \" \"\t\"", "\"\\n\" \" \" \"\\t\"", + "\"\\n\" \" \" \"\\t\"", "\"\\n\" \" \" \"\\t\""); } |