summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Brandenburger <filbranden@google.com>2015-06-08 21:31:43 -0700
committerFilipe Brandenburger <filbranden@google.com>2015-06-17 11:12:12 -0700
commitb59292b296ad71a20a40d7c347b6ca71df48892d (patch)
tree64e88630263d09fa31c3c5db9eb00e2e277e513a
parentd6293c070e6e4b83d8e7ec56e465b0b215d55d98 (diff)
util: Introduce unquote_first_word_and_warn
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.
-rw-r--r--src/basic/util.c30
-rw-r--r--src/basic/util.h1
-rw-r--r--src/test/test-util.c145
3 files changed, 176 insertions, 0 deletions
diff --git a/src/basic/util.c b/src/basic/util.c
index 46a48c4d60..727be56f58 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -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;
diff --git a/src/basic/util.h b/src/basic/util.h
index 748f22f1a2..a1d1dd15c3 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -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);
diff --git a/src/test/test-util.c b/src/test/test-util.c
index b3e79cd6f5..ad9ea3bcce 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -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();