|
|
1ff636 |
From 32b4631e74262e02094c6402d39d1e4264442037 Mon Sep 17 00:00:00 2001
|
|
|
1ff636 |
From: Lennart Poettering <lennart@poettering.net>
|
|
|
1ff636 |
Date: Thu, 9 Apr 2015 18:32:21 +0200
|
|
|
1ff636 |
Subject: [PATCH] util: add shell_maybe_quote() call for preparing a string for
|
|
|
1ff636 |
shell cmdline inclusion
|
|
|
1ff636 |
|
|
|
1ff636 |
If necessary the passed string is enclosed in "", and all special
|
|
|
1ff636 |
characters escapes.
|
|
|
1ff636 |
|
|
|
1ff636 |
This also ports over usage in bus-util.c and job.c to use this, instead
|
|
|
1ff636 |
of a incorrect local implementation that forgets to properly escape.
|
|
|
1ff636 |
|
|
|
1ff636 |
Conflicts:
|
|
|
1ff636 |
src/shared/util.c
|
|
|
1ff636 |
src/shared/util.h
|
|
|
1ff636 |
|
|
|
1ff636 |
Cherry-picked from: 019c7fba
|
|
|
1ff636 |
Resolves: #1016680
|
|
|
1ff636 |
---
|
|
|
1ff636 |
src/core/job.c | 8 +++----
|
|
|
1ff636 |
src/libsystemd/sd-bus/bus-util.c | 15 +++++++-------
|
|
|
1ff636 |
src/shared/util.c | 45 ++++++++++++++++++++++++++++++++++++++--
|
|
|
1ff636 |
src/shared/util.h | 2 ++
|
|
|
1ff636 |
src/test/test-util.c | 19 +++++++++++++++++
|
|
|
1ff636 |
5 files changed, 74 insertions(+), 15 deletions(-)
|
|
|
1ff636 |
|
|
|
1ff636 |
diff --git a/src/core/job.c b/src/core/job.c
|
|
|
1ff636 |
index 4740ff1..7416386 100644
|
|
|
1ff636 |
--- a/src/core/job.c
|
|
|
1ff636 |
+++ b/src/core/job.c
|
|
|
1ff636 |
@@ -679,15 +679,13 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
|
|
|
1ff636 |
break;
|
|
|
1ff636 |
|
|
|
1ff636 |
case JOB_FAILED: {
|
|
|
1ff636 |
- bool quotes;
|
|
|
1ff636 |
+ _cleanup_free_ char *quoted = NULL;
|
|
|
1ff636 |
|
|
|
1ff636 |
- quotes = chars_intersect(u->id, SHELL_NEED_QUOTES);
|
|
|
1ff636 |
+ quoted = shell_maybe_quote(u->id);
|
|
|
1ff636 |
|
|
|
1ff636 |
manager_flip_auto_status(u->manager, true);
|
|
|
1ff636 |
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
|
|
|
1ff636 |
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
|
|
|
1ff636 |
- "See \"systemctl status %s%s%s\" for details.",
|
|
|
1ff636 |
- quotes ? "'" : "", u->id, quotes ? "'" : "");
|
|
|
1ff636 |
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
|
|
|
1ff636 |
break;
|
|
|
1ff636 |
}
|
|
|
1ff636 |
|
|
|
1ff636 |
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
|
|
|
1ff636 |
index 52d4ebe..b0a5a75 100644
|
|
|
1ff636 |
--- a/src/libsystemd/sd-bus/bus-util.c
|
|
|
1ff636 |
+++ b/src/libsystemd/sd-bus/bus-util.c
|
|
|
1ff636 |
@@ -1709,16 +1709,15 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) {
|
|
|
1ff636 |
else if (streq(d->result, "unsupported"))
|
|
|
1ff636 |
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
|
|
|
1ff636 |
else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
|
|
|
1ff636 |
- if (d->name) {
|
|
|
1ff636 |
- bool quotes;
|
|
|
1ff636 |
+ _cleanup_free_ char *quoted = NULL;
|
|
|
1ff636 |
|
|
|
1ff636 |
- quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
|
|
|
1ff636 |
+ if (d->name)
|
|
|
1ff636 |
+ quoted = shell_maybe_quote(d->name);
|
|
|
1ff636 |
|
|
|
1ff636 |
- log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
|
|
|
1ff636 |
- d->name,
|
|
|
1ff636 |
- quotes ? "'" : "", d->name, quotes ? "'" : "");
|
|
|
1ff636 |
- } else
|
|
|
1ff636 |
- log_error("Job failed. See \"journalctl -xe\" for details.");
|
|
|
1ff636 |
+ if (quoted)
|
|
|
1ff636 |
+ log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xe' for details.", d->name, quoted);
|
|
|
1ff636 |
+ else
|
|
|
1ff636 |
+ log_error("Job failed. See 'journalctl -xe' for details.");
|
|
|
1ff636 |
}
|
|
|
1ff636 |
}
|
|
|
1ff636 |
|
|
|
1ff636 |
diff --git a/src/shared/util.c b/src/shared/util.c
|
|
|
1ff636 |
index 649344d..778c2b0 100644
|
|
|
1ff636 |
--- a/src/shared/util.c
|
|
|
1ff636 |
+++ b/src/shared/util.c
|
|
|
1ff636 |
@@ -1329,7 +1329,8 @@ char *cescape(const char *s) {
|
|
|
1ff636 |
|
|
|
1ff636 |
assert(s);
|
|
|
1ff636 |
|
|
|
1ff636 |
- /* Does C style string escaping. */
|
|
|
1ff636 |
+ /* Does C style string escaping. May be be reversed with
|
|
|
1ff636 |
+ * cunescape(). */
|
|
|
1ff636 |
|
|
|
1ff636 |
r = new(char, strlen(s)*4 + 1);
|
|
|
1ff636 |
if (!r)
|
|
|
1ff636 |
@@ -1493,7 +1494,7 @@ char *xescape(const char *s, const char *bad) {
|
|
|
1ff636 |
|
|
|
1ff636 |
/* Escapes all chars in bad, in addition to \ and all special
|
|
|
1ff636 |
* chars, in \xFF style escaping. May be reversed with
|
|
|
1ff636 |
- * cunescape. */
|
|
|
1ff636 |
+ * cunescape(). */
|
|
|
1ff636 |
|
|
|
1ff636 |
r = new(char, strlen(s) * 4 + 1);
|
|
|
1ff636 |
if (!r)
|
|
|
1ff636 |
@@ -8101,3 +8102,43 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|
|
1ff636 |
|
|
|
1ff636 |
return -1;
|
|
|
1ff636 |
}
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+char *shell_maybe_quote(const char *s) {
|
|
|
1ff636 |
+ const char *p;
|
|
|
1ff636 |
+ char *r, *t;
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ assert(s);
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ /* Encloses a string in double quotes if necessary to make it
|
|
|
1ff636 |
+ * OK as shell string. */
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ for (p = s; *p; p++)
|
|
|
1ff636 |
+ if (*p <= ' ' ||
|
|
|
1ff636 |
+ *p >= 127 ||
|
|
|
1ff636 |
+ strchr(SHELL_NEED_QUOTES, *p))
|
|
|
1ff636 |
+ break;
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ if (!*p)
|
|
|
1ff636 |
+ return strdup(s);
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ r = new(char, 1+strlen(s)*2+1+1);
|
|
|
1ff636 |
+ if (!r)
|
|
|
1ff636 |
+ return NULL;
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ t = r;
|
|
|
1ff636 |
+ *(t++) = '"';
|
|
|
1ff636 |
+ t = mempcpy(t, s, p - s);
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ for (; *p; p++) {
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ if (strchr(SHELL_NEED_ESCAPE, *p))
|
|
|
1ff636 |
+ *(t++) = '\\';
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ *(t++) = *p;
|
|
|
1ff636 |
+ }
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ *(t++)= '"';
|
|
|
1ff636 |
+ *t = 0;
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ return r;
|
|
|
1ff636 |
+}
|
|
|
1ff636 |
diff --git a/src/shared/util.h b/src/shared/util.h
|
|
|
1ff636 |
index a83b588..7ecfd85 100644
|
|
|
1ff636 |
--- a/src/shared/util.h
|
|
|
1ff636 |
+++ b/src/shared/util.h
|
|
|
1ff636 |
@@ -1078,3 +1078,5 @@ void sigkill_wait(pid_t *pid);
|
|
|
1ff636 |
#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
|
|
|
1ff636 |
|
|
|
1ff636 |
int syslog_parse_priority(const char **p, int *priority, bool with_facility);
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+char *shell_maybe_quote(const char *s);
|
|
|
1ff636 |
diff --git a/src/test/test-util.c b/src/test/test-util.c
|
|
|
1ff636 |
index 9515a8c..9ae347b 100644
|
|
|
1ff636 |
--- a/src/test/test-util.c
|
|
|
1ff636 |
+++ b/src/test/test-util.c
|
|
|
1ff636 |
@@ -1512,6 +1512,24 @@ static void test_sparse_write(void) {
|
|
|
1ff636 |
test_sparse_write_one(fd, test_e, sizeof(test_e));
|
|
|
1ff636 |
}
|
|
|
1ff636 |
|
|
|
1ff636 |
+static void test_shell_maybe_quote_one(const char *s, const char *expected) {
|
|
|
1ff636 |
+ _cleanup_free_ char *r;
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ assert_se(r = shell_maybe_quote(s));
|
|
|
1ff636 |
+ assert_se(streq(r, expected));
|
|
|
1ff636 |
+}
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+static void test_shell_maybe_quote(void) {
|
|
|
1ff636 |
+
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("", "");
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("\\", "\"\\\\\"");
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("\"", "\"\\\"\"");
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("foobar", "foobar");
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("foo bar", "\"foo bar\"");
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\"");
|
|
|
1ff636 |
+ test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
|
|
|
1ff636 |
+}
|
|
|
1ff636 |
+
|
|
|
1ff636 |
int main(int argc, char *argv[]) {
|
|
|
1ff636 |
log_parse_environment();
|
|
|
1ff636 |
log_open();
|
|
|
1ff636 |
@@ -1589,6 +1607,7 @@ int main(int argc, char *argv[]) {
|
|
|
1ff636 |
test_same_fd();
|
|
|
1ff636 |
test_uid_ptr();
|
|
|
1ff636 |
test_sparse_write();
|
|
|
1ff636 |
+ test_shell_maybe_quote();
|
|
|
1ff636 |
|
|
|
1ff636 |
return 0;
|
|
|
1ff636 |
}
|