mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #44 from filbranden/unquote_first_word1
Replace FOREACH_WORD_QUOTED with a loop using unquote_first_word in config_parse_exec()
This commit is contained in:
commit
7391cb5d58
125
src/basic/util.c
125
src/basic/util.c
@ -5209,35 +5209,6 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
|
||||
break;
|
||||
|
||||
case VALUE_ESCAPE:
|
||||
if (c == 0) {
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
goto finish;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+7))
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags & UNQUOTE_CUNESCAPE) {
|
||||
uint32_t u;
|
||||
|
||||
r = cunescape_one(*p, (size_t) -1, &c, &u);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
(*p) += r - 1;
|
||||
|
||||
if (c != 0)
|
||||
s[sz++] = c; /* normal explicit char */
|
||||
else
|
||||
sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
|
||||
} else
|
||||
s[sz++] = c;
|
||||
|
||||
state = VALUE;
|
||||
break;
|
||||
|
||||
case SINGLE_QUOTE:
|
||||
if (c == 0) {
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
@ -5256,35 +5227,6 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
|
||||
break;
|
||||
|
||||
case SINGLE_QUOTE_ESCAPE:
|
||||
if (c == 0) {
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
goto finish;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+7))
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags & UNQUOTE_CUNESCAPE) {
|
||||
uint32_t u;
|
||||
|
||||
r = cunescape_one(*p, (size_t) -1, &c, &u);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
(*p) += r - 1;
|
||||
|
||||
if (c != 0)
|
||||
s[sz++] = c;
|
||||
else
|
||||
sz += utf8_encode_unichar(s + sz, u);
|
||||
} else
|
||||
s[sz++] = c;
|
||||
|
||||
state = SINGLE_QUOTE;
|
||||
break;
|
||||
|
||||
case DOUBLE_QUOTE:
|
||||
if (c == 0)
|
||||
return -EINVAL;
|
||||
@ -5301,33 +5243,56 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
|
||||
break;
|
||||
|
||||
case SINGLE_QUOTE_ESCAPE:
|
||||
case DOUBLE_QUOTE_ESCAPE:
|
||||
case VALUE_ESCAPE:
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+7))
|
||||
return -ENOMEM;
|
||||
|
||||
if (c == 0) {
|
||||
if ((flags & UNQUOTE_CUNESCAPE_RELAX) &&
|
||||
(state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) {
|
||||
/* If we find an unquoted trailing backslash and we're in
|
||||
* UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the
|
||||
* output.
|
||||
*
|
||||
* Unbalanced quotes will only be allowed in UNQUOTE_RELAX
|
||||
* mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them.
|
||||
*/
|
||||
s[sz++] = '\\';
|
||||
goto finish;
|
||||
}
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
goto finish;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+7))
|
||||
return -ENOMEM;
|
||||
|
||||
if (flags & UNQUOTE_CUNESCAPE) {
|
||||
uint32_t u;
|
||||
|
||||
r = cunescape_one(*p, (size_t) -1, &c, &u);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
if (flags & UNQUOTE_CUNESCAPE_RELAX) {
|
||||
s[sz++] = '\\';
|
||||
s[sz++] = c;
|
||||
goto end_escape;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
(*p) += r - 1;
|
||||
|
||||
if (c != 0)
|
||||
s[sz++] = c;
|
||||
s[sz++] = c; /* normal explicit char */
|
||||
else
|
||||
sz += utf8_encode_unichar(s + sz, u);
|
||||
sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
|
||||
} else
|
||||
s[sz++] = c;
|
||||
|
||||
state = DOUBLE_QUOTE;
|
||||
end_escape:
|
||||
state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE :
|
||||
(state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE :
|
||||
VALUE;
|
||||
break;
|
||||
|
||||
case SPACE:
|
||||
@ -5355,6 +5320,36 @@ finish:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unquote_first_word_and_warn(
|
||||
const char **p,
|
||||
char **ret,
|
||||
UnquoteFlags flags,
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *rvalue) {
|
||||
/* Try to unquote it, if it fails, warn about it and try again but this
|
||||
* time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim
|
||||
* in invalid escape sequences. */
|
||||
const char *save;
|
||||
int r;
|
||||
|
||||
save = *p;
|
||||
r = unquote_first_word(p, ret, flags);
|
||||
if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) {
|
||||
/* Retry it with UNQUOTE_CUNESCAPE_RELAX. */
|
||||
*p = save;
|
||||
r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
|
||||
else
|
||||
log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
|
||||
"Invalid escape sequences in command line: \"%s\"", rvalue);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
|
||||
va_list ap;
|
||||
char **l;
|
||||
|
@ -839,11 +839,13 @@ int is_dir(const char *path, bool follow);
|
||||
int is_device_node(const char *path);
|
||||
|
||||
typedef enum UnquoteFlags {
|
||||
UNQUOTE_RELAX = 1,
|
||||
UNQUOTE_CUNESCAPE = 2,
|
||||
UNQUOTE_RELAX = 1,
|
||||
UNQUOTE_CUNESCAPE = 2,
|
||||
UNQUOTE_CUNESCAPE_RELAX = 4,
|
||||
} UnquoteFlags;
|
||||
|
||||
int unquote_first_word(const char **p, char **ret, UnquoteFlags flags);
|
||||
int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
|
||||
int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_;
|
||||
|
||||
int free_and_strdup(char **p, const char *s);
|
||||
|
@ -520,9 +520,9 @@ int config_parse_exec(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
ExecCommand **e = data, *nce;
|
||||
char *path, **n;
|
||||
unsigned k;
|
||||
ExecCommand **e = data;
|
||||
const char *p;
|
||||
bool semicolon;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
@ -532,156 +532,154 @@ int config_parse_exec(
|
||||
|
||||
e += ltype;
|
||||
|
||||
rvalue += strspn(rvalue, WHITESPACE);
|
||||
p = rvalue;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
/* An empty assignment resets the list */
|
||||
*e = exec_command_free_list(*e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We accept an absolute path as first argument, or
|
||||
* alternatively an absolute prefixed with @ to allow
|
||||
* overriding of argv[0]. */
|
||||
for (;;) {
|
||||
do {
|
||||
int i;
|
||||
const char *word, *state, *reason;
|
||||
size_t l;
|
||||
_cleanup_strv_free_ char **n = NULL;
|
||||
size_t nlen = 0, nbufsize = 0;
|
||||
_cleanup_free_ ExecCommand *nce = NULL;
|
||||
_cleanup_free_ char *path = NULL, *firstword = NULL;
|
||||
char *f;
|
||||
bool separate_argv0 = false, ignore = false;
|
||||
|
||||
path = NULL;
|
||||
nce = NULL;
|
||||
n = NULL;
|
||||
semicolon = false;
|
||||
|
||||
rvalue += strspn(rvalue, WHITESPACE);
|
||||
r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
|
||||
if (r <= 0)
|
||||
return 0;
|
||||
|
||||
if (rvalue[0] == 0)
|
||||
break;
|
||||
|
||||
k = 0;
|
||||
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
|
||||
if (k == 0) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (*word == '-' && !ignore) {
|
||||
ignore = true;
|
||||
word ++;
|
||||
}
|
||||
|
||||
if (*word == '@' && !separate_argv0) {
|
||||
separate_argv0 = true;
|
||||
word ++;
|
||||
}
|
||||
}
|
||||
} else if (strneq(word, ";", MAX(l, 1U)))
|
||||
goto found;
|
||||
|
||||
k++;
|
||||
f = firstword;
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* We accept an absolute path as first argument, or
|
||||
* alternatively an absolute prefixed with @ to allow
|
||||
* overriding of argv[0]. */
|
||||
if (*f == '-' && !ignore)
|
||||
ignore = true;
|
||||
else if (*f == '@' && !separate_argv0)
|
||||
separate_argv0 = true;
|
||||
else
|
||||
break;
|
||||
f ++;
|
||||
}
|
||||
if (!isempty(state)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
|
||||
|
||||
if (isempty(f)) {
|
||||
/* First word is either "-" or "@" with no command. */
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Empty path in command line, ignoring: \"%s\"", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
found:
|
||||
/* If separate_argv0, we'll move first element to path variable */
|
||||
n = new(char*, MAX(k + !separate_argv0, 1u));
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
k = 0;
|
||||
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
|
||||
char *c;
|
||||
unsigned skip;
|
||||
|
||||
if (separate_argv0 ? path == NULL : k == 0) {
|
||||
/* first word, very special */
|
||||
skip = separate_argv0 + ignore;
|
||||
|
||||
/* skip special chars in the beginning */
|
||||
if (l <= skip) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Empty path in command line, ignoring: \"%s\"", rvalue);
|
||||
r = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
} else if (strneq(word, ";", MAX(l, 1U)))
|
||||
/* new commandline */
|
||||
break;
|
||||
|
||||
else
|
||||
skip = strneq(word, "\\;", MAX(l, 1U));
|
||||
|
||||
r = cunescape_length(word + skip, l - skip, UNESCAPE_RELAX, &c);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to unescape command line, ignoring: %s", rvalue);
|
||||
r = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!utf8_is_valid(c)) {
|
||||
log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
|
||||
r = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* where to stuff this? */
|
||||
if (separate_argv0 && path == NULL)
|
||||
path = c;
|
||||
else
|
||||
n[k++] = c;
|
||||
if (!string_is_safe(f)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Executable path contains special characters, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (!path_is_absolute(f)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Executable path is not absolute, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (endswith(f, "/")) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Executable path specifies a directory, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n[k] = NULL;
|
||||
if (f == firstword) {
|
||||
path = firstword;
|
||||
firstword = NULL;
|
||||
} else {
|
||||
path = strdup(f);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (!n[0])
|
||||
reason = "Empty executable name or zeroeth argument";
|
||||
else if (!string_is_safe(path ?: n[0]))
|
||||
reason = "Executable path contains special characters";
|
||||
else if (!path_is_absolute(path ?: n[0]))
|
||||
reason = "Executable path is not absolute";
|
||||
else if (endswith(path ?: n[0], "/"))
|
||||
reason = "Executable path specifies a directory";
|
||||
else
|
||||
goto ok;
|
||||
if (!separate_argv0) {
|
||||
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
|
||||
return log_oom();
|
||||
f = strdup(path);
|
||||
if (!f)
|
||||
return log_oom();
|
||||
n[nlen++] = f;
|
||||
n[nlen] = NULL;
|
||||
}
|
||||
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "%s, ignoring: %s", reason, rvalue);
|
||||
r = 0;
|
||||
goto fail;
|
||||
path_kill_slashes(path);
|
||||
|
||||
ok:
|
||||
if (!path) {
|
||||
path = strdup(n[0]);
|
||||
if (!path) {
|
||||
r = log_oom();
|
||||
goto fail;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
/* Check explicitly for an unquoted semicolon as
|
||||
* command separator token. */
|
||||
if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
|
||||
p ++;
|
||||
p += strspn(p, WHITESPACE);
|
||||
semicolon = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for \; explicitly, to not confuse it with \\;
|
||||
* or "\;" or "\\;" etc. unquote_first_word would
|
||||
* return the same for all of those. */
|
||||
if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
|
||||
p += 2;
|
||||
p += strspn(p, WHITESPACE);
|
||||
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
|
||||
return log_oom();
|
||||
f = strdup(";");
|
||||
if (!f)
|
||||
return log_oom();
|
||||
n[nlen++] = f;
|
||||
n[nlen] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
|
||||
if (r == 0)
|
||||
break;
|
||||
else if (r < 0)
|
||||
return 0;
|
||||
|
||||
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
|
||||
return log_oom();
|
||||
n[nlen++] = word;
|
||||
n[nlen] = NULL;
|
||||
word = NULL;
|
||||
}
|
||||
|
||||
if (!n || !n[0]) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Empty executable name or zeroeth argument, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nce = new0(ExecCommand, 1);
|
||||
if (!nce) {
|
||||
r = log_oom();
|
||||
goto fail;
|
||||
}
|
||||
if (!nce)
|
||||
return log_oom();
|
||||
|
||||
nce->argv = n;
|
||||
nce->path = path;
|
||||
nce->ignore = ignore;
|
||||
|
||||
path_kill_slashes(nce->path);
|
||||
|
||||
exec_command_append_list(e, nce);
|
||||
|
||||
rvalue = state;
|
||||
}
|
||||
/* Do not _cleanup_free_ these. */
|
||||
n = NULL;
|
||||
path = NULL;
|
||||
nce = NULL;
|
||||
|
||||
rvalue = p;
|
||||
} while (semicolon);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
n[k] = NULL;
|
||||
strv_free(n);
|
||||
free(path);
|
||||
free(nce);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
|
||||
|
@ -145,19 +145,19 @@ static void test_config_parse_exec(void) {
|
||||
assert_se(r == 0);
|
||||
assert_se(c1->command_next == NULL);
|
||||
|
||||
log_info("/* no command, check for bad memory access */");
|
||||
log_info("/* no command, whitespace only, reset */");
|
||||
r = config_parse_exec(NULL, "fake", 3, "section", 1,
|
||||
"LValue", 0, " ",
|
||||
&c, NULL);
|
||||
assert_se(r == 0);
|
||||
assert_se(c1->command_next == NULL);
|
||||
assert_se(c == NULL);
|
||||
|
||||
log_info("/* ignore && honour_argv0 */");
|
||||
r = config_parse_exec(NULL, "fake", 4, "section", 1,
|
||||
"LValue", 0, "-@/RValue///slashes3 argv0a r1",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
c1 = c;
|
||||
check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true);
|
||||
|
||||
log_info("/* ignore && honour_argv0 */");
|
||||
@ -195,6 +195,19 @@ static void test_config_parse_exec(void) {
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false);
|
||||
|
||||
log_info("/* two semicolons in a row */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"-@/RValue argv0 r1 ; ; "
|
||||
"/goo/goo boo",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
|
||||
|
||||
/* second command fails because the executable name is ";" */
|
||||
assert_se(c1->command_next == NULL);
|
||||
|
||||
log_info("/* trailing semicolon */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
@ -206,6 +219,26 @@ static void test_config_parse_exec(void) {
|
||||
|
||||
assert_se(c1->command_next == NULL);
|
||||
|
||||
log_info("/* trailing semicolon, no whitespace */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"-@/RValue argv0 r1 ;",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true);
|
||||
|
||||
assert_se(c1->command_next == NULL);
|
||||
|
||||
log_info("/* trailing semicolon in single quotes */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"-@/RValue argv0 r1 ';'",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1, "/RValue", "argv0", "r1", ";", true);
|
||||
|
||||
log_info("/* escaped semicolon */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
@ -218,12 +251,22 @@ static void test_config_parse_exec(void) {
|
||||
log_info("/* escaped semicolon with following arg */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"/sbin/find \\; x",
|
||||
"/sbin/find \\; /x",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1,
|
||||
"/sbin/find", NULL, ";", "x", false);
|
||||
"/sbin/find", NULL, ";", "/x", false);
|
||||
|
||||
log_info("/* escaped semicolon as part of an expression */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"/sbin/find \\;x",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1,
|
||||
"/sbin/find", NULL, "\\;x", NULL, false);
|
||||
|
||||
log_info("/* encoded semicolon */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
@ -234,6 +277,25 @@ static void test_config_parse_exec(void) {
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
|
||||
|
||||
log_info("/* quoted semicolon */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"/bin/find \";\"",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
|
||||
|
||||
log_info("/* quoted semicolon with following arg */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
"/sbin/find \";\" /x",
|
||||
&c, NULL);
|
||||
assert_se(r >= 0);
|
||||
c1 = c1->command_next;
|
||||
check_execcommand(c1,
|
||||
"/sbin/find", NULL, ";", "/x", false);
|
||||
|
||||
log_info("/* spaces in the filename */");
|
||||
r = config_parse_exec(NULL, "fake", 5, "section", 1,
|
||||
"LValue", 0,
|
||||
|
@ -1304,6 +1304,244 @@ static void test_unquote_first_word(void) {
|
||||
assert_se(streq(t, "pi\360\237\222\251le"));
|
||||
free(t);
|
||||
assert_se(p == original + 32);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "foo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "foo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\ bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "\\w+@\\K[\\d.]+";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL);
|
||||
assert_se(p == original + 1);
|
||||
|
||||
p = original = "\\w+@\\K[\\d.]+";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
|
||||
p = original = "\\w+\\b";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "\\w+\b"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
}
|
||||
|
||||
static void test_unquote_first_word_and_warn(void) {
|
||||
const char *p, *original;
|
||||
char *t;
|
||||
|
||||
p = original = "foobar waldo";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foobar"));
|
||||
free(t);
|
||||
assert_se(p == original + 7);
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(p == original + 12);
|
||||
|
||||
p = original = "\"foobar\" \'waldo\'";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foobar"));
|
||||
free(t);
|
||||
assert_se(p == original + 9);
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 16);
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(p == original + 16);
|
||||
|
||||
p = original = "\"";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
|
||||
assert_se(p == original + 1);
|
||||
|
||||
p = original = "\'";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
|
||||
assert_se(p == original + 1);
|
||||
|
||||
p = original = "\'fooo";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\'fooo";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = " foo\\ba\\x6ar ";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foo\ba\x6ar"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
|
||||
p = original = " foo\\ba\\x6ar ";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foobax6ar"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
|
||||
p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "föo"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "pi\360\237\222\251le"));
|
||||
free(t);
|
||||
assert_se(p == original + 32);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo\\ bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "\\w+@\\K[\\d.]+";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
|
||||
p = original = "\\w+\\b";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "\\w+\b"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
}
|
||||
|
||||
static void test_unquote_many_words(void) {
|
||||
@ -1610,6 +1848,7 @@ int main(int argc, char *argv[]) {
|
||||
test_glob_exists();
|
||||
test_execute_directory();
|
||||
test_unquote_first_word();
|
||||
test_unquote_first_word_and_warn();
|
||||
test_unquote_many_words();
|
||||
test_parse_proc_cmdline();
|
||||
test_raw_clone();
|
||||
|
Loading…
Reference in New Issue
Block a user