]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
util: Introduce unquote_first_word_and_warn
authorFilipe Brandenburger <filbranden@google.com>
Tue, 9 Jun 2015 04:31:43 +0000 (21:31 -0700)
committerFilipe Brandenburger <filbranden@google.com>
Wed, 17 Jun 2015 18:12:12 +0000 (11:12 -0700)
It will try to unquot_first_word, but if it runs into escaping problems
it will retry it adding UNQUOTE_CUNESCAPE_RELAX to the flags.  If it
succeeds on the second try, it will log a warning about it.  If it fails
both times, it will log an error.

Add test cases to confirm it behaves as expected.

src/basic/util.c
src/basic/util.h
src/test/test-util.c

index 46a48c4d60cf07302500bc5138fbf0cec71d880a..727be56f58302a90d1d3395262ea754efa4bb256 100644 (file)
@@ -5320,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;
index 748f22f1a2eba3d609230e595b6b1f3314a9ca8a..a1d1dd15c3948b3682da88632c63271ce70bbb92 100644 (file)
@@ -845,6 +845,7 @@ typedef enum UnquoteFlags {
 } 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);
index b3e79cd6f55328d22754810f7ed7fa65d9ebb80f..ad9ea3bcce85792c44b10e7cfebf5207498aa062 100644 (file)
@@ -1400,6 +1400,150 @@ static void test_unquote_first_word(void) {
         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) {
         const char *p, *original;
         char *a, *b, *c;
@@ -1704,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();