diff options
Diffstat (limited to 'run-command.c')
-rw-r--r-- | run-command.c | 80 |
1 files changed, 63 insertions, 17 deletions
diff --git a/run-command.c b/run-command.c index 761f0fde40..aad03ab705 100644 --- a/run-command.c +++ b/run-command.c @@ -4,14 +4,11 @@ #include "sigchain.h" #include "argv-array.h" -#ifndef SHELL_PATH -# define SHELL_PATH "/bin/sh" -#endif - void child_process_init(struct child_process *child) { memset(child, 0, sizeof(*child)); argv_array_init(&child->args); + argv_array_init(&child->env_array); } struct child_to_clean { @@ -287,6 +284,8 @@ int start_command(struct child_process *cmd) if (!cmd->argv) cmd->argv = cmd->args.argv; + if (!cmd->env) + cmd->env = cmd->env_array.argv; /* * In case of errors we must keep the promise to close FDs @@ -338,6 +337,7 @@ fail_pipe: error("cannot create %s pipe for %s: %s", str, cmd->argv[0], strerror(failed_errno)); argv_array_clear(&cmd->args); + argv_array_clear(&cmd->env_array); errno = failed_errno; return -1; } @@ -524,6 +524,7 @@ fail_pipe: else if (cmd->err) close(cmd->err); argv_array_clear(&cmd->args); + argv_array_clear(&cmd->env_array); errno = failed_errno; return -1; } @@ -550,12 +551,18 @@ int finish_command(struct child_process *cmd) { int ret = wait_or_whine(cmd->pid, cmd->argv[0]); argv_array_clear(&cmd->args); + argv_array_clear(&cmd->env_array); return ret; } int run_command(struct child_process *cmd) { - int code = start_command(cmd); + int code; + + if (cmd->out < 0 || cmd->err < 0) + die("BUG: run_command with a pipe can cause deadlock"); + + code = start_command(cmd); if (code) return code; return finish_command(cmd); @@ -620,6 +627,45 @@ static int async_die_is_recursing(void) return ret != NULL; } +#else + +static struct { + void (**handlers)(void); + size_t nr; + size_t alloc; +} git_atexit_hdlrs; + +static int git_atexit_installed; + +static void git_atexit_dispatch(void) +{ + size_t i; + + for (i=git_atexit_hdlrs.nr ; i ; i--) + git_atexit_hdlrs.handlers[i-1](); +} + +static void git_atexit_clear(void) +{ + free(git_atexit_hdlrs.handlers); + memset(&git_atexit_hdlrs, 0, sizeof(git_atexit_hdlrs)); + git_atexit_installed = 0; +} + +#undef atexit +int git_atexit(void (*handler)(void)) +{ + ALLOC_GROW(git_atexit_hdlrs.handlers, git_atexit_hdlrs.nr + 1, git_atexit_hdlrs.alloc); + git_atexit_hdlrs.handlers[git_atexit_hdlrs.nr++] = handler; + if (!git_atexit_installed) { + if (atexit(&git_atexit_dispatch)) + return -1; + git_atexit_installed = 1; + } + return 0; +} +#define atexit git_atexit + #endif int start_async(struct async *async) @@ -678,6 +724,7 @@ int start_async(struct async *async) close(fdin[1]); if (need_out) close(fdout[0]); + git_atexit_clear(); exit(!!async->proc(proc_in, proc_out, async->data)); } @@ -788,19 +835,18 @@ int run_hook_le(const char *const *env, const char *name, ...) return ret; } -int run_hook_with_custom_index(const char *index_file, const char *name, ...) +int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint) { - const char *hook_env[3] = { NULL }; - char index[PATH_MAX]; - va_list args; - int ret; - - snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); - hook_env[0] = index; + cmd->out = -1; + if (start_command(cmd) < 0) + return -1; - va_start(args, name); - ret = run_hook_ve(hook_env, name, args); - va_end(args); + if (strbuf_read(buf, cmd->out, hint) < 0) { + close(cmd->out); + finish_command(cmd); /* throw away exit code */ + return -1; + } - return ret; + close(cmd->out); + return finish_command(cmd); } |