From: Junio C Hamano Date: Sat, 15 Sep 2012 04:39:37 +0000 (-0700) Subject: Merge branch 'dg/run-command-child-cleanup' X-Git-Tag: v1.8.0-rc0~52 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/5816cc7ca14c476ab34142eb05b817df9a7240cf?ds=inline;hp=-c Merge branch 'dg/run-command-child-cleanup' The code to wait for subprocess and remove it from our internal queue wasn't quite right. * dg/run-command-child-cleanup: run-command.c: fix broken list iteration in clear_child_for_cleanup --- 5816cc7ca14c476ab34142eb05b817df9a7240cf diff --combined run-command.c index f9922b9ecc,d1d58d3e21..1101ef7237 --- a/run-command.c +++ b/run-command.c @@@ -4,10 -4,6 +4,10 @@@ #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; @@@ -53,13 -49,14 +53,14 @@@ static void mark_child_for_cleanup(pid_ static void clear_child_for_cleanup(pid_t pid) { - struct child_to_clean **last, *p; + struct child_to_clean **pp; - last = &children_to_clean; - for (p = children_to_clean; p; p = p->next) { - if (p->pid == pid) { - *last = p->next; - free(p); + for (pp = &children_to_clean; *pp; pp = &(*pp)->next) { + struct child_to_clean *clean_me = *pp; + + if (clean_me->pid == pid) { + *pp = clean_me->next; + free(clean_me); return; } } @@@ -80,70 -77,6 +81,70 @@@ static inline void dup_devnull(int to } #endif +static char *locate_in_PATH(const char *file) +{ + const char *p = getenv("PATH"); + struct strbuf buf = STRBUF_INIT; + + if (!p || !*p) + return NULL; + + while (1) { + const char *end = strchrnul(p, ':'); + + strbuf_reset(&buf); + + /* POSIX specifies an empty entry as the current directory. */ + if (end != p) { + strbuf_add(&buf, p, end - p); + strbuf_addch(&buf, '/'); + } + strbuf_addstr(&buf, file); + + if (!access(buf.buf, F_OK)) + return strbuf_detach(&buf, NULL); + + if (!*end) + break; + p = end + 1; + } + + strbuf_release(&buf); + return NULL; +} + +static int exists_in_PATH(const char *file) +{ + char *r = locate_in_PATH(file); + free(r); + return r != NULL; +} + +int sane_execvp(const char *file, char * const argv[]) +{ + if (!execvp(file, argv)) + return 0; /* cannot happen ;-) */ + + /* + * When a command can't be found because one of the directories + * listed in $PATH is unsearchable, execvp reports EACCES, but + * careful usability testing (read: analysis of occasional bug + * reports) reveals that "No such file or directory" is more + * intuitive. + * + * We avoid commands with "/", because execvp will not do $PATH + * lookups in that case. + * + * The reassignment of EACCES to errno looks like a no-op below, + * but we need to protect against exists_in_PATH overwriting errno. + */ + if (errno == EACCES && !strchr(file, '/')) + errno = exists_in_PATH(file) ? EACCES : ENOENT; + else if (errno == ENOTDIR && !strchr(file, '/')) + errno = ENOENT; + return -1; +} + static const char **prepare_shell_cmd(const char **argv) { int argc, nargc = 0; @@@ -158,11 -91,7 +159,11 @@@ 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) @@@ -186,7 -115,7 +187,7 @@@ static int execv_shell_cmd(const char * { const char **nargv = prepare_shell_cmd(argv); trace_argv_printf(nargv, "trace: exec:"); - execvp(nargv[0], (char **)nargv); + sane_execvp(nargv[0], (char **)nargv); free(nargv); return -1; } @@@ -411,7 -340,7 +412,7 @@@ fail_pipe } else if (cmd->use_shell) { execv_shell_cmd(cmd->argv); } else { - execvp(cmd->argv[0], (char *const*) cmd->argv); + sane_execvp(cmd->argv[0], (char *const*) cmd->argv); } if (errno == ENOENT) { if (!cmd->silent_exec_failure) @@@ -569,7 -498,6 +570,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)