summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-04-09 18:32:21 +0200
committerLennart Poettering <lennart@poettering.net>2015-04-09 18:32:21 +0200
commit019c7fba754f74909bdb8bbbbbbe529082928a95 (patch)
tree9b53a83d39a2b128e46065625fb6a298942e90f8 /src
parentab51b943d42eb6a5e4c6e26cd3c641d4e604bd1c (diff)
util: add shell_maybe_quote() call for preparing a string for shell cmdline inclusion
If necessary the passed string is enclosed in "", and all special characters escapes. This also ports over usage in bus-util.c and job.c to use this, instead of a incorrect local implementation that forgets to properly escape.
Diffstat (limited to 'src')
-rw-r--r--src/core/job.c8
-rw-r--r--src/libsystemd/sd-bus/bus-util.c15
-rw-r--r--src/shared/util.c45
-rw-r--r--src/shared/util.h2
-rw-r--r--src/test/test-util.c19
5 files changed, 74 insertions, 15 deletions
diff --git a/src/core/job.c b/src/core/job.c
index bd63eb16ba..0230f9316b 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -674,15 +674,13 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
break;
case JOB_FAILED: {
- bool quotes;
+ _cleanup_free_ char *quoted = NULL;
- quotes = chars_intersect(u->id, SHELL_NEED_QUOTES);
+ quoted = shell_maybe_quote(u->id);
manager_flip_auto_status(u->manager, true);
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
- "See \"systemctl status %s%s%s\" for details.",
- quotes ? "'" : "", u->id, quotes ? "'" : "");
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
break;
}
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 6498769260..45882abaad 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -1735,16 +1735,15 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) {
else if (streq(d->result, "unsupported"))
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
- if (d->name) {
- bool quotes;
+ _cleanup_free_ char *quoted = NULL;
- quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
+ if (d->name)
+ quoted = shell_maybe_quote(d->name);
- log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
- d->name,
- quotes ? "'" : "", d->name, quotes ? "'" : "");
- } else
- log_error("Job failed. See \"journalctl -xe\" for details.");
+ if (quoted)
+ log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xe' for details.", d->name, quoted);
+ else
+ log_error("Job failed. See 'journalctl -xe' for details.");
}
}
diff --git a/src/shared/util.c b/src/shared/util.c
index da75667c80..3a80f264ca 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -1332,7 +1332,8 @@ char *cescape(const char *s) {
assert(s);
- /* Does C style string escaping. */
+ /* Does C style string escaping. May be be reversed with
+ * cunescape(). */
r = new(char, strlen(s)*4 + 1);
if (!r)
@@ -1542,7 +1543,7 @@ char *xescape(const char *s, const char *bad) {
/* Escapes all chars in bad, in addition to \ and all special
* chars, in \xFF style escaping. May be reversed with
- * cunescape. */
+ * cunescape(). */
r = new(char, strlen(s) * 4 + 1);
if (!r)
@@ -8035,3 +8036,43 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
+
+char *shell_maybe_quote(const char *s) {
+ const char *p;
+ char *r, *t;
+
+ assert(s);
+
+ /* Encloses a string in double quotes if necessary to make it
+ * OK as shell string. */
+
+ for (p = s; *p; p++)
+ if (*p <= ' ' ||
+ *p >= 127 ||
+ strchr(SHELL_NEED_QUOTES, *p))
+ break;
+
+ if (!*p)
+ return strdup(s);
+
+ r = new(char, 1+strlen(s)*2+1+1);
+ if (!r)
+ return NULL;
+
+ t = r;
+ *(t++) = '"';
+ t = mempcpy(t, s, p - s);
+
+ for (; *p; p++) {
+
+ if (strchr(SHELL_NEED_ESCAPE, *p))
+ *(t++) = '\\';
+
+ *(t++) = *p;
+ }
+
+ *(t++)= '"';
+ *t = 0;
+
+ return r;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index b41090bf70..737a3f3280 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -1090,3 +1090,5 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility);
void cmsg_close_all(struct msghdr *mh);
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+
+char *shell_maybe_quote(const char *s);
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 052e292a6c..f1403fa393 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -1542,6 +1542,24 @@ static void test_sparse_write(void) {
test_sparse_write_one(fd, test_e, sizeof(test_e));
}
+static void test_shell_maybe_quote_one(const char *s, const char *expected) {
+ _cleanup_free_ char *r;
+
+ assert_se(r = shell_maybe_quote(s));
+ assert_se(streq(r, expected));
+}
+
+static void test_shell_maybe_quote(void) {
+
+ test_shell_maybe_quote_one("", "");
+ test_shell_maybe_quote_one("\\", "\"\\\\\"");
+ test_shell_maybe_quote_one("\"", "\"\\\"\"");
+ test_shell_maybe_quote_one("foobar", "foobar");
+ test_shell_maybe_quote_one("foo bar", "\"foo bar\"");
+ test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\"");
+ test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -1619,6 +1637,7 @@ int main(int argc, char *argv[]) {
test_same_fd();
test_uid_ptr();
test_sparse_write();
+ test_shell_maybe_quote();
return 0;
}