summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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) {