From: Junio C Hamano Date: Fri, 20 Apr 2012 22:51:18 +0000 (-0700) Subject: Merge branch 'js/spawn-via-shell-path-fix' X-Git-Tag: v1.7.11-rc0~134 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/8cc5223495332f0454aff8e382adbb434c065942?ds=inline;hp=-c Merge branch 'js/spawn-via-shell-path-fix' Mops up an unfortunate fallout from bw/spawn-via-shell-path topic. By Johannes Sixt * js/spawn-via-shell-path-fix: Do not use SHELL_PATH from build system in prepare_shell_cmd on Windows --- 8cc5223495332f0454aff8e382adbb434c065942 diff --combined run-command.c index 5be1b4b5ba,e4edede8b9..606791dc67 --- a/run-command.c +++ b/run-command.c @@@ -80,68 -80,6 +80,68 @@@ 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; + return -1; +} + static const char **prepare_shell_cmd(const char **argv) { int argc, nargc = 0; @@@ -156,7 -94,11 +156,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) @@@ -180,7 -122,7 +184,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; } @@@ -405,7 -347,7 +409,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)