chiark / gitweb /
execute: support minimal environment variable replacement when executing processes
authorLennart Poettering <lennart@poettering.net>
Thu, 8 Jul 2010 02:09:59 +0000 (04:09 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 8 Jul 2010 02:09:59 +0000 (04:09 +0200)
src/execute.c
src/strv.c
src/strv.h
src/util.c
src/util.h

index 138d388..955a3e2 100644 (file)
@@ -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);
index a663696..9dbab29 100644 (file)
@@ -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));
+}
index 0d50b02..8cb35ef 100644 (file)
@@ -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)++)
 
index a01229e..cdfc9e0 100644 (file)
@@ -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",
index ff79583..b29f890 100644 (file)
@@ -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);