chiark / gitweb /
util: rework /proc/cmdline parser to use unquote_first_word()
authorLennart Poettering <lennart@poettering.net>
Thu, 6 Nov 2014 23:10:24 +0000 (00:10 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 Nov 2014 00:19:56 +0000 (01:19 +0100)
src/shared/condition.c
src/shared/util.c
src/shared/util.h
src/test/test-util.c

index ae23599410600b32461478bdc8eb5b9512b21d92..c5a3caa4dbbe2b0e318d0bcf1850da70a433e042 100644 (file)
@@ -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)
index 6401aaf61c0d8b77aaae018d1acb93a1b98d3cf8..ba86d206150cc92e0b43954d12dfb6d21404e1e6 100644 (file)
@@ -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;
 
index af589b6708c79d04f7b917538a1c408935be3711..4997225d832872e4a2146d1f65ecc5b62e3be9b0 100644 (file)
@@ -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);
index de6a2a0d89da39771e248a8969f7b14779c0ab84..01b0192c1c912d223909758e967164a0fb55bc25 100644 (file)
@@ -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;
 }