mirror of
https://github.com/systemd/systemd.git
synced 2024-12-26 03:22:00 +03:00
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.
This commit is contained in:
parent
f3af629050
commit
8c41640a71
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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\"");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user