Brandon Williams <bmwill@xxxxxxxxxx> writes: > @@ -238,6 +238,12 @@ static void prepare_cmd(struct argv_array *out, const struct child_process *cmd) > if (!cmd->argv[0]) > die("BUG: command is empty"); > > + /* > + * Add SHELL_PATH so in the event exec fails with ENOEXEC we can > + * attempt to interpret the command with 'sh'. > + */ > + argv_array_push(out, SHELL_PATH); > + > if (cmd->git_cmd) { > argv_array_push(out, "git"); > argv_array_pushv(out, cmd->argv); So, given "cat-file", "-t", "HEAD" with cmd->git_cmd == TRUE, this will now prepare ("/bin/sh", "git", "cat-file", "-t", "HEAD", NULL) in the argv-array, and then ... > @@ -246,6 +252,20 @@ static void prepare_cmd(struct argv_array *out, const struct child_process *cmd) > } else { > argv_array_pushv(out, cmd->argv); > } > + > + /* > + * If there are no '/' characters in the command then perform a path > + * lookup and use the resolved path as the command to exec. If there > + * are no '/' characters or if the command wasn't found in the path, > + * have exec attempt to invoke the command directly. > + */ > + if (!strchr(out->argv[1], '/')) { > + char *program = locate_in_PATH(out->argv[1]); > + if (program) { > + free((char *)out->argv[1]); > + out->argv[1] = program; > + } > + } ... turn the first element from "git" to "/usr/bin/git", i.e. ("/bin/sh", "/usr/bin/git", "cat-file", "-t", "HEAD", NULL) which ... > #endif > > @@ -445,7 +465,15 @@ int start_command(struct child_process *cmd) > } > } > > - sane_execvp(argv.argv[0], (char *const *) argv.argv); > + /* > + * Attempt to exec using the command and arguments starting at > + * argv.argv[1]. argv.argv[0] contains SHELL_PATH which will > + * be used in the event exec failed with ENOEXEC at which point > + * we will try to interpret the command using 'sh'. > + */ > + execv(argv.argv[1], (char *const *) argv.argv + 1); ... first is given without the leading "/bin/sh", as the end-user intended (sort of), but if it fails > + if (errno == ENOEXEC) > + execv(argv.argv[0], (char *const *) argv.argv); "/bin/sh" tries to run "/usr/bin/git" that was not executable (well, the one in "usr/bin/" would have +x bit, but let's pretend that we are trying to run one from bin-wrappers/ and somehow forgot +x bit)? I think all of that is sensible, but there is one "huh?" I can't figure out. Typically we do "sh -c git cat-file -t HEAD" but this lacks the "-c" (cf. the original prepare_shell_cmd()); why do we not need it in this case? Thanks.