From f32d2db140150b9d38684a699c9875b6e24ca27c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Nov 2014 00:10:24 +0100 Subject: [PATCH] util: rework /proc/cmdline parser to use unquote_first_word() --- src/shared/condition.c | 2 +- src/shared/util.c | 59 +++++++++++++++++++++++++++++++++----------------- src/shared/util.h | 2 +- src/test/test-util.c | 41 ++++++++++++++++++++++++++--------- 4 files changed, 72 insertions(+), 32 deletions(-) diff --git a/src/shared/condition.c b/src/shared/condition.c index ae23599..c5a3caa 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 = unquote_first_word(&p, &word); + r = unquote_first_word(&p, &word, true); if (r < 0) return r; if (r == 0) diff --git a/src/shared/util.c b/src/shared/util.c index 6401aaf..ba86d20 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -6146,8 +6146,7 @@ int split_pair(const char *s, const char *sep, char **l, char **r) { int shall_restore_state(void) { _cleanup_free_ char *line = NULL; - const char *word, *state; - size_t l; + const char *p; int r; r = proc_cmdline(&line); @@ -6155,15 +6154,20 @@ int shall_restore_state(void) { return r; r = 1; - FOREACH_WORD_QUOTED(word, l, line, state) { + p = line; + + for (;;) { + _cleanup_free_ char *word = NULL; const char *e; - char n[l+1]; int k; - memcpy(n, word, l); - n[l] = 0; + k = unquote_first_word(&p, &word, true); + if (k < 0) + return k; + if (k == 0) + break; - e = startswith(n, "systemd.restore_state="); + e = startswith(word, "systemd.restore_state="); if (!e) continue; @@ -6186,8 +6190,7 @@ int proc_cmdline(char **ret) { int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { _cleanup_free_ char *line = NULL; - const char *w, *state; - size_t l; + const char *p; int r; assert(parse_item); @@ -6196,11 +6199,16 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { if (r < 0) return r; - FOREACH_WORD_QUOTED(w, l, line, state) { - char word[l+1], *value; + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + char *value = NULL; - memcpy(word, w, l); - word[l] = 0; + r = unquote_first_word(&p, &word, true); + if (r < 0) + return r; + if (r == 0) + break; /* Filter out arguments that are intended only for the * initrd */ @@ -6976,7 +6984,7 @@ int is_dir(const char* path, bool follow) { return !!S_ISDIR(st.st_mode); } -int unquote_first_word(const char **p, char **ret) { +int unquote_first_word(const char **p, char **ret, bool relax) { _cleanup_free_ char *s = NULL; size_t allocated = 0, sz = 0; @@ -7035,8 +7043,11 @@ int unquote_first_word(const char **p, char **ret) { break; case VALUE_ESCAPE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; + } if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -7047,9 +7058,11 @@ int unquote_first_word(const char **p, char **ret) { break; case SINGLE_QUOTE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; - else if (c == '\'') + } else if (c == '\'') state = VALUE; else if (c == '\\') state = SINGLE_QUOTE_ESCAPE; @@ -7063,8 +7076,11 @@ int unquote_first_word(const char **p, char **ret) { break; case SINGLE_QUOTE_ESCAPE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; + } if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -7090,8 +7106,11 @@ int unquote_first_word(const char **p, char **ret) { break; case DOUBLE_QUOTE_ESCAPE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; + } if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -7151,7 +7170,7 @@ int unquote_many_words(const char **p, ...) { l = newa0(char*, n); for (c = 0; c < n; c++) { - r = unquote_first_word(p, &l[c]); + r = unquote_first_word(p, &l[c], false); if (r < 0) { int j; diff --git a/src/shared/util.h b/src/shared/util.h index af589b6..4997225 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -1018,7 +1018,7 @@ int take_password_lock(const char *root); int is_symlink(const char *path); int is_dir(const char *path, bool follow); -int unquote_first_word(const char **p, char **ret); +int unquote_first_word(const char **p, char **ret, bool relax); int unquote_many_words(const char **p, ...) _sentinel_; int free_and_strdup(char **p, const char *s); diff --git a/src/test/test-util.c b/src/test/test-util.c index de6a2a0..01b0192 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1173,51 +1173,60 @@ static void test_unquote_first_word(void) { char *t; p = original = "foobar waldo"; - assert_se(unquote_first_word(&p, &t) > 0); + assert_se(unquote_first_word(&p, &t, false) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 7); - assert_se(unquote_first_word(&p, &t) > 0); + assert_se(unquote_first_word(&p, &t, false) > 0); assert_se(streq(t, "waldo")); free(t); assert_se(p == original + 12); - assert_se(unquote_first_word(&p, &t) == 0); + assert_se(unquote_first_word(&p, &t, false) == 0); assert_se(!t); assert_se(p == original + 12); p = original = "\"foobar\" \'waldo\'"; - assert_se(unquote_first_word(&p, &t) > 0); + assert_se(unquote_first_word(&p, &t, false) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 9); - assert_se(unquote_first_word(&p, &t) > 0); + assert_se(unquote_first_word(&p, &t, false) > 0); assert_se(streq(t, "waldo")); free(t); assert_se(p == original + 16); - assert_se(unquote_first_word(&p, &t) == 0); + assert_se(unquote_first_word(&p, &t, false) == 0); assert_se(!t); assert_se(p == original + 16); p = original = "\""; - assert_se(unquote_first_word(&p, &t) == -EINVAL); + assert_se(unquote_first_word(&p, &t, false) == -EINVAL); assert_se(p == original + 1); p = original = "\'"; - assert_se(unquote_first_word(&p, &t) == -EINVAL); + assert_se(unquote_first_word(&p, &t, false) == -EINVAL); assert_se(p == original + 1); + p = original = "\'fooo"; + assert_se(unquote_first_word(&p, &t, false) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(unquote_first_word(&p, &t, true) > 0); + assert_se(streq(t, "fooo")); + assert_se(p == original + 5); + p = original = "yay\'foo\'bar"; - assert_se(unquote_first_word(&p, &t) > 0); + assert_se(unquote_first_word(&p, &t, false) > 0); assert_se(streq(t, "yayfoobar")); free(t); assert_se(p == original + 11); p = original = " foobar "; - assert_se(unquote_first_word(&p, &t) > 0); + assert_se(unquote_first_word(&p, &t, false) > 0); assert_se(streq(t, "foobar")); free(t); assert_se(p == original + 12); @@ -1277,6 +1286,17 @@ static void test_unquote_many_words(void) { free(a); } +static int parse_item(const char *key, const char *value) { + assert_se(key); + + log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); + return 0; +} + +static void test_parse_proc_cmdline(void) { + assert_se(parse_proc_cmdline(parse_item) >= 0); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -1348,6 +1368,7 @@ int main(int argc, char *argv[]) { test_execute_directory(); test_unquote_first_word(); test_unquote_many_words(); + test_parse_proc_cmdline(); return 0; } -- 2.7.4