]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Allow braceless variables to be expanded
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 11 Feb 2017 19:05:10 +0000 (14:05 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 21 Feb 2017 04:30:50 +0000 (23:30 -0500)
(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.

man/environment.d.xml
src/basic/env-util.c
src/basic/env-util.h
src/basic/fileio.c
src/test/test-env-util.c
src/test/test-fileio.c

index 4f3e03825a2e3c3b3bcce59c869bf2bd1ba9264d..2302992fa5b461afb235dc85ee7d366c744d131e 100644 (file)
@@ -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>
index 8774a8153114675f0832406dbd9d368d8fbfcb93..f37085467390b6f16093ecdb3c8f596eedf681f4 100644 (file)
@@ -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) {
index 4e83dcb43ab43f7271481d327b28d624f82a4050..03bbc6af008f8dfef3ebf4144a81aee5d7316ef3 100644 (file)
@@ -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);
index 49dd52bfd9ee127858cc1079a581dd907a1f6486..3c2dab18558980c5094c1aba7976c41da0649802 100644 (file)
@@ -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);
 }
 
index f44cb3d57be1efb547f9ccd28424b006463ebf92..77a5219d82e51a41175bb3fbfe604c9605447077 100644 (file)
@@ -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();
index 84f394a7138405a992e40f8328285e0c498ba9ec..c204cbae22b05e89bdaf6ef8daef27a8b5397ec7 100644 (file)
@@ -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) {