From: Junio C Hamano Date: Tue, 11 Sep 2012 18:09:19 +0000 (-0700) Subject: Merge branch 'jc/maint-sane-execvp-notdir' into maint-1.7.11 X-Git-Tag: v1.7.11.6~4 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/91feb387f2cba906a233c3683cfa5ff2bc32d79a?ds=inline;hp=-c Merge branch 'jc/maint-sane-execvp-notdir' into maint-1.7.11 * jc/maint-sane-execvp-notdir: sane_execvp(): ignore non-directory on $PATH --- 91feb387f2cba906a233c3683cfa5ff2bc32d79a diff --combined run-command.c index 606791dc67,f9b7db2385..f9922b9ecc --- a/run-command.c +++ b/run-command.c @@@ -1,70 -1,8 +1,70 @@@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" +#include "sigchain.h" #include "argv-array.h" +#ifndef SHELL_PATH +# define SHELL_PATH "/bin/sh" +#endif + +struct child_to_clean { + pid_t pid; + struct child_to_clean *next; +}; +static struct child_to_clean *children_to_clean; +static int installed_child_cleanup_handler; + +static void cleanup_children(int sig) +{ + while (children_to_clean) { + struct child_to_clean *p = children_to_clean; + children_to_clean = p->next; + kill(p->pid, sig); + free(p); + } +} + +static void cleanup_children_on_signal(int sig) +{ + cleanup_children(sig); + sigchain_pop(sig); + raise(sig); +} + +static void cleanup_children_on_exit(void) +{ + cleanup_children(SIGTERM); +} + +static void mark_child_for_cleanup(pid_t pid) +{ + struct child_to_clean *p = xmalloc(sizeof(*p)); + p->pid = pid; + p->next = children_to_clean; + children_to_clean = p; + + if (!installed_child_cleanup_handler) { + atexit(cleanup_children_on_exit); + sigchain_push_common(cleanup_children_on_signal); + installed_child_cleanup_handler = 1; + } +} + +static void clear_child_for_cleanup(pid_t pid) +{ + struct child_to_clean **last, *p; + + last = &children_to_clean; + for (p = children_to_clean; p; p = p->next) { + if (p->pid == pid) { + *last = p->next; + free(p); + return; + } + } +} + static inline void close_pair(int fd[2]) { close(fd[0]); @@@ -139,6 -77,8 +139,8 @@@ int sane_execvp(const char *file, char */ if (errno == EACCES && !strchr(file, '/')) errno = exists_in_PATH(file) ? EACCES : ENOENT; + else if (errno == ENOTDIR && !strchr(file, '/')) + errno = ENOENT; return -1; } @@@ -156,11 -96,7 +158,11 @@@ static const char **prepare_shell_cmd(c die("BUG: shell command is empty"); if (strcspn(argv[0], "|&;<>()$`\\\"' \t\n*?[#~=%") != strlen(argv[0])) { +#ifndef WIN32 + nargv[nargc++] = SHELL_PATH; +#else nargv[nargc++] = "sh"; +#endif nargv[nargc++] = "-c"; if (argc < 2) @@@ -258,9 -194,6 +260,9 @@@ static int wait_or_whine(pid_t pid, con } else { error("waitpid is confused (%s)", argv0); } + + clear_child_for_cleanup(pid); + errno = failed_errno; return code; } @@@ -423,8 -356,6 +425,8 @@@ fail_pipe if (cmd->pid < 0) error("cannot fork() for %s: %s", cmd->argv[0], strerror(failed_errno = errno)); + else if (cmd->clean_on_exit) + mark_child_for_cleanup(cmd->pid); /* * Wait for child's execvp. If the execvp succeeds (or if fork() @@@ -445,7 -376,6 +447,7 @@@ cmd->pid = -1; } close(notify_pipe[0]); + } #else { @@@ -490,8 -420,6 +492,8 @@@ failed_errno = errno; if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT)) error("cannot spawn %s: %s", cmd->argv[0], strerror(errno)); + if (cmd->clean_on_exit && cmd->pid >= 0) + mark_child_for_cleanup(cmd->pid); if (cmd->env) free_environ(env); @@@ -567,7 -495,6 +569,7 @@@ static void prepare_run_command_v_opt(s cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0; cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0; + cmd->clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0; } int run_command_v_opt(const char **argv, int opt) @@@ -677,8 -604,6 +679,8 @@@ int start_async(struct async *async exit(!!async->proc(proc_in, proc_out, async->data)); } + mark_child_for_cleanup(async->pid); + if (need_in) close(fdin[0]); else if (async->in)