diff options
-rw-r--r-- | src/execute.c | 10 | ||||
-rw-r--r-- | src/strv.c | 17 | ||||
-rw-r--r-- | src/strv.h | 3 | ||||
-rw-r--r-- | src/util.c | 112 | ||||
-rw-r--r-- | src/util.h | 4 |
5 files changed, 141 insertions, 5 deletions
diff --git a/src/execute.c b/src/execute.c index 138d38817f..955a3e2378 100644 --- a/src/execute.c +++ b/src/execute.c @@ -943,7 +943,7 @@ int exec_spawn(ExecCommand *command, const char *username = NULL, *home = NULL; uid_t uid = (uid_t) -1; gid_t gid = (gid_t) -1; - char **our_env = NULL, **pam_env = NULL, **final_env = NULL; + char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; unsigned n_env = 0; int saved_stdout = -1, saved_stdin = -1; bool keep_stdout = false, keep_stdin = false; @@ -1260,13 +1260,19 @@ int exec_spawn(ExecCommand *command, goto fail; } - execve(command->path, argv, final_env); + if (!(final_argv = replace_env_argv(argv, final_env))) { + r = EXIT_MEMORY; + goto fail; + } + + execve(command->path, final_argv, final_env); r = EXIT_EXEC; fail: strv_free(our_env); strv_free(final_env); strv_free(pam_env); + strv_free(final_argv); if (saved_stdin >= 0) close_nointr_nofail(saved_stdin); diff --git a/src/strv.c b/src/strv.c index a66369602b..9dbab2937c 100644 --- a/src/strv.c +++ b/src/strv.c @@ -539,3 +539,20 @@ fail: return NULL; } + +char *strv_env_get_with_length(char **l, const char *name, size_t k) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (strncmp(*i, name, k) == 0 && + (*i)[k] == '=') + return *i + k + 1; + + return NULL; +} + +char *strv_env_get(char **l, const char *name) { + return strv_env_get_with_length(l, name, strlen(name)); +} diff --git a/src/strv.h b/src/strv.h index 0d50b02f01..8cb35ef395 100644 --- a/src/strv.h +++ b/src/strv.h @@ -60,6 +60,9 @@ char **strv_env_delete(char **x, unsigned n_lists, ...); char **strv_env_set(char **x, const char *p); +char *strv_env_get_with_length(char **l, const char *name, size_t k); +char *strv_env_get(char **x, const char *n); + #define STRV_FOREACH(s, l) \ for ((s) = (l); (s) && *(s); (s)++) diff --git a/src/util.c b/src/util.c index a01229e659..cdfc9e0158 100644 --- a/src/util.c +++ b/src/util.c @@ -613,15 +613,23 @@ int get_process_cmdline(pid_t pid, size_t max_length, char **line) { return 0; } -char *strappend(const char *s, const char *suffix) { - size_t a, b; +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; char *r; + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + assert(s); assert(suffix); a = strlen(s); - b = strlen(suffix); if (!(r = new(char, a+b+1))) return NULL; @@ -633,6 +641,10 @@ char *strappend(const char *s, const char *suffix) { return r; } +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + int readlink_malloc(const char *p, char **r) { size_t l = 100; @@ -2692,6 +2704,100 @@ void status_welcome(void) { #endif } +char *replace_env(const char *format, char **env) { + enum { + WORD, + DOLLAR, + VARIABLE + } state = WORD; + + const char *e, *word = format; + char *r = NULL, *k; + + assert(format); + + for (e = format; *e; e ++) { + + switch (state) { + + case WORD: + if (*e == '$') + state = DOLLAR; + break; + + case DOLLAR: + if (*e == '(') { + if (!(k = strnappend(r, word, e-word-1))) + goto fail; + + free(r); + r = k; + + word = e-1; + state = VARIABLE; + + } else if (*e == '$') { + if (!(k = strnappend(r, word, e-word))) + goto fail; + + free(r); + r = k; + + word = e+1; + state = WORD; + } else + state = WORD; + break; + + case VARIABLE: + if (*e == ')') { + char *t; + + if ((t = strv_env_get_with_length(env, word+2, e-word-2))) { + if (!(k = strappend(r, t))) + goto fail; + + free(r); + r = k; + + word = e+1; + } + + state = WORD; + } + break; + } + } + + if (!(k = strnappend(r, word, e-word))) + goto fail; + + free(r); + return k; + +fail: + free(r); + return NULL; +} + +char **replace_env_argv(char **argv, char **env) { + char **r, **i; + unsigned k; + + if (!(r = new(char*, strv_length(argv)+1))) + return NULL; + + STRV_FOREACH(i, argv) { + if (!(r[k++] = replace_env(*i, env))) { + strv_free(r); + return NULL; + } + } + + r[k] = NULL; + return r; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index ff79583d80..b29f890b5f 100644 --- a/src/util.h +++ b/src/util.h @@ -183,6 +183,10 @@ int write_one_line_file(const char *fn, const char *line); int read_one_line_file(const char *fn, char **line); char *strappend(const char *s, const char *suffix); +char *strnappend(const char *s, const char *suffix, size_t length); + +char *replace_env(const char *format, char **env); +char **replace_env_argv(char **argv, char **env); int readlink_malloc(const char *p, char **r); int readlink_and_make_absolute(const char *p, char **r); |