mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
Merge pull request #908 from richardmaw-codethink/nspawn-path-escapes-v3
Allow arbitrary file paths to be passed to nspawn (v3)
This commit is contained in:
commit
0038aed166
6
TODO
6
TODO
@ -6,7 +6,7 @@ Bugfixes:
|
||||
automount points even when the original .automount file did not exist
|
||||
anymore. Only the .mount unit was still around.
|
||||
|
||||
* ExecStart with unicode characters fails in strv_split_quoted:
|
||||
* ExecStart with unicode characters fails in strv_split_extract:
|
||||
|
||||
[Service]
|
||||
Environment=ONE='one' "TWO='two two' too" THREE=
|
||||
@ -273,7 +273,7 @@ Features:
|
||||
|
||||
* maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment=
|
||||
|
||||
* code cleanup: retire FOREACH_WORD_QUOTED, port to unquote_first_word() loops instead
|
||||
* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead
|
||||
|
||||
* introduce systemd-timesync-wait.service or so to sync on an NTP fix?
|
||||
|
||||
@ -309,7 +309,7 @@ Features:
|
||||
|
||||
* exponential backoff in timesyncd and resolved when we cannot reach a server
|
||||
|
||||
* unquote_many_words() should probably be used by a lot of code that
|
||||
* extract_many_words() should probably be used by a lot of code that
|
||||
currently uses FOREACH_WORD and friends. For example, most conf
|
||||
parsing callbacks should use it.
|
||||
|
||||
|
@ -581,7 +581,9 @@
|
||||
same path in the container --, or a colon-separated pair of
|
||||
paths -- in which case the first specified path is the source
|
||||
in the host, and the second path is the destination in the
|
||||
container. This option may be specified multiple times for
|
||||
container. Backslash escapes are interpreted so
|
||||
<literal>\:</literal> may be used to embed colons in either path.
|
||||
This option may be specified multiple times for
|
||||
creating multiple independent bind mount points. The
|
||||
<option>--bind-ro=</option> option creates read-only bind
|
||||
mounts.</para></listitem>
|
||||
@ -600,7 +602,10 @@
|
||||
otherwise specified). This option is particularly useful for
|
||||
mounting directories such as <filename>/var</filename> as
|
||||
tmpfs, to allow state-less systems, in particular when
|
||||
combined with <option>--read-only</option>.</para></listitem>
|
||||
combined with <option>--read-only</option>.
|
||||
Backslash escapes are interpreted in the path so
|
||||
<literal>\:</literal> may be used to embed colons in the path.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -612,6 +617,10 @@
|
||||
list of colon-separated paths to the directory trees to
|
||||
combine and the destination mount point.</para>
|
||||
|
||||
<para>Backslash escapes are interpreted in the paths, so
|
||||
<literal>\:</literal> may be used to embed colons in the paths.
|
||||
</para>
|
||||
|
||||
<para>If three or more paths are specified, then the last
|
||||
specified path is the destination mount point in the
|
||||
container, all paths specified before refer to directory trees
|
||||
|
@ -550,7 +550,7 @@ char **replace_env_argv(char **argv, char **env) {
|
||||
if (e) {
|
||||
int r;
|
||||
|
||||
r = strv_split_quoted(&m, e, UNQUOTE_RELAX);
|
||||
r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES);
|
||||
if (r < 0) {
|
||||
ret[k] = NULL;
|
||||
strv_free(ret);
|
||||
|
@ -278,7 +278,7 @@ char **strv_split_newlines(const char *s) {
|
||||
return l;
|
||||
}
|
||||
|
||||
int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) {
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
|
||||
size_t n = 0, allocated = 0;
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
int r;
|
||||
@ -289,11 +289,12 @@ int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) {
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = unquote_first_word(&s, &word, flags);
|
||||
r = extract_first_word(&s, &word, separators, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(l, allocated, n + 2))
|
||||
return -ENOMEM;
|
||||
@ -693,6 +694,26 @@ char **strv_reverse(char **l) {
|
||||
return l;
|
||||
}
|
||||
|
||||
char **strv_shell_escape(char **l, const char *bad) {
|
||||
char **s;
|
||||
|
||||
/* Escapes every character in every string in l that is in bad,
|
||||
* edits in-place, does not roll-back on error. */
|
||||
|
||||
STRV_FOREACH(s, l) {
|
||||
char *v;
|
||||
|
||||
v = shell_escape(*s, bad);
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
free(*s);
|
||||
*s = v;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
|
||||
char* const* p;
|
||||
|
||||
|
@ -73,7 +73,7 @@ static inline bool strv_isempty(char * const *l) {
|
||||
char **strv_split(const char *s, const char *separator);
|
||||
char **strv_split_newlines(const char *s);
|
||||
|
||||
int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags);
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
|
||||
|
||||
char *strv_join(char **l, const char *separator);
|
||||
char *strv_join_quoted(char **l);
|
||||
@ -145,6 +145,7 @@ void strv_print(char **l);
|
||||
}))
|
||||
|
||||
char **strv_reverse(char **l);
|
||||
char **strv_shell_escape(char **l, const char *bad);
|
||||
|
||||
bool strv_fnmatch(char* const* patterns, const char *s, int flags);
|
||||
|
||||
|
138
src/basic/util.c
138
src/basic/util.c
@ -4843,7 +4843,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
char *value = NULL;
|
||||
|
||||
r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -4883,7 +4883,7 @@ int get_proc_cmdline_key(const char *key, char **value) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
const char *e;
|
||||
|
||||
r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -5698,7 +5698,7 @@ int is_device_node(const char *path) {
|
||||
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
|
||||
}
|
||||
|
||||
int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
size_t allocated = 0, sz = 0;
|
||||
int r;
|
||||
@ -5711,13 +5711,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
SINGLE_QUOTE_ESCAPE,
|
||||
DOUBLE_QUOTE,
|
||||
DOUBLE_QUOTE_ESCAPE,
|
||||
SPACE,
|
||||
SEPARATOR,
|
||||
} state = START;
|
||||
|
||||
assert(p);
|
||||
assert(*p);
|
||||
assert(ret);
|
||||
|
||||
if (!separators)
|
||||
separators = WHITESPACE;
|
||||
|
||||
/* Bail early if called after last value or with no input */
|
||||
if (!*p)
|
||||
goto finish_force_terminate;
|
||||
|
||||
/* Parses the first word of a string, and returns it in
|
||||
* *ret. Removes all quotes in the process. When parsing fails
|
||||
* (because of an uneven number of quotes or similar), leaves
|
||||
@ -5729,32 +5735,46 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
switch (state) {
|
||||
|
||||
case START:
|
||||
if (c == 0)
|
||||
goto finish;
|
||||
else if (strchr(WHITESPACE, c))
|
||||
if (c == 0) {
|
||||
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+1))
|
||||
return -ENOMEM;
|
||||
goto finish_force_terminate;
|
||||
} else if (strchr(separators, c)) {
|
||||
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+1))
|
||||
return -ENOMEM;
|
||||
(*p) ++;
|
||||
goto finish_force_next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
state = VALUE;
|
||||
/* fallthrough */
|
||||
|
||||
case VALUE:
|
||||
if (c == 0)
|
||||
goto finish;
|
||||
else if (c == '\'') {
|
||||
goto finish_force_terminate;
|
||||
else if (c == '\'' && (flags & EXTRACT_QUOTES)) {
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+1))
|
||||
return -ENOMEM;
|
||||
|
||||
state = SINGLE_QUOTE;
|
||||
} else if (c == '\\')
|
||||
state = VALUE_ESCAPE;
|
||||
else if (c == '\"') {
|
||||
else if (c == '\"' && (flags & EXTRACT_QUOTES)) {
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+1))
|
||||
return -ENOMEM;
|
||||
|
||||
state = DOUBLE_QUOTE;
|
||||
} else if (strchr(WHITESPACE, c))
|
||||
state = SPACE;
|
||||
else {
|
||||
} else if (strchr(separators, c)) {
|
||||
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
|
||||
(*p) ++;
|
||||
goto finish_force_next;
|
||||
}
|
||||
state = SEPARATOR;
|
||||
} else {
|
||||
if (!GREEDY_REALLOC(s, allocated, sz+2))
|
||||
return -ENOMEM;
|
||||
|
||||
@ -5765,8 +5785,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
|
||||
case SINGLE_QUOTE:
|
||||
if (c == 0) {
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
goto finish;
|
||||
if (flags & EXTRACT_RELAX)
|
||||
goto finish_force_terminate;
|
||||
return -EINVAL;
|
||||
} else if (c == '\'')
|
||||
state = VALUE;
|
||||
@ -5804,29 +5824,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
|
||||
return -ENOMEM;
|
||||
|
||||
if (c == 0) {
|
||||
if ((flags & UNQUOTE_CUNESCAPE_RELAX) &&
|
||||
(state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) {
|
||||
if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
|
||||
(state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
|
||||
/* If we find an unquoted trailing backslash and we're in
|
||||
* UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the
|
||||
* EXTRACT_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.
|
||||
* Unbalanced quotes will only be allowed in EXTRACT_RELAX
|
||||
* mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
|
||||
*/
|
||||
s[sz++] = '\\';
|
||||
goto finish;
|
||||
goto finish_force_terminate;
|
||||
}
|
||||
if (flags & UNQUOTE_RELAX)
|
||||
goto finish;
|
||||
if (flags & EXTRACT_RELAX)
|
||||
goto finish_force_terminate;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flags & UNQUOTE_CUNESCAPE) {
|
||||
if (flags & EXTRACT_CUNESCAPE) {
|
||||
uint32_t u;
|
||||
|
||||
r = cunescape_one(*p, (size_t) -1, &c, &u);
|
||||
if (r < 0) {
|
||||
if (flags & UNQUOTE_CUNESCAPE_RELAX) {
|
||||
if (flags & EXTRACT_CUNESCAPE_RELAX) {
|
||||
s[sz++] = '\\';
|
||||
s[sz++] = c;
|
||||
goto end_escape;
|
||||
@ -5849,24 +5869,29 @@ end_escape:
|
||||
VALUE;
|
||||
break;
|
||||
|
||||
case SPACE:
|
||||
case SEPARATOR:
|
||||
if (c == 0)
|
||||
goto finish_force_terminate;
|
||||
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
|
||||
goto finish_force_next;
|
||||
if (!strchr(separators, c))
|
||||
goto finish;
|
||||
if (!strchr(WHITESPACE, c))
|
||||
goto finish;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
(*p) ++;
|
||||
}
|
||||
|
||||
finish_force_terminate:
|
||||
*p = NULL;
|
||||
finish:
|
||||
if (!s) {
|
||||
*p = NULL;
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
finish_force_next:
|
||||
s[sz] = 0;
|
||||
*ret = s;
|
||||
s = NULL;
|
||||
@ -5874,26 +5899,27 @@ finish:
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unquote_first_word_and_warn(
|
||||
int extract_first_word_and_warn(
|
||||
const char **p,
|
||||
char **ret,
|
||||
UnquoteFlags flags,
|
||||
const char *separators,
|
||||
ExtractFlags 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
|
||||
* time using EXTRACT_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. */
|
||||
r = extract_first_word(p, ret, separators, flags);
|
||||
if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
|
||||
/* Retry it with EXTRACT_CUNESCAPE_RELAX. */
|
||||
*p = save;
|
||||
r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX);
|
||||
r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
|
||||
@ -5904,7 +5930,7 @@ int unquote_first_word_and_warn(
|
||||
return r;
|
||||
}
|
||||
|
||||
int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
|
||||
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
|
||||
va_list ap;
|
||||
char **l;
|
||||
int n = 0, i, c, r;
|
||||
@ -5930,7 +5956,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
|
||||
l = newa0(char*, n);
|
||||
for (c = 0; c < n; c++) {
|
||||
|
||||
r = unquote_first_word(p, &l[c], flags);
|
||||
r = extract_first_word(p, &l[c], separators, flags);
|
||||
if (r < 0) {
|
||||
int j;
|
||||
|
||||
@ -6511,6 +6537,32 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
|
||||
assert(bad);
|
||||
|
||||
for (; *s; s++) {
|
||||
if (*s == '\\' || strchr(bad, *s))
|
||||
*(t++) = '\\';
|
||||
|
||||
*(t++) = *s;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
char *shell_escape(const char *s, const char *bad) {
|
||||
char *r, *t;
|
||||
|
||||
r = new(char, strlen(s)*2+1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
t = strcpy_backslash_escaped(r, s, bad);
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *shell_maybe_quote(const char *s) {
|
||||
const char *p;
|
||||
char *r, *t;
|
||||
@ -6537,13 +6589,7 @@ char *shell_maybe_quote(const char *s) {
|
||||
*(t++) = '"';
|
||||
t = mempcpy(t, s, p - s);
|
||||
|
||||
for (; *p; p++) {
|
||||
|
||||
if (strchr(SHELL_NEED_ESCAPE, *p))
|
||||
*(t++) = '\\';
|
||||
|
||||
*(t++) = *p;
|
||||
}
|
||||
t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
|
||||
|
||||
*(t++)= '"';
|
||||
*t = 0;
|
||||
|
@ -854,15 +854,17 @@ int is_symlink(const char *path);
|
||||
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_CUNESCAPE_RELAX = 4,
|
||||
} UnquoteFlags;
|
||||
typedef enum ExtractFlags {
|
||||
EXTRACT_RELAX = 1,
|
||||
EXTRACT_CUNESCAPE = 2,
|
||||
EXTRACT_CUNESCAPE_RELAX = 4,
|
||||
EXTRACT_QUOTES = 8,
|
||||
EXTRACT_DONT_COALESCE_SEPARATORS = 16,
|
||||
} ExtractFlags;
|
||||
|
||||
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 extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
|
||||
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
|
||||
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
|
||||
|
||||
static inline void free_and_replace(char **s, char *v) {
|
||||
free(*s);
|
||||
@ -917,6 +919,7 @@ void cmsg_close_all(struct msghdr *mh);
|
||||
|
||||
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
|
||||
|
||||
char *shell_escape(const char *s, const char *bad);
|
||||
char *shell_maybe_quote(const char *s);
|
||||
|
||||
int parse_mode(const char *s, mode_t *ret);
|
||||
|
@ -552,7 +552,7 @@ int config_parse_exec(
|
||||
|
||||
semicolon = false;
|
||||
|
||||
r = unquote_first_word_and_warn(&p, &firstword, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
|
||||
r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
|
||||
if (r <= 0)
|
||||
return 0;
|
||||
|
||||
@ -614,7 +614,7 @@ int config_parse_exec(
|
||||
|
||||
path_kill_slashes(path);
|
||||
|
||||
for (;;) {
|
||||
while (!isempty(p)) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
/* Check explicitly for an unquoted semicolon as
|
||||
@ -627,7 +627,7 @@ int config_parse_exec(
|
||||
}
|
||||
|
||||
/* Check for \; explicitly, to not confuse it with \\;
|
||||
* or "\;" or "\\;" etc. unquote_first_word would
|
||||
* or "\;" or "\\;" etc. extract_first_word would
|
||||
* return the same for all of those. */
|
||||
if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
|
||||
p += 2;
|
||||
@ -642,7 +642,7 @@ int config_parse_exec(
|
||||
continue;
|
||||
}
|
||||
|
||||
r = unquote_first_word_and_warn(&p, &word, UNQUOTE_CUNESCAPE, unit, filename, line, rvalue);
|
||||
r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
|
||||
if (r == 0)
|
||||
break;
|
||||
else if (r < 0)
|
||||
|
@ -148,7 +148,7 @@ static int spawn_getter(const char *getter, const char *url) {
|
||||
_cleanup_strv_free_ char **words = NULL;
|
||||
|
||||
assert(getter);
|
||||
r = strv_split_quoted(&words, getter, 0);
|
||||
r = strv_split_extract(&words, getter, WHITESPACE, EXTRACT_QUOTES);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to split getter option: %m");
|
||||
|
||||
|
@ -222,7 +222,7 @@ static int x11_read_data(Context *c) {
|
||||
if (in_section && first_word(l, "Option")) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
|
||||
r = strv_split_quoted(&a, l, 0);
|
||||
r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -245,7 +245,7 @@ static int x11_read_data(Context *c) {
|
||||
} else if (!in_section && first_word(l, "Section")) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
|
||||
r = strv_split_quoted(&a, l, 0);
|
||||
r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -544,7 +544,7 @@ static int read_next_mapping(const char* filename,
|
||||
if (l[0] == 0 || l[0] == '#')
|
||||
continue;
|
||||
|
||||
r = strv_split_quoted(&b, l, 0);
|
||||
r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -655,17 +655,22 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
case ARG_BIND:
|
||||
case ARG_BIND_RO: {
|
||||
const char *current = optarg;
|
||||
_cleanup_free_ char *source = NULL, *destination = NULL;
|
||||
CustomMount *m;
|
||||
char *e;
|
||||
_cleanup_strv_free_ char **strv = NULL;
|
||||
|
||||
e = strchr(optarg, ':');
|
||||
if (e) {
|
||||
source = strndup(optarg, e - optarg);
|
||||
destination = strdup(e + 1);
|
||||
} else {
|
||||
source = strdup(optarg);
|
||||
destination = strdup(optarg);
|
||||
r = extract_many_words(¤t, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
|
||||
switch (r) {
|
||||
case 1:
|
||||
destination = strdup(source);
|
||||
case 2:
|
||||
break;
|
||||
case -ENOMEM:
|
||||
return log_oom();
|
||||
default:
|
||||
log_error("Invalid bind mount specification: %s", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!source || !destination)
|
||||
@ -690,18 +695,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
case ARG_TMPFS: {
|
||||
const char *current = optarg;
|
||||
_cleanup_free_ char *path = NULL, *opts = NULL;
|
||||
CustomMount *m;
|
||||
char *e;
|
||||
|
||||
e = strchr(optarg, ':');
|
||||
if (e) {
|
||||
path = strndup(optarg, e - optarg);
|
||||
opts = strdup(e + 1);
|
||||
} else {
|
||||
path = strdup(optarg);
|
||||
opts = strdup("mode=0755");
|
||||
r = extract_first_word(¤t, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
else if (r < 0) {
|
||||
log_error("Invalid tmpfs specification: %s", optarg);
|
||||
return r;
|
||||
}
|
||||
if (r)
|
||||
opts = strdup(current);
|
||||
else
|
||||
opts = strdup("mode=0755");
|
||||
|
||||
if (!path || !opts)
|
||||
return log_oom();
|
||||
@ -731,9 +739,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
unsigned n = 0;
|
||||
char **i;
|
||||
|
||||
lower = strv_split(optarg, ":");
|
||||
if (!lower)
|
||||
r = strv_split_extract(&lower, optarg, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
else if (r < 0) {
|
||||
log_error("Invalid overlay specification: %s", optarg);
|
||||
return r;
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, lower) {
|
||||
if (!path_is_absolute(*i)) {
|
||||
@ -1227,6 +1239,21 @@ static int mount_tmpfs(const char *dest, CustomMount *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *joined_and_escaped_lower_dirs(char * const *lower) {
|
||||
_cleanup_strv_free_ char **sv = NULL;
|
||||
|
||||
sv = strv_copy(lower);
|
||||
if (!sv)
|
||||
return NULL;
|
||||
|
||||
strv_reverse(sv);
|
||||
|
||||
if (!strv_shell_escape(sv, ",:"))
|
||||
return NULL;
|
||||
|
||||
return strv_join(sv, ":");
|
||||
}
|
||||
|
||||
static int mount_overlay(const char *dest, CustomMount *m) {
|
||||
_cleanup_free_ char *lower = NULL;
|
||||
const char *where, *options;
|
||||
@ -1243,19 +1270,32 @@ static int mount_overlay(const char *dest, CustomMount *m) {
|
||||
|
||||
(void) mkdir_p_label(m->source, 0755);
|
||||
|
||||
strv_reverse(m->lower);
|
||||
lower = strv_join(m->lower, ":");
|
||||
strv_reverse(m->lower);
|
||||
lower = joined_and_escaped_lower_dirs(m->lower);
|
||||
if (!lower)
|
||||
return log_oom();
|
||||
|
||||
if (m->read_only)
|
||||
options = strjoina("lowerdir=", m->source, ":", lower);
|
||||
else {
|
||||
if (m->read_only) {
|
||||
_cleanup_free_ char *escaped_source = NULL;
|
||||
|
||||
escaped_source = shell_escape(m->source, ",:");
|
||||
if (!escaped_source)
|
||||
return log_oom();
|
||||
|
||||
options = strjoina("lowerdir=", escaped_source, ":", lower);
|
||||
} else {
|
||||
_cleanup_free_ char *escaped_source = NULL, *escaped_work_dir = NULL;
|
||||
|
||||
assert(m->work_dir);
|
||||
(void) mkdir_label(m->work_dir, 0700);
|
||||
|
||||
options = strjoina("lowerdir=", lower, ",upperdir=", m->source, ",workdir=", m->work_dir);
|
||||
escaped_source = shell_escape(m->source, ",:");
|
||||
if (!escaped_source)
|
||||
return log_oom();
|
||||
escaped_work_dir = shell_escape(m->work_dir, ",:");
|
||||
if (!escaped_work_dir)
|
||||
return log_oom();
|
||||
|
||||
options = strjoina("lowerdir=", lower, ",upperdir=", escaped_source, ",workdir=", escaped_work_dir);
|
||||
}
|
||||
|
||||
if (mount("overlay", where, "overlay", m->read_only ? MS_RDONLY : 0, options) < 0)
|
||||
|
@ -101,7 +101,7 @@ static int condition_test_kernel_command_line(Condition *c) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
bool found;
|
||||
|
||||
r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
|
@ -1380,7 +1380,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
|
||||
/* Parse columns */
|
||||
p = buffer;
|
||||
r = unquote_many_words(&p, 0, &action, &name, &id, &description, &home, NULL);
|
||||
r = extract_many_words(&p, NULL, EXTRACT_QUOTES, &action, &name, &id, &description, &home, NULL);
|
||||
if (r < 0) {
|
||||
log_error("[%s:%u] Syntax error.", fname, line);
|
||||
return r;
|
||||
@ -1389,7 +1389,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
log_error("[%s:%u] Missing action and name columns.", fname, line);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (*p != 0) {
|
||||
if (!isempty(p)) {
|
||||
log_error("[%s:%u] Trailing garbage.", fname, line);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
|
||||
assert_se(p);
|
||||
assert_se(streq(p, quoted));
|
||||
|
||||
r = strv_split_quoted(&s, quoted, 0);
|
||||
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
|
||||
assert_se(r == 0);
|
||||
assert_se(s);
|
||||
STRV_FOREACH(t, s) {
|
||||
@ -182,7 +182,7 @@ static void test_strv_unquote(const char *quoted, char **list) {
|
||||
char **t;
|
||||
int r;
|
||||
|
||||
r = strv_split_quoted(&s, quoted, 0);
|
||||
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
|
||||
assert_se(r == 0);
|
||||
assert_se(s);
|
||||
j = strv_join(s, " | ");
|
||||
@ -199,7 +199,7 @@ static void test_invalid_unquote(const char *quoted) {
|
||||
char **s = NULL;
|
||||
int r;
|
||||
|
||||
r = strv_split_quoted(&s, quoted, 0);
|
||||
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
|
||||
assert_se(s == NULL);
|
||||
assert_se(r == -EINVAL);
|
||||
}
|
||||
@ -219,6 +219,21 @@ static void test_strv_split(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_strv_split_extract(void) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
const char *str = ":foo\\:bar::waldo:";
|
||||
int r;
|
||||
|
||||
r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
assert_se(r == 0);
|
||||
assert_se(streq_ptr(l[0], ""));
|
||||
assert_se(streq_ptr(l[1], "foo:bar"));
|
||||
assert_se(streq_ptr(l[2], ""));
|
||||
assert_se(streq_ptr(l[3], "waldo"));
|
||||
assert_se(streq_ptr(l[4], ""));
|
||||
assert_se(streq_ptr(l[5], NULL));
|
||||
}
|
||||
|
||||
static void test_strv_split_newlines(void) {
|
||||
unsigned i = 0;
|
||||
char **s;
|
||||
@ -542,6 +557,18 @@ static void test_strv_reverse(void) {
|
||||
assert_se(streq_ptr(d[3], NULL));
|
||||
}
|
||||
|
||||
static void test_strv_shell_escape(void) {
|
||||
_cleanup_strv_free_ char **v = NULL;
|
||||
|
||||
v = strv_new("foo:bar", "bar,baz", "wal\\do", NULL);
|
||||
assert_se(v);
|
||||
assert_se(strv_shell_escape(v, ",:"));
|
||||
assert_se(streq_ptr(v[0], "foo\\:bar"));
|
||||
assert_se(streq_ptr(v[1], "bar\\,baz"));
|
||||
assert_se(streq_ptr(v[2], "wal\\\\do"));
|
||||
assert_se(streq_ptr(v[3], NULL));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_specifier_printf();
|
||||
test_strv_foreach();
|
||||
@ -583,6 +610,7 @@ int main(int argc, char *argv[]) {
|
||||
test_invalid_unquote("'x'y'g");
|
||||
|
||||
test_strv_split();
|
||||
test_strv_split_extract();
|
||||
test_strv_split_newlines();
|
||||
test_strv_split_nulstr();
|
||||
test_strv_parse_nulstr();
|
||||
@ -598,6 +626,7 @@ int main(int argc, char *argv[]) {
|
||||
test_strv_equal();
|
||||
test_strv_is_uniq();
|
||||
test_strv_reverse();
|
||||
test_strv_shell_escape();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1487,350 +1487,448 @@ static void test_execute_directory(void) {
|
||||
(void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||
}
|
||||
|
||||
static void test_unquote_first_word(void) {
|
||||
static void test_extract_first_word(void) {
|
||||
const char *p, *original;
|
||||
char *t;
|
||||
|
||||
p = original = "foobar waldo";
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "foobar"));
|
||||
free(t);
|
||||
assert_se(p == original + 7);
|
||||
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(unquote_first_word(&p, &t, 0) == 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foobar\" \'waldo\'";
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "\"foobar\""));
|
||||
free(t);
|
||||
assert_se(p == original + 9);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "\'waldo\'"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foobar\" \'waldo\'";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
|
||||
assert_se(streq(t, "foobar"));
|
||||
free(t);
|
||||
assert_se(p == original + 9);
|
||||
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 16);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(unquote_first_word(&p, &t, 0) == 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(p == original + 16);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"";
|
||||
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
|
||||
assert_se(streq(t, "\""));
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
|
||||
assert_se(p == original + 1);
|
||||
|
||||
p = original = "\'";
|
||||
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
|
||||
assert_se(streq(t, "\'"));
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\'";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
|
||||
assert_se(p == original + 1);
|
||||
|
||||
p = original = "\'fooo";
|
||||
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
|
||||
assert_se(streq(t, "\'fooo"));
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\'fooo";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\'fooo";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "yay\'foo\'bar";
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "yay\'foo\'bar"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "yay\'foo\'bar";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
|
||||
assert_se(streq(t, "yayfoobar"));
|
||||
free(t);
|
||||
assert_se(p == original + 11);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " foobar ";
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "foobar"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " foo\\ba\\x6ar ";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
|
||||
assert_se(streq(t, "foo\ba\x6ar"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " foo\\ba\\x6ar ";
|
||||
assert_se(unquote_first_word(&p, &t, 0) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
|
||||
assert_se(streq(t, "foobax6ar"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
|
||||
assert_se(streq(t, "föo"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0);
|
||||
assert_se(streq(t, "pi\360\237\222\251le"));
|
||||
free(t);
|
||||
assert_se(p == original + 32);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
|
||||
p = original = "foo::bar";
|
||||
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
|
||||
assert_se(streq(t, "bar"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", 0) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "foo\\:bar::waldo";
|
||||
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
|
||||
assert_se(streq(t, "foo:bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", 0) == 1);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", 0) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) == -EINVAL);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_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(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "foo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "foo\\"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
|
||||
assert_se(streq(t, "fooo bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
|
||||
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(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_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(extract_first_word(&p, &t, NULL, EXTRACT_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(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\\w+\\b";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
|
||||
assert_se(streq(t, "\\w+\b"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "-N ''";
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
|
||||
assert_se(streq(t, "-N"));
|
||||
free(t);
|
||||
assert_se(p == original + 3);
|
||||
|
||||
assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
|
||||
assert_se(streq(t, ""));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = ":foo\\:bar::waldo:";
|
||||
assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
|
||||
assert_se(t);
|
||||
assert_se(streq(t, ""));
|
||||
free(t);
|
||||
assert_se(p == original + 1);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
|
||||
assert_se(streq(t, "foo:bar"));
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
|
||||
assert_se(t);
|
||||
assert_se(streq(t, ""));
|
||||
free(t);
|
||||
assert_se(p == original + 11);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 17);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
|
||||
assert_se(streq(t, ""));
|
||||
free(t);
|
||||
assert_se(p == NULL);
|
||||
|
||||
assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(!p);
|
||||
}
|
||||
|
||||
static void test_unquote_first_word_and_warn(void) {
|
||||
static void test_extract_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(extract_first_word_and_warn(&p, &t, NULL, 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(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foobar\" \'waldo\'";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "waldo"));
|
||||
free(t);
|
||||
assert_se(p == original + 16);
|
||||
assert_se(isempty(p));
|
||||
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
|
||||
assert_se(!t);
|
||||
assert_se(p == original + 16);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " foo\\ba\\x6ar ";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foo\ba\x6ar"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " foo\\ba\\x6ar ";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foobax6ar"));
|
||||
free(t);
|
||||
assert_se(p == original + 13);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "pi\360\237\222\251le"));
|
||||
free(t);
|
||||
assert_se(p == original + 32);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "fooo\\"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
|
||||
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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\"foo\\";
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_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, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "foo"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_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(extract_first_word_and_warn(&p, &t, NULL, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "\\w+@\\K[\\d.]+"));
|
||||
free(t);
|
||||
assert_se(p == original + 12);
|
||||
assert_se(isempty(p));
|
||||
|
||||
p = original = "\\w+\\b";
|
||||
assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
|
||||
assert_se(streq(t, "\\w+\b"));
|
||||
free(t);
|
||||
assert_se(p == original + 5);
|
||||
assert_se(isempty(p));
|
||||
}
|
||||
|
||||
static void test_unquote_many_words(void) {
|
||||
static void test_extract_many_words(void) {
|
||||
const char *p, *original;
|
||||
char *a, *b, *c;
|
||||
|
||||
p = original = "foobar waldi piep";
|
||||
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 3);
|
||||
assert_se(p == original + 17);
|
||||
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
|
||||
assert_se(isempty(p));
|
||||
assert_se(streq_ptr(a, "foobar"));
|
||||
assert_se(streq_ptr(b, "waldi"));
|
||||
assert_se(streq_ptr(c, "piep"));
|
||||
@ -1839,8 +1937,17 @@ static void test_unquote_many_words(void) {
|
||||
free(c);
|
||||
|
||||
p = original = "'foobar' wa\"ld\"i ";
|
||||
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 2);
|
||||
assert_se(p == original + 19);
|
||||
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
|
||||
assert_se(isempty(p));
|
||||
assert_se(streq_ptr(a, "'foobar'"));
|
||||
assert_se(streq_ptr(b, "wa\"ld\"i"));
|
||||
assert_se(streq_ptr(c, NULL));
|
||||
free(a);
|
||||
free(b);
|
||||
|
||||
p = original = "'foobar' wa\"ld\"i ";
|
||||
assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2);
|
||||
assert_se(isempty(p));
|
||||
assert_se(streq_ptr(a, "foobar"));
|
||||
assert_se(streq_ptr(b, "waldi"));
|
||||
assert_se(streq_ptr(c, NULL));
|
||||
@ -1848,32 +1955,32 @@ static void test_unquote_many_words(void) {
|
||||
free(b);
|
||||
|
||||
p = original = "";
|
||||
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0);
|
||||
assert_se(p == original);
|
||||
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
|
||||
assert_se(isempty(p));
|
||||
assert_se(streq_ptr(a, NULL));
|
||||
assert_se(streq_ptr(b, NULL));
|
||||
assert_se(streq_ptr(c, NULL));
|
||||
|
||||
p = original = " ";
|
||||
assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0);
|
||||
assert_se(p == original+2);
|
||||
assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
|
||||
assert_se(isempty(p));
|
||||
assert_se(streq_ptr(a, NULL));
|
||||
assert_se(streq_ptr(b, NULL));
|
||||
assert_se(streq_ptr(c, NULL));
|
||||
|
||||
p = original = "foobar";
|
||||
assert_se(unquote_many_words(&p, 0, NULL) == 0);
|
||||
assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
|
||||
assert_se(p == original);
|
||||
|
||||
p = original = "foobar waldi";
|
||||
assert_se(unquote_many_words(&p, 0, &a, NULL) == 1);
|
||||
assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
|
||||
assert_se(p == original+7);
|
||||
assert_se(streq_ptr(a, "foobar"));
|
||||
free(a);
|
||||
|
||||
p = original = " foobar ";
|
||||
assert_se(unquote_many_words(&p, 0, &a, NULL) == 1);
|
||||
assert_se(p == original+15);
|
||||
assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
|
||||
assert_se(isempty(p));
|
||||
assert_se(streq_ptr(a, "foobar"));
|
||||
free(a);
|
||||
}
|
||||
@ -1993,6 +2100,21 @@ static void test_sparse_write(void) {
|
||||
test_sparse_write_one(fd, test_e, sizeof(test_e));
|
||||
}
|
||||
|
||||
static void test_shell_escape_one(const char *s, const char *bad, const char *expected) {
|
||||
_cleanup_free_ char *r;
|
||||
|
||||
assert_se(r = shell_escape(s, bad));
|
||||
assert_se(streq_ptr(r, expected));
|
||||
}
|
||||
|
||||
static void test_shell_escape(void) {
|
||||
test_shell_escape_one("", "", "");
|
||||
test_shell_escape_one("\\", "", "\\\\");
|
||||
test_shell_escape_one("foobar", "", "foobar");
|
||||
test_shell_escape_one("foobar", "o", "f\\o\\obar");
|
||||
test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz");
|
||||
}
|
||||
|
||||
static void test_shell_maybe_quote_one(const char *s, const char *expected) {
|
||||
_cleanup_free_ char *r;
|
||||
|
||||
@ -2149,14 +2271,15 @@ int main(int argc, char *argv[]) {
|
||||
test_search_and_fopen_nulstr();
|
||||
test_glob_exists();
|
||||
test_execute_directory();
|
||||
test_unquote_first_word();
|
||||
test_unquote_first_word_and_warn();
|
||||
test_unquote_many_words();
|
||||
test_extract_first_word();
|
||||
test_extract_first_word_and_warn();
|
||||
test_extract_many_words();
|
||||
test_parse_proc_cmdline();
|
||||
test_raw_clone();
|
||||
test_same_fd();
|
||||
test_uid_ptr();
|
||||
test_sparse_write();
|
||||
test_shell_escape();
|
||||
test_shell_maybe_quote();
|
||||
test_parse_mode();
|
||||
test_tempfn();
|
||||
|
@ -662,7 +662,7 @@ static int parse_xattrs_from_arg(Item *i) {
|
||||
for (;;) {
|
||||
_cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL, *xattr_replaced = NULL;
|
||||
|
||||
r = unquote_first_word(&p, &xattr, UNQUOTE_CUNESCAPE);
|
||||
r = extract_first_word(&p, &xattr, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
|
||||
if (r <= 0)
|
||||
@ -1760,9 +1760,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
assert(line >= 1);
|
||||
assert(buffer);
|
||||
|
||||
r = unquote_many_words(
|
||||
r = extract_many_words(
|
||||
&buffer,
|
||||
0,
|
||||
NULL,
|
||||
EXTRACT_QUOTES,
|
||||
&action,
|
||||
&path,
|
||||
&mode,
|
||||
|
Loading…
Reference in New Issue
Block a user