| -rw-r--r-- | shared.c | 66 |
1 files changed, 56 insertions, 10 deletions
@@ -383,7 +383,7 @@ typedef struct { char * value; } cgit_env_var; -static void prepare_env(struct cgit_repo * repo) { +static char * prepare_env(struct cgit_repo * repo) { cgit_env_var env_vars[] = { { .name = "CGIT_REPO_URL", .value = repo->url }, { .name = "CGIT_REPO_NAME", .value = repo->name }, @@ -394,14 +394,52 @@ static void prepare_env(struct cgit_repo * repo) { { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url } }; int env_var_count = ARRAY_SIZE(env_vars); - cgit_env_var *p, *q; - static char *warn = "cgit warning: failed to set env: %s=%s\n"; + long values_space = (env_var_count * (PATH_MAX + 64)); - p = env_vars; - q = p + env_var_count; - for (; p < q; p++) - if (setenv(p->name, p->value, 1)) - fprintf(stderr, warn, p->name, p->value); + void * buffer; + char ** vars; + char * values; + int vars_index = 0; + unsigned int chars_printed; + + /* Allocate buffer for environment variables: first in the buffer is an + * array of pointers to argument strings, terminated with a NULL pointer. + * After that the argument strings are placed after each other */ + buffer = malloc(((env_var_count + 1) * sizeof(char *)) + values_space); + if (!buffer) + return NULL; + + vars = buffer; + values = (char *) &vars[env_var_count + 1]; + + /* loop over all defined environment variables and their values */ + while (vars_index < env_var_count) { + char * name = env_vars[vars_index].name; + char * value = env_vars[vars_index].value; + + if (!value) + value = ""; + + chars_printed = snprintf(values, (values_space - 1), "%s=%s", name, + value); + if (chars_printed > (values_space - 1)) { + /* Buffer space exhausted: stop adding variables. + * Not all environment variables are defined, but the best we can + * do is to provide the ones that _are_ defined */ + break; + } + + values[chars_printed] = '\0'; + *&vars[vars_index] = values; + values += (chars_printed + 1); + values_space -= (chars_printed + 1); + vars_index++; + } + + /* terminate the array with pointers */ + *&vars[vars_index] = NULL; + + return (char *) buffer; } int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo) @@ -412,12 +450,20 @@ int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo) chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess"); filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); if (filter->pid == 0) { + char * env = NULL; + close(filter->pipe_fh[1]); chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), "Unable to use pipe as STDIN"); + if (repo) - prepare_env(repo); - execvp(filter->cmd, filter->argv); + env = prepare_env(repo); + + execve(filter->cmd, filter->argv, (char **)env); + + if (env) + free(env); + die("Unable to exec subprocess %s: %s (%d)", filter->cmd, strerror(errno), errno); } |