return out->argv;
}
-#ifndef GIT_WINDOWS_NATIVE
-static int execv_shell_cmd(const char **argv)
-{
- struct argv_array nargv = ARGV_ARRAY_INIT;
- prepare_shell_cmd(&nargv, argv);
- trace_argv_printf(nargv.argv, "trace: exec:");
- sane_execvp(nargv.argv[0], (char **)nargv.argv);
- argv_array_clear(&nargv);
- return -1;
-}
-#endif
-
#ifndef GIT_WINDOWS_NATIVE
static int child_notifier = -1;
*/
xwrite(child_notifier, "", 1);
}
+
+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);
+ } else if (cmd->use_shell) {
+ prepare_shell_cmd(out, cmd->argv);
+ } 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;
+ }
+ }
+}
#endif
static inline void set_cloexec(int fd)
#ifndef GIT_WINDOWS_NATIVE
{
int notify_pipe[2];
+ struct argv_array argv = ARGV_ARRAY_INIT;
+
if (pipe(notify_pipe))
notify_pipe[0] = notify_pipe[1] = -1;
+ prepare_cmd(&argv, cmd);
+
cmd->pid = fork();
failed_errno = errno;
if (!cmd->pid) {
unsetenv(*cmd->env);
}
}
- if (cmd->git_cmd)
- execv_git_cmd(cmd->argv);
- else if (cmd->use_shell)
- execv_shell_cmd(cmd->argv);
- else
- sane_execvp(cmd->argv[0], (char *const*) cmd->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);
+ if (errno == ENOEXEC)
+ execv(argv.argv[0], (char *const *) argv.argv);
+
if (errno == ENOENT) {
if (!cmd->silent_exec_failure)
error("cannot run %s: %s", cmd->argv[0],
mark_child_for_cleanup(cmd->pid, cmd);
/*
- * Wait for child's execvp. If the execvp succeeds (or if fork()
+ * Wait for child's exec. If the exec succeeds (or if fork()
* failed), EOF is seen immediately by the parent. Otherwise, the
* child process sends a single byte.
* Note that use of this infrastructure is completely advisory,
close(notify_pipe[1]);
if (read(notify_pipe[0], ¬ify_pipe[1], 1) == 1) {
/*
- * At this point we know that fork() succeeded, but execvp()
+ * At this point we know that fork() succeeded, but exec()
* failed. Errors have been reported to our stderr.
*/
wait_or_whine(cmd->pid, cmd->argv[0], 0);
cmd->pid = -1;
}
close(notify_pipe[0]);
+
+ argv_array_clear(&argv);
}
#else
{