Use "dollar-single-quotes" to escape shell-sensitive strings

Also called "ANSI-C Quoting" in info:(bash) ANSI-C Quoting.

The escaping rules are a POSIX proposal, and are described in
http://austingroupbugs.net/view.php?id=249. There's a lot of back-and-forth on
the details of escaping of control characters, but we'll be only using a small
subset of the syntax that is common to all proposals and is widely supported.
Unfortunately dash and fish and maybe some other shells do not support it (see
the man page patch for a list).

This allows environment variables to be safely exported using show-environment
and imported into the shell. Shells which do not support this syntax will have
to do something like
    export $(systemctl show-environment|grep -v '=\$')
or whatever is appropriate in their case. I think csh and fish do not support
the A=B syntax anyway, so the change is moot for them.

Fixes #5536.

v2:
- also escape newlines (which currently disallowed in shell values, so this
  doesn't really matter), and tabs (as $'\t'), and ! (as $'!'). This way quoted
  output can be included directly in both interactive and noninteractive bash.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2017-06-19 19:39:43 -04:00
parent 42d3bf86bb
commit 804ee07c13
8 changed files with 134 additions and 33 deletions
+24 -2
View File
@@ -47,6 +47,7 @@
#include "dropin.h"
#include "efivars.h"
#include "env-util.h"
#include "escape.h"
#include "exit-status.h"
#include "fd-util.h"
#include "fileio.h"
@@ -5573,6 +5574,24 @@ static int reset_failed(int argc, char *argv[], void *userdata) {
return r;
}
static int print_variable(const char *s) {
const char *sep;
_cleanup_free_ char *esc = NULL;
sep = strchr(s, '=');
if (!sep) {
log_error("Invalid environment block");
return -EUCLEAN;
}
esc = shell_maybe_quote(sep + 1, ESCAPE_POSIX);
if (!esc)
return log_oom();
printf("%.*s=%s\n", (int)(sep-s), s, esc);
return 0;
}
static int show_environment(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -5602,8 +5621,11 @@ static int show_environment(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
puts(text);
while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
r = print_variable(text);
if (r < 0)
return r;
}
if (r < 0)
return bus_log_parse_error(r);