From 12ba2c44dde4d7cfc0e531dbc3cbd0581c323637 Mon Sep 17 00:00:00 2001 From: Richard Maw Date: Tue, 23 Jun 2015 16:26:49 +0000 Subject: util: Don't interpret quotes by default in extract_first_word This adds an EXTRACT_QUOTES option to allow the previous behaviour, of not interpreting any character inside ' or " quotes as separators. --- src/basic/strv.c | 2 +- src/basic/util.c | 8 ++--- src/basic/util.h | 1 + src/core/load-fragment.c | 4 +-- src/shared/condition.c | 2 +- src/sysusers/sysusers.c | 2 +- src/test/test-util.c | 91 ++++++++++++++++++++++++++++++++++++------------ src/tmpfiles/tmpfiles.c | 4 +-- 8 files changed, 80 insertions(+), 34 deletions(-) diff --git a/src/basic/strv.c b/src/basic/strv.c index 69eb8c7fdb..72964a166a 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -289,7 +289,7 @@ int strv_split_quoted(char ***t, const char *s, ExtractFlags flags) { for (;;) { _cleanup_free_ char *word = NULL; - r = extract_first_word(&s, &word, NULL, flags); + r = extract_first_word(&s, &word, NULL, flags|EXTRACT_QUOTES); if (r < 0) return r; if (r == 0) diff --git a/src/basic/util.c b/src/basic/util.c index 8ddd627ac0..d4c385fcef 100644 --- a/src/basic/util.c +++ b/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 = extract_first_word(&p, &word, NULL, EXTRACT_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 = extract_first_word(&p, &word, NULL, EXTRACT_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -5746,14 +5746,14 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra case VALUE: if (c == 0) goto finish_force_terminate; - else if (c == '\'') { + 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; diff --git a/src/basic/util.h b/src/basic/util.h index a5d035b8bd..82fb771e20 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -858,6 +858,7 @@ typedef enum ExtractFlags { EXTRACT_RELAX = 1, EXTRACT_CUNESCAPE = 2, EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, } ExtractFlags; int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 9c93f526e8..e1e3a5ffb7 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -552,7 +552,7 @@ int config_parse_exec( semicolon = false; - r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_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; @@ -642,7 +642,7 @@ int config_parse_exec( continue; } - r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_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) diff --git a/src/shared/condition.c b/src/shared/condition.c index f7e182284f..f58e84a3d0 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -101,7 +101,7 @@ static int condition_test_kernel_command_line(Condition *c) { _cleanup_free_ char *word = NULL; bool found; - r = extract_first_word(&p, &word, NULL, EXTRACT_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index b08b3aba57..b5e09cad26 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1380,7 +1380,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { /* Parse columns */ p = buffer; - r = extract_many_words(&p, NULL, 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; diff --git a/src/test/test-util.c b/src/test/test-util.c index db80379395..40f5d34de3 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1508,11 +1508,26 @@ static void test_extract_first_word(void) { p = original = "\"foobar\" \'waldo\'"; assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobar")); + 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(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "waldo")); free(t); assert_se(isempty(p)); @@ -1522,25 +1537,46 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\""; - assert_se(extract_first_word(&p, &t, NULL, 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(extract_first_word(&p, &t, NULL, 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(extract_first_word(&p, &t, NULL, 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(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo")); free(t); assert_se(isempty(p)); p = original = "yay\'foo\'bar"; 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(isempty(p)); @@ -1569,7 +1605,7 @@ static void test_extract_first_word(void) { free(t); assert_se(p == original + 13); - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_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(isempty(p)); @@ -1603,7 +1639,7 @@ static void test_extract_first_word(void) { assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo")); free(t); assert_se(isempty(p)); @@ -1639,17 +1675,17 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_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(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_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(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_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)); @@ -1699,12 +1735,12 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "-N ''"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 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(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); assert_se(streq(t, "")); free(t); assert_se(isempty(p)); @@ -1730,12 +1766,12 @@ static void test_extract_first_word_and_warn(void) { assert_se(isempty(p)); p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 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(extract_first_word_and_warn(&p, &t, NULL, 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(isempty(p)); @@ -1745,19 +1781,19 @@ static void test_extract_first_word_and_warn(void) { assert_se(isempty(p)); p = original = "\""; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 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(extract_first_word_and_warn(&p, &t, NULL, 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(extract_first_word_and_warn(&p, &t, NULL, 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_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(isempty(p)); @@ -1780,7 +1816,7 @@ static void test_extract_first_word_and_warn(void) { free(t); assert_se(p == original + 13); - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_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(isempty(p)); @@ -1804,21 +1840,21 @@ static void test_extract_first_word_and_warn(void) { assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 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 = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_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_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + 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(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_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(isempty(p)); @@ -1871,6 +1907,15 @@ static void test_extract_many_words(void) { p = original = "'foobar' wa\"ld\"i "; 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)); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index d73138900d..8f29256c6d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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 = extract_first_word(&p, &xattr, NULL, EXTRACT_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) @@ -1763,7 +1763,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { r = extract_many_words( &buffer, NULL, - 0, + EXTRACT_QUOTES, &action, &path, &mode, -- cgit v1.2.3-54-g00ecf