summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/env-util.c17
-rw-r--r--src/basic/env-util.h8
-rw-r--r--src/basic/fileio.c28
-rw-r--r--src/basic/fileio.h2
-rw-r--r--src/test/test-env-util.c31
-rw-r--r--src/test/test-fileio.c52
6 files changed, 131 insertions, 7 deletions
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 86ac07e1b6..99a130008b 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -454,7 +454,7 @@ fail:
return NULL;
}
-char *strv_env_get_n(char **l, const char *name, size_t k) {
+char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
char **i;
assert(name);
@@ -467,13 +467,20 @@ char *strv_env_get_n(char **l, const char *name, size_t k) {
(*i)[k] == '=')
return *i + k + 1;
+ if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
+ const char *t;
+
+ t = strndupa(name, k);
+ return getenv(t);
+ };
+
return NULL;
}
char *strv_env_get(char **l, const char *name) {
assert(name);
- return strv_env_get_n(l, name, strlen(name));
+ return strv_env_get_n(l, name, strlen(name), 0);
}
char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
@@ -512,7 +519,7 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha
return e;
}
-char *replace_env(const char *format, char **env) {
+char *replace_env(const char *format, char **env, unsigned flags) {
enum {
WORD,
CURLY,
@@ -563,7 +570,7 @@ char *replace_env(const char *format, char **env) {
if (*e == '}') {
const char *t;
- t = strv_env_get_n(env, word+2, e-word-2);
+ t = strv_env_get_n(env, word+2, e-word-2, flags);
k = strappend(r, t);
if (!k)
@@ -643,7 +650,7 @@ char **replace_env_argv(char **argv, char **env) {
}
/* If ${FOO} appears as part of a word, replace it by the variable as-is */
- ret[k] = replace_env(*i, env);
+ ret[k] = replace_env(*i, env, 0);
if (!ret[k]) {
strv_free(ret);
return NULL;
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index 90df5b1cd9..4e83dcb43a 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -29,7 +29,11 @@ bool env_name_is_valid(const char *e);
bool env_value_is_valid(const char *e);
bool env_assignment_is_valid(const char *e);
-char *replace_env(const char *format, char **env);
+enum {
+ REPLACE_ENV_USE_ENVIRONMENT = 1u,
+};
+
+char *replace_env(const char *format, char **env, unsigned flags);
char **replace_env_argv(char **argv, char **env);
bool strv_env_is_valid(char **e);
@@ -47,7 +51,7 @@ char **strv_env_unset(char **l, const char *p); /* In place ... */
char **strv_env_unset_many(char **l, ...) _sentinel_;
int strv_env_replace(char ***l, char *p); /* In place ... */
-char *strv_env_get_n(char **l, const char *name, size_t k) _pure_;
+char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_;
char *strv_env_get(char **x, const char *n) _pure_;
int getenv_bool(const char *p);
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index a1e4978125..49dd52bfd9 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -762,6 +762,34 @@ int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char **
return 0;
}
+static int merge_env_file_push(
+ const char *filename, unsigned line,
+ const char *key, char *value,
+ void *userdata,
+ int *n_pushed) {
+
+ char ***env = userdata;
+ char *expanded_value;
+
+ assert(env);
+
+ expanded_value = replace_env(value, *env, REPLACE_ENV_USE_ENVIRONMENT);
+ if (!expanded_value)
+ return -ENOMEM;
+
+ free_and_replace(value, expanded_value);
+
+ return load_env_file_push(filename, line, key, value, env, n_pushed);
+}
+
+int merge_env_file(
+ char ***env,
+ FILE *f,
+ const char *fname) {
+
+ return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL);
+}
+
static void write_env_var(FILE *f, const char *v) {
const char *p;
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 64852b15a8..e547614cc4 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -48,6 +48,8 @@ int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l);
+int merge_env_file(char ***env, FILE *f, const char *fname);
+
int write_env_file(const char *fname, char **l);
int executable_is_script(const char *path, char **interpreter);
diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c
index e004c518fb..f44cb3d57b 100644
--- a/src/test/test-env-util.c
+++ b/src/test/test-env-util.c
@@ -112,6 +112,36 @@ static void test_strv_env_merge(void) {
assert_se(strv_length(r) == 5);
}
+static void test_env_strv_get_n(void) {
+ const char *_env[] = {
+ "FOO=NO NO NO",
+ "FOO=BAR BAR",
+ "BAR=waldo",
+ "PATH=unset",
+ NULL
+ };
+ char **env = (char**) _env;
+
+ assert_se(streq(strv_env_get_n(env, "FOO__", 3, 0), "BAR BAR"));
+ assert_se(streq(strv_env_get_n(env, "FOO__", 3, REPLACE_ENV_USE_ENVIRONMENT), "BAR BAR"));
+ assert_se(streq(strv_env_get_n(env, "FOO", 3, 0), "BAR BAR"));
+ assert_se(streq(strv_env_get_n(env, "FOO", 3, REPLACE_ENV_USE_ENVIRONMENT), "BAR BAR"));
+
+ assert_se(streq(strv_env_get_n(env, "PATH__", 4, 0), "unset"));
+ assert_se(streq(strv_env_get_n(env, "PATH", 4, 0), "unset"));
+ assert_se(streq(strv_env_get_n(env, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT), "unset"));
+ assert_se(streq(strv_env_get_n(env, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT), "unset"));
+
+ env[3] = NULL; /* kill our $PATH */
+
+ assert_se(!strv_env_get_n(env, "PATH__", 4, 0));
+ assert_se(!strv_env_get_n(env, "PATH", 4, 0));
+ assert_se(streq(strv_env_get_n(env, "PATH__", 4, REPLACE_ENV_USE_ENVIRONMENT),
+ getenv("PATH")));
+ assert_se(streq(strv_env_get_n(env, "PATH", 4, REPLACE_ENV_USE_ENVIRONMENT),
+ getenv("PATH")));
+}
+
static void test_replace_env_arg(void) {
const char *env[] = {
"FOO=BAR BAR",
@@ -225,6 +255,7 @@ int main(int argc, char *argv[]) {
test_strv_env_unset();
test_strv_env_set();
test_strv_env_merge();
+ test_env_strv_get_n();
test_replace_env_arg();
test_env_clean();
test_env_name_is_valid();
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index a38bb874a9..84f394a713 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -206,6 +206,56 @@ static void test_parse_multiline_env_file(void) {
unlink(p);
}
+static void test_merge_env_file(void) {
+ char t[] = "/tmp/test-fileio-XXXXXX";
+ int fd, r;
+ FILE *f;
+ _cleanup_strv_free_ char **a = NULL;
+ char **i;
+
+ fd = mkostemp_safe(t);
+ assert_se(fd >= 0);
+
+ log_info("/* %s (%s) */", __func__, t);
+
+ f = fdopen(fd, "w");
+ assert_se(f);
+
+ r = write_string_stream(f,
+ "one=1 \n"
+ "twelve=${one}2\n"
+ "twentyone=2${one}\n"
+ "one=2\n"
+ "twentytwo=2${one}\n", false);
+ assert(r >= 0);
+
+ r = merge_env_file(&a, NULL, t);
+ assert_se(r >= 0);
+ strv_sort(a);
+
+ STRV_FOREACH(i, a)
+ log_info("Got: <%s>", *i);
+
+ assert_se(streq(a[0], "one=2"));
+ 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);
+
+
+ r = merge_env_file(&a, NULL, t);
+ assert_se(r >= 0);
+ strv_sort(a);
+
+ STRV_FOREACH(i, a)
+ log_info("Got2: <%s>", *i);
+
+ assert_se(streq(a[0], "one=2"));
+ 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);
+}
static void test_executable_is_script(void) {
char t[] = "/tmp/test-executable-XXXXXX";
@@ -557,11 +607,13 @@ static void test_tempfn(void) {
}
int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
test_parse_env_file();
test_parse_multiline_env_file();
+ test_merge_env_file();
test_executable_is_script();
test_status_field();
test_capeff();