summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2017-02-11 14:05:10 -0500
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2017-02-20 23:30:50 -0500
commitccad1fd07ce4eb40a2fcf81cfb55d9b41fdcac48 (patch)
tree41b72c7747d8072e212ed58fd8b5c1e71c18d0b7
parentcb4499d0056a7c974d7d3695cc355c7e77edc938 (diff)
Allow braceless variables to be expanded
(Only in environment.d files.) We have only basic compatibility with shell syntax, but specifying variables without using braces is probably more common, and I think a lot of people would be surprised if this didn't work.
-rw-r--r--man/environment.d.xml4
-rw-r--r--src/basic/env-util.c45
-rw-r--r--src/basic/env-util.h1
-rw-r--r--src/basic/fileio.c7
-rw-r--r--src/test/test-env-util.c31
-rw-r--r--src/test/test-fileio.c14
6 files changed, 91 insertions, 11 deletions
diff --git a/man/environment.d.xml b/man/environment.d.xml
index 4f3e03825a..2302992fa5 100644
--- a/man/environment.d.xml
+++ b/man/environment.d.xml
@@ -78,7 +78,7 @@
<literal><replaceable>KEY</replaceable>=<replaceable>VALUE</replaceable></literal> environment
variable assignments, separated by newlines. The right hand side of these assignments may
reference previously defined environment variables, using the <literal>${OTHER_KEY}</literal>
- format. No other elements of shell syntax are supported.
+ and <literal>$OTHER_KEY</literal> format. No other elements of shell syntax are supported.
</para>
<refsect2>
@@ -91,7 +91,7 @@
</para>
<programlisting>
FOO_DEBUG=force-software-gl,log-verbose
- PATH=/opt/foo/bin:${PATH}
+ PATH=/opt/foo/bin:$PATH
LD_LIBRARY_PATH=/opt/foo/lib
XDG_DATA_DIRS=/opt/foo/share:${XDG_DATA_DIRS}
</programlisting>
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 8774a81531..f370854673 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -523,7 +523,8 @@ char *replace_env(const char *format, char **env, unsigned flags) {
enum {
WORD,
CURLY,
- VARIABLE
+ VARIABLE,
+ VARIABLE_RAW,
} state = WORD;
const char *e, *word = format;
@@ -563,6 +564,18 @@ char *replace_env(const char *format, char **env, unsigned flags) {
word = e+1;
state = WORD;
+
+ } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
+ k = strnappend(r, word, e-word-1);
+ if (!k)
+ return NULL;
+
+ free(r);
+ r = k;
+
+ word = e-1;
+ state = VARIABLE_RAW;
+
} else
state = WORD;
break;
@@ -584,10 +597,38 @@ char *replace_env(const char *format, char **env, unsigned flags) {
state = WORD;
}
break;
+
+ case VARIABLE_RAW:
+ assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
+
+ if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
+ const char *t;
+
+ t = strv_env_get_n(env, word+1, e-word-1, flags);
+
+ k = strappend(r, t);
+ if (!k)
+ return NULL;
+
+ free(r);
+ r = k;
+
+ word = e--;
+ state = WORD;
+ }
+ break;
}
}
- return strnappend(r, word, e-word);
+ if (state == VARIABLE_RAW) {
+ const char *t;
+
+ assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
+
+ t = strv_env_get_n(env, word+1, e-word-1, flags);
+ return strappend(r, t);
+ } else
+ return strnappend(r, word, e-word);
}
char **replace_env_argv(char **argv, char **env) {
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index 4e83dcb43a..03bbc6af00 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -31,6 +31,7 @@ bool env_assignment_is_valid(const char *e);
enum {
REPLACE_ENV_USE_ENVIRONMENT = 1u,
+ REPLACE_ENV_ALLOW_BRACELESS = 2u,
};
char *replace_env(const char *format, char **env, unsigned flags);
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 49dd52bfd9..3c2dab1855 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -773,7 +773,8 @@ static int merge_env_file_push(
assert(env);
- expanded_value = replace_env(value, *env, REPLACE_ENV_USE_ENVIRONMENT);
+ expanded_value = replace_env(value, *env,
+ REPLACE_ENV_USE_ENVIRONMENT|REPLACE_ENV_ALLOW_BRACELESS);
if (!expanded_value)
return -ENOMEM;
@@ -787,6 +788,10 @@ int merge_env_file(
FILE *f,
const char *fname) {
+ /* NOTE: this function supports braceful and braceless variable expansions,
+ * unlike other exported parsing functions.
+ */
+
return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL);
}
diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c
index f44cb3d57b..77a5219d82 100644
--- a/src/test/test-env-util.c
+++ b/src/test/test-env-util.c
@@ -142,7 +142,32 @@ static void test_env_strv_get_n(void) {
getenv("PATH")));
}
-static void test_replace_env_arg(void) {
+static void test_replace_env(bool braceless) {
+ const char *env[] = {
+ "FOO=BAR BAR",
+ "BAR=waldo",
+ NULL
+ };
+ _cleanup_free_ char *t = NULL, *s = NULL, *q = NULL, *r = NULL, *p = NULL;
+ unsigned flags = REPLACE_ENV_ALLOW_BRACELESS*braceless;
+
+ t = replace_env("FOO=$FOO=${FOO}", (char**) env, flags);
+ assert_se(streq(t, braceless ? "FOO=BAR BAR=BAR BAR" : "FOO=$FOO=BAR BAR"));
+
+ s = replace_env("BAR=$BAR=${BAR}", (char**) env, flags);
+ assert_se(streq(s, braceless ? "BAR=waldo=waldo" : "BAR=$BAR=waldo"));
+
+ q = replace_env("BARBAR=$BARBAR=${BARBAR}", (char**) env, flags);
+ assert_se(streq(q, braceless ? "BARBAR==" : "BARBAR=$BARBAR="));
+
+ q = replace_env("BAR=$BAR$BAR${BAR}${BAR}", (char**) env, flags);
+ assert_se(streq(q, braceless ? "BAR=waldowaldowaldowaldo" : "BAR=$BAR$BARwaldowaldo"));
+
+ p = replace_env("${BAR}$BAR$BAR", (char**) env, flags);
+ assert_se(streq(p, braceless ? "waldowaldowaldo" : "waldo$BAR$BAR"));
+}
+
+static void test_replace_env_argv(void) {
const char *env[] = {
"FOO=BAR BAR",
"BAR=waldo",
@@ -256,7 +281,9 @@ int main(int argc, char *argv[]) {
test_strv_env_set();
test_strv_env_merge();
test_env_strv_get_n();
- test_replace_env_arg();
+ test_replace_env(false);
+ test_replace_env(true);
+ test_replace_env_argv();
test_env_clean();
test_env_name_is_valid();
test_env_value_is_valid();
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index 84f394a713..c204cbae22 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -226,7 +226,10 @@ static void test_merge_env_file(void) {
"twelve=${one}2\n"
"twentyone=2${one}\n"
"one=2\n"
- "twentytwo=2${one}\n", false);
+ "twentytwo=2${one}\n"
+ "xxx_minus_three=$xxx - 3\n"
+ "xxx=0x$one$one$one\n"
+ , false);
assert(r >= 0);
r = merge_env_file(&a, NULL, t);
@@ -240,8 +243,9 @@ static void test_merge_env_file(void) {
assert_se(streq(a[1], "twelve=12"));
assert_se(streq(a[2], "twentyone=21"));
assert_se(streq(a[3], "twentytwo=22"));
- assert_se(a[4] == NULL);
-
+ assert_se(streq(a[4], "xxx=0x222"));
+ assert_se(streq(a[5], "xxx_minus_three= - 3"));
+ assert_se(a[6] == NULL);
r = merge_env_file(&a, NULL, t);
assert_se(r >= 0);
@@ -254,7 +258,9 @@ static void test_merge_env_file(void) {
assert_se(streq(a[1], "twelve=12"));
assert_se(streq(a[2], "twentyone=21"));
assert_se(streq(a[3], "twentytwo=22"));
- assert_se(a[4] == NULL);
+ assert_se(streq(a[4], "xxx=0x222"));
+ assert_se(streq(a[5], "xxx_minus_three=0x222 - 3"));
+ assert_se(a[6] == NULL);
}
static void test_executable_is_script(void) {