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;
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);
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));
+}
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)++)
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;
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;
#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",
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);