155 lines
5.2 KiB
Diff
155 lines
5.2 KiB
Diff
From 75bf5737f83ed16e23db32e3f6a68c8a28fc7527 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
|
Date: Thu, 18 Dec 2014 17:51:38 -0500
|
|
Subject: [PATCH] Treat a trailing backslash as an error
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Commit a2a5291b3f5 changed the parser to reject unfinished quoted
|
|
strings. Unfortunately it introduced an error where a trailing
|
|
backslash would case an infinite loop. Of course this must fixed, but
|
|
the question is what to to instead. Allowing trailing backslashes and
|
|
treating them as normal characters would be one option, but this seems
|
|
suboptimal. First, there would be inconsistency between handling of
|
|
quoting and of backslashes. Second, a trailing backslash is most
|
|
likely an error, at it seems better to point it out to the user than
|
|
to try to continue.
|
|
|
|
Updated rules:
|
|
ExecStart=/bin/echo \\ → OK, prints a backslash
|
|
ExecStart=/bin/echo \ → error
|
|
ExecStart=/bin/echo "x → error
|
|
ExecStart=/bin/echo "x"y → error
|
|
|
|
(cherry picked from commit ba774317ac7d3e67fdb9ed81663264d38859df59)
|
|
|
|
Conflicts:
|
|
src/test/test-strv.c
|
|
---
|
|
src/shared/util.c | 8 +++++++-
|
|
src/test/test-strv.c | 5 +++++
|
|
src/test/test-util.c | 49 ++++++++++++++++++++++++++++++-------------------
|
|
3 files changed, 42 insertions(+), 20 deletions(-)
|
|
|
|
diff --git a/src/shared/util.c b/src/shared/util.c
|
|
index 927bca4ec4..956649eab9 100644
|
|
--- a/src/shared/util.c
|
|
+++ b/src/shared/util.c
|
|
@@ -418,7 +418,7 @@ int safe_atod(const char *s, double *ret_d) {
|
|
|
|
static size_t strcspn_escaped(const char *s, const char *reject) {
|
|
bool escaped = false;
|
|
- size_t n;
|
|
+ int n;
|
|
|
|
for (n=0; s[n]; n++) {
|
|
if (escaped)
|
|
@@ -428,6 +428,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) {
|
|
else if (strchr(reject, s[n]))
|
|
break;
|
|
}
|
|
+
|
|
/* if s ends in \, return index of previous char */
|
|
return n - escaped;
|
|
}
|
|
@@ -463,6 +464,11 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
|
|
*state = current++ + *l + 2;
|
|
} else if (quoted) {
|
|
*l = strcspn_escaped(current, separator);
|
|
+ if (current[*l] && !strchr(separator, current[*l])) {
|
|
+ /* unfinished escape */
|
|
+ *state = current;
|
|
+ return NULL;
|
|
+ }
|
|
*state = current + *l;
|
|
} else {
|
|
*l = strcspn(current, separator);
|
|
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
|
|
index 204a821d6e..c8a7b25736 100644
|
|
--- a/src/test/test-strv.c
|
|
+++ b/src/test/test-strv.c
|
|
@@ -446,6 +446,11 @@ int main(int argc, char *argv[]) {
|
|
|
|
test_invalid_unquote("a --b='c \"d e\"'");
|
|
test_invalid_unquote("a --b='c \"d e\" '");
|
|
+
|
|
+ /* trailing backslashes */
|
|
+ test_strv_unquote(" x\\\\", STRV_MAKE("x\\"));
|
|
+ test_invalid_unquote(" x\\");
|
|
+
|
|
test_invalid_unquote("a --b='c \"d e\"garbage");
|
|
test_invalid_unquote("'");
|
|
test_invalid_unquote("\"");
|
|
diff --git a/src/test/test-util.c b/src/test/test-util.c
|
|
index de6a2a0d89..0fdd7f59ad 100644
|
|
--- a/src/test/test-util.c
|
|
+++ b/src/test/test-util.c
|
|
@@ -405,28 +405,12 @@ static void test_foreach_word(void) {
|
|
assert_se(strneq(expected[i++], word, l));
|
|
}
|
|
|
|
-static void test_foreach_word_quoted(void) {
|
|
+static void check(const char *test, char** expected, bool trailing) {
|
|
const char *word, *state;
|
|
size_t l;
|
|
int i = 0;
|
|
- const char test[] = "test a b c 'd' e '' '' hhh '' '' \"a b c\"";
|
|
- const char * const expected[] = {
|
|
- "test",
|
|
- "a",
|
|
- "b",
|
|
- "c",
|
|
- "d",
|
|
- "e",
|
|
- "",
|
|
- "",
|
|
- "hhh",
|
|
- "",
|
|
- "",
|
|
- "a b c",
|
|
- NULL
|
|
- };
|
|
|
|
- printf("<%s>\n", test);
|
|
+ printf("<<<%s>>>\n", test);
|
|
FOREACH_WORD_QUOTED(word, l, test, state) {
|
|
_cleanup_free_ char *t = NULL;
|
|
|
|
@@ -434,7 +418,34 @@ static void test_foreach_word_quoted(void) {
|
|
assert_se(strneq(expected[i++], word, l));
|
|
printf("<%s>\n", t);
|
|
}
|
|
- assert_se(isempty(state));
|
|
+ printf("<<<%s>>>\n", state);
|
|
+ assert(expected[i] == NULL);
|
|
+ assert_se(isempty(state) == !trailing);
|
|
+}
|
|
+
|
|
+static void test_foreach_word_quoted(void) {
|
|
+ check("test a b c 'd' e '' '' hhh '' '' \"a b c\"",
|
|
+ STRV_MAKE("test",
|
|
+ "a",
|
|
+ "b",
|
|
+ "c",
|
|
+ "d",
|
|
+ "e",
|
|
+ "",
|
|
+ "",
|
|
+ "hhh",
|
|
+ "",
|
|
+ "",
|
|
+ "a b c"),
|
|
+ false);
|
|
+
|
|
+ check("test \"xxx",
|
|
+ STRV_MAKE("test"),
|
|
+ true);
|
|
+
|
|
+ check("test\\",
|
|
+ STRV_MAKE_EMPTY,
|
|
+ true);
|
|
}
|
|
|
|
static void test_default_term_for_tty(void) {
|