int start_async(struct async *async) { int pipe_out[2]; if (pipe(pipe_out) < 0) return error("cannot create pipe: %s", strerror(errno)); async->out = pipe_out[0]; #ifndef __MINGW32__ async->pid = fork(); if (async->pid < 0) { error("fork (async) failed: %s", strerror(errno)); close_pair(pipe_out); return -1; } if (!async->pid) { close(pipe_out[0]); exit(!!async->proc(pipe_out[1], async->data)); } close(pipe_out[1]); #else async->fd_for_proc = pipe_out[1]; async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL); if (!async->tid) { error("cannot create thread: %s", strerror(errno)); close_pair(pipe_out); return -1; } #endif return 0; }
static int start_command(struct child_process *cmd) { int need_in; int fdin[2]; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { if (cmd->out > 0) close(cmd->out); return -1; } cmd->in = fdin[1]; } fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { if (need_in) { dup2(fdin[0], 0); close_pair(fdin); } else if (cmd->in > 0) { dup2(cmd->in, 0); close(cmd->in); } cmd->preexec_cb(); execvp(cmd->argv[0], (char *const*) cmd->argv); exit(127); /* cmd not found */ } if (cmd->pid < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); return -1; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); return 0; }
int start_async(struct async *async) { int pipe_out[2]; if (pipe(pipe_out) < 0) return error("cannot create pipe: %s", strerror(errno)); async->out = pipe_out[0]; /* Flush stdio before fork() to avoid cloning buffers */ fflush(NULL); async->pid = fork(); if (async->pid < 0) { error("fork (async) failed: %s", strerror(errno)); close_pair(pipe_out); return -1; } if (!async->pid) { close(pipe_out[0]); exit(!!async->proc(pipe_out[1], async->data)); } close(pipe_out[1]); return 0; }
int start_async(struct async *async) { int need_in, need_out; int fdin[2], fdout[2]; int proc_in, proc_out; need_in = async->in < 0; if (need_in) { if (pipe(fdin) < 0) { if (async->out > 0) close(async->out); return error("cannot create pipe: %s", strerror(errno)); } async->in = fdin[1]; } need_out = async->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); else if (async->in) close(async->in); return error("cannot create pipe: %s", strerror(errno)); } async->out = fdout[0]; } if (need_in) proc_in = fdin[0]; else if (async->in) proc_in = async->in; else proc_in = -1; if (need_out) proc_out = fdout[1]; else if (async->out) proc_out = async->out; else proc_out = -1; #ifdef NO_PTHREADS /* Flush stdio before fork() to avoid cloning buffers */ fflush(NULL); async->pid = fork(); if (async->pid < 0) { error("fork (async) failed: %s", strerror(errno)); goto error; } if (!async->pid) { if (need_in) close(fdin[1]); if (need_out) close(fdout[0]); git_atexit_clear(); process_is_async = 1; 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) close(async->in); if (need_out) close(fdout[1]); else if (async->out) close(async->out); #else if (!main_thread_set) { /* * We assume that the first time that start_async is called * it is from the main thread. */ main_thread_set = 1; main_thread = pthread_self(); pthread_key_create(&async_key, NULL); pthread_key_create(&async_die_counter, NULL); set_die_routine(die_async); set_die_is_recursing_routine(async_die_is_recursing); } if (proc_in >= 0) set_cloexec(proc_in); if (proc_out >= 0) set_cloexec(proc_out); async->proc_in = proc_in; async->proc_out = proc_out; { int err = pthread_create(&async->tid, NULL, run_thread, async); if (err) { error("cannot create thread: %s", strerror(err)); goto error; } } #endif return 0; error: if (need_in) close_pair(fdin); else if (async->in) close(async->in); if (need_out) close_pair(fdout); else if (async->out) close(async->out); return -1; }
int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; int failed_errno; char *str; if (!cmd->argv) cmd->argv = cmd->args.argv; if (!cmd->env) cmd->env = cmd->env_array.argv; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { failed_errno = errno; if (cmd->out > 0) close(cmd->out); str = "standard input"; goto fail_pipe; } cmd->in = fdin[1]; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { failed_errno = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); str = "standard output"; goto fail_pipe; } cmd->out = fdout[0]; } need_err = !cmd->no_stderr && cmd->err < 0; if (need_err) { if (pipe(fderr) < 0) { failed_errno = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); str = "standard error"; fail_pipe: error("cannot create %s pipe for %s: %s", str, cmd->argv[0], strerror(failed_errno)); child_process_clear(cmd); errno = failed_errno; return -1; } cmd->err = fderr[0]; } trace_argv_printf(cmd->argv, "trace: run_command:"); fflush(NULL); #ifndef GIT_WINDOWS_NATIVE { int notify_pipe[2]; if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; cmd->pid = fork(); failed_errno = errno; if (!cmd->pid) { /* * Redirect the channel to write syscall error messages to * before redirecting the process's stderr so that all die() * in subsequent call paths use the parent's stderr. */ if (cmd->no_stderr || need_err) { int child_err = dup(2); set_cloexec(child_err); set_error_handle(fdopen(child_err, "w")); } close(notify_pipe[0]); set_cloexec(notify_pipe[1]); child_notifier = notify_pipe[1]; atexit(notify_parent); if (cmd->no_stdin) dup_devnull(0); else if (need_in) { dup2(fdin[0], 0); close_pair(fdin); } else if (cmd->in) { dup2(cmd->in, 0); close(cmd->in); } if (cmd->no_stderr) dup_devnull(2); else if (need_err) { dup2(fderr[1], 2); close_pair(fderr); } else if (cmd->err > 1) { dup2(cmd->err, 2); close(cmd->err); } if (cmd->no_stdout) dup_devnull(1); else if (cmd->stdout_to_stderr) dup2(2, 1); else if (need_out) { dup2(fdout[1], 1); close_pair(fdout); } else if (cmd->out > 1) { dup2(cmd->out, 1); close(cmd->out); } if (cmd->dir && chdir(cmd->dir)) die_errno("exec '%s': cd to '%s' failed", cmd->argv[0], cmd->dir); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) putenv((char *)*cmd->env); else 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); if (errno == ENOENT) { if (!cmd->silent_exec_failure) error("cannot run %s: %s", cmd->argv[0], strerror(ENOENT)); exit(127); } else { die_errno("cannot exec '%s'", cmd->argv[0]); } } if (cmd->pid < 0) error("cannot fork() for %s: %s", cmd->argv[0], strerror(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() * 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, * therefore, we keep error checks minimal. */ close(notify_pipe[1]); if (read(notify_pipe[0], ¬ify_pipe[1], 1) == 1) { /* * At this point we know that fork() succeeded, but execvp() * failed. Errors have been reported to our stderr. */ wait_or_whine(cmd->pid, cmd->argv[0], 0); failed_errno = errno; cmd->pid = -1; } close(notify_pipe[0]); } #else { int fhin = 0, fhout = 1, fherr = 2; const char **sargv = cmd->argv; struct argv_array nargv = ARGV_ARRAY_INIT; if (cmd->no_stdin) fhin = open("/dev/null", O_RDWR); else if (need_in) fhin = dup(fdin[0]); else if (cmd->in) fhin = dup(cmd->in); if (cmd->no_stderr) fherr = open("/dev/null", O_RDWR); else if (need_err) fherr = dup(fderr[1]); else if (cmd->err > 2) fherr = dup(cmd->err); if (cmd->no_stdout) fhout = open("/dev/null", O_RDWR); else if (cmd->stdout_to_stderr) fhout = dup(fherr); else if (need_out) fhout = dup(fdout[1]); else if (cmd->out > 1) fhout = dup(cmd->out); if (cmd->git_cmd) cmd->argv = prepare_git_cmd(&nargv, cmd->argv); else if (cmd->use_shell) cmd->argv = prepare_shell_cmd(&nargv, cmd->argv); cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env, cmd->dir, fhin, fhout, fherr); 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); argv_array_clear(&nargv); cmd->argv = sargv; if (fhin != 0) close(fhin); if (fhout != 1) close(fhout); if (fherr != 2) close(fherr); } #endif if (cmd->pid < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); if (need_err) close_pair(fderr); else if (cmd->err) close(cmd->err); child_process_clear(cmd); errno = failed_errno; return -1; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); if (need_out) close(fdout[1]); else if (cmd->out) close(cmd->out); if (need_err) close(fderr[1]); else if (cmd->err) close(cmd->err); return 0; }
int start_async(struct async *async) { int need_in, need_out; int fdin[2], fdout[2]; int proc_in, proc_out; need_in = async->in < 0; if (need_in) { if (pipe(fdin) < 0) { if (async->out > 0) close(async->out); return error("cannot create pipe: %s", strerror(errno)); } async->in = fdin[1]; } need_out = async->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); else if (async->in) close(async->in); return error("cannot create pipe: %s", strerror(errno)); } async->out = fdout[0]; } if (need_in) proc_in = fdin[0]; else if (async->in) proc_in = async->in; else proc_in = -1; if (need_out) proc_out = fdout[1]; else if (async->out) proc_out = async->out; else proc_out = -1; #ifndef WIN32 /* Flush stdio before fork() to avoid cloning buffers */ fflush(NULL); async->pid = fork(); if (async->pid < 0) { error("fork (async) failed: %s", strerror(errno)); goto error; } if (!async->pid) { if (need_in) close(fdin[1]); if (need_out) close(fdout[0]); exit(!!async->proc(proc_in, proc_out, async->data)); } if (need_in) close(fdin[0]); else if (async->in) close(async->in); if (need_out) close(fdout[1]); else if (async->out) close(async->out); #else async->proc_in = proc_in; async->proc_out = proc_out; async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL); if (!async->tid) { error("cannot create thread: %s", strerror(errno)); goto error; } #endif return 0; error: if (need_in) close_pair(fdin); else if (async->in) close(async->in); if (need_out) close_pair(fdout); else if (async->out) close(async->out); return -1; }
int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; int failed_errno = failed_errno; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { failed_errno = errno; if (cmd->out > 0) close(cmd->out); goto fail_pipe; } cmd->in = fdin[1]; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { failed_errno = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); goto fail_pipe; } cmd->out = fdout[0]; } need_err = !cmd->no_stderr && cmd->err < 0; if (need_err) { if (pipe(fderr) < 0) { failed_errno = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); fail_pipe: error("cannot create pipe for %s: %s", cmd->argv[0], strerror(failed_errno)); errno = failed_errno; return -1; } cmd->err = fderr[0]; } trace_argv_printf(cmd->argv, "trace: run_command:"); #ifndef WIN32 { int notify_pipe[2]; if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { /* * Redirect the channel to write syscall error messages to * before redirecting the process's stderr so that all die() * in subsequent call paths use the parent's stderr. */ if (cmd->no_stderr || need_err) { child_err = dup(2); set_cloexec(child_err); } set_die_routine(die_child); close(notify_pipe[0]); set_cloexec(notify_pipe[1]); child_notifier = notify_pipe[1]; atexit(notify_parent); if (cmd->no_stdin) dup_devnull(0); else if (need_in) { dup2(fdin[0], 0); close_pair(fdin); } else if (cmd->in) { dup2(cmd->in, 0); close(cmd->in); } if (cmd->no_stderr) dup_devnull(2); else if (need_err) { dup2(fderr[1], 2); close_pair(fderr); } else if (cmd->err > 1) { dup2(cmd->err, 2); close(cmd->err); } if (cmd->no_stdout) dup_devnull(1); else if (cmd->stdout_to_stderr) dup2(2, 1); else if (need_out) { dup2(fdout[1], 1); close_pair(fdout); } else if (cmd->out > 1) { dup2(cmd->out, 1); close(cmd->out); } if (cmd->dir && chdir(cmd->dir)) die_errno("exec '%s': cd to '%s' failed", cmd->argv[0], cmd->dir); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) putenv((char *)*cmd->env); else unsetenv(*cmd->env); } } if (cmd->preexec_cb) { /* * We cannot predict what the pre-exec callback does. * Forgo parent notification. */ close(child_notifier); child_notifier = -1; cmd->preexec_cb(); } if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else if (cmd->use_shell) { execv_shell_cmd(cmd->argv); } else { execvp(cmd->argv[0], (char *const*) cmd->argv); } /* * Do not check for cmd->silent_exec_failure; the parent * process will check it when it sees this exit code. */ if (errno == ENOENT) exit(127); else die_errno("cannot exec '%s'", cmd->argv[0]); } if (cmd->pid < 0) error("cannot fork() for %s: %s", cmd->argv[0], strerror(failed_errno = errno)); /* * Wait for child's execvp. If the execvp 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, * therefore, we keep error checks minimal. */ close(notify_pipe[1]); if (read(notify_pipe[0], ¬ify_pipe[1], 1) == 1) { /* * At this point we know that fork() succeeded, but execvp() * failed. Errors have been reported to our stderr. */ wait_or_whine(cmd->pid, cmd->argv[0], cmd->silent_exec_failure); failed_errno = errno; cmd->pid = -1; } close(notify_pipe[0]); } #else { int fhin = 0, fhout = 1, fherr = 2; const char **sargv = cmd->argv; char **env = environ; if (cmd->no_stdin) fhin = open("/dev/null", O_RDWR); else if (need_in) fhin = dup(fdin[0]); else if (cmd->in) fhin = dup(cmd->in); if (cmd->no_stderr) fherr = open("/dev/null", O_RDWR); else if (need_err) fherr = dup(fderr[1]); else if (cmd->err > 2) fherr = dup(cmd->err); if (cmd->no_stdout) fhout = open("/dev/null", O_RDWR); else if (cmd->stdout_to_stderr) fhout = dup(fherr); else if (need_out) fhout = dup(fdout[1]); else if (cmd->out > 1) fhout = dup(cmd->out); if (cmd->env) env = make_augmented_environ(cmd->env); if (cmd->git_cmd) { cmd->argv = prepare_git_cmd(cmd->argv); } else if (cmd->use_shell) { cmd->argv = prepare_shell_cmd(cmd->argv); } cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir, fhin, fhout, fherr); 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->env) free_environ(env); if (cmd->git_cmd) free(cmd->argv); cmd->argv = sargv; if (fhin != 0) close(fhin); if (fhout != 1) close(fhout); if (fherr != 2) close(fherr); } #endif if (cmd->pid < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); if (need_err) close_pair(fderr); else if (cmd->err) close(cmd->err); errno = failed_errno; return -1; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); if (need_out) close(fdout[1]); else if (cmd->out) close(cmd->out); if (need_err) close(fderr[1]); else if (cmd->err) close(cmd->err); return 0; }
int exec_program_v(const char *working_directory, struct strbuf *output, struct strbuf *error_output, int flags, const char **argv) { int fdout[2], fderr[2]; int s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ pid_t pid; int status = 0; int ret; struct strbuf strout = STRBUF_INIT, strerr = STRBUF_INIT; if (!output) output = &strout; if (!error_output) error_output = &strerr; reporter *debug = QUIETMODE & flags ? _debug_git : _debug_git_mbox; if (!git_path()) { debug("[ERROR] Could not find git path"); return -1; } if (pipe(fdout) < 0) { return -ERR_RUN_COMMAND_PIPE; } s1 = dup(1); dup2(fdout[1], 1); flags |= WAITMODE; if (pipe(fderr) < 0) { if (output) close_pair(fdout); return -ERR_RUN_COMMAND_PIPE; } s2 = dup(2); dup2(fderr[1], 2); flags |= WAITMODE; pid = fork_process(argv[0], argv, working_directory); if (s1 >= 0) dup2(s1, 1), close(s1); if (s2 >= 0) dup2(s2, 2), close(s2); if (pid < 0) { close_pair(fdout); close_pair(fderr); return -ERR_RUN_COMMAND_FORK; } close(fdout[1]); close(fderr[1]); if (WAITMODE & flags) { ret = wait_for_process(pid, MAX_PROCESSING_TIME, &status); if (ret) { if (ret < 0) { debug_git("[ERROR] wait_for_process failed (%d); " "wd: %s; cmd: %s", status, working_directory, argv[0]); status = -1; } strbuf_read(output, fdout[0], 0); debug_git("STDOUT:\r\n%s\r\n*** end of STDOUT ***\r\n", output->buf); strbuf_read(error_output, fderr[0], 0); debug_git("STDERR:\r\n%s\r\n*** end of STDERR ***\r\n", error_output->buf); } else { status = -ERR_RUN_COMMAND_WAITPID_NOEXIT; debug_git("[ERROR] process timed out; " "wd: %s; cmd: %s", working_directory, argv[0]); } } close_process(pid); close(fdout[0]); close(fderr[0]); strbuf_release(&strerr); strbuf_release(&strout); return status; }
int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { if (cmd->out > 0) close(cmd->out); return -ERR_RUN_COMMAND_PIPE; } cmd->in = fdin[1]; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); return -ERR_RUN_COMMAND_PIPE; } cmd->out = fdout[0]; } need_err = !cmd->no_stderr && cmd->err < 0; if (need_err) { if (pipe(fderr) < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); return -ERR_RUN_COMMAND_PIPE; } cmd->err = fderr[0]; } fflush(NULL); cmd->pid = fork(); if (!cmd->pid) { if (cmd->no_stdin) dup_devnull(0); else if (need_in) { dup2(fdin[0], 0); close_pair(fdin); } else if (cmd->in) { dup2(cmd->in, 0); close(cmd->in); } if (cmd->no_stderr) dup_devnull(2); else if (need_err) { dup2(fderr[1], 2); close_pair(fderr); } if (cmd->no_stdout) dup_devnull(1); else if (cmd->stdout_to_stderr) dup2(2, 1); else if (need_out) { dup2(fdout[1], 1); close_pair(fdout); } else if (cmd->out > 1) { dup2(cmd->out, 1); close(cmd->out); } if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) putenv((char*)*cmd->env); else unsetenv(*cmd->env); } } if (cmd->preexec_cb) cmd->preexec_cb(); if (cmd->perf_cmd) { execv_perf_cmd(cmd->argv); } else { execvp(cmd->argv[0], (char *const*) cmd->argv); } exit(127); } if (cmd->pid < 0) { int err = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); if (need_err) close_pair(fderr); return err == ENOENT ? -ERR_RUN_COMMAND_EXEC : -ERR_RUN_COMMAND_FORK; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); if (need_out) close(fdout[1]); else if (cmd->out) close(cmd->out); if (need_err) close(fderr[1]); return 0; }
int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; int failed_errno; char *str; if (!cmd->argv) cmd->argv = cmd->args.argv; if (!cmd->env) cmd->env = cmd->env_array.argv; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { failed_errno = errno; if (cmd->out > 0) close(cmd->out); str = "standard input"; goto fail_pipe; } cmd->in = fdin[1]; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { failed_errno = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); str = "standard output"; goto fail_pipe; } cmd->out = fdout[0]; } need_err = !cmd->no_stderr && cmd->err < 0; if (need_err) { if (pipe(fderr) < 0) { failed_errno = errno; if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); str = "standard error"; fail_pipe: error("cannot create %s pipe for %s: %s", str, cmd->argv[0], strerror(failed_errno)); child_process_clear(cmd); errno = failed_errno; return -1; } cmd->err = fderr[0]; } trace_argv_printf(cmd->argv, "trace: run_command:"); fflush(NULL); #ifndef GIT_WINDOWS_NATIVE { int notify_pipe[2]; int null_fd = -1; char **childenv; struct argv_array argv = ARGV_ARRAY_INIT; struct child_err cerr; struct atfork_state as; if (pipe(notify_pipe)) notify_pipe[0] = notify_pipe[1] = -1; if (cmd->no_stdin || cmd->no_stdout || cmd->no_stderr) { null_fd = open("/dev/null", O_RDWR | O_CLOEXEC); if (null_fd < 0) die_errno(_("open /dev/null failed")); set_cloexec(null_fd); } prepare_cmd(&argv, cmd); childenv = prep_childenv(cmd->env); atfork_prepare(&as); /* * NOTE: In order to prevent deadlocking when using threads special * care should be taken with the function calls made in between the * fork() and exec() calls. No calls should be made to functions which * require acquiring a lock (e.g. malloc) as the lock could have been * held by another thread at the time of forking, causing the lock to * never be released in the child process. This means only * Async-Signal-Safe functions are permitted in the child. */ cmd->pid = fork(); failed_errno = errno; if (!cmd->pid) { int sig; /* * Ensure the default die/error/warn routines do not get * called, they can take stdio locks and malloc. */ set_die_routine(child_die_fn); set_error_routine(child_error_fn); set_warn_routine(child_warn_fn); close(notify_pipe[0]); set_cloexec(notify_pipe[1]); child_notifier = notify_pipe[1]; if (cmd->no_stdin) child_dup2(null_fd, 0); else if (need_in) { child_dup2(fdin[0], 0); child_close_pair(fdin); } else if (cmd->in) { child_dup2(cmd->in, 0); child_close(cmd->in); } if (cmd->no_stderr) child_dup2(null_fd, 2); else if (need_err) { child_dup2(fderr[1], 2); child_close_pair(fderr); } else if (cmd->err > 1) { child_dup2(cmd->err, 2); child_close(cmd->err); } if (cmd->no_stdout) child_dup2(null_fd, 1); else if (cmd->stdout_to_stderr) child_dup2(2, 1); else if (need_out) { child_dup2(fdout[1], 1); child_close_pair(fdout); } else if (cmd->out > 1) { child_dup2(cmd->out, 1); child_close(cmd->out); } if (cmd->dir && chdir(cmd->dir)) child_die(CHILD_ERR_CHDIR); /* * restore default signal handlers here, in case * we catch a signal right before execve below */ for (sig = 1; sig < NSIG; sig++) { /* ignored signals get reset to SIG_DFL on execve */ if (signal(sig, SIG_DFL) == SIG_IGN) signal(sig, SIG_IGN); } if (sigprocmask(SIG_SETMASK, &as.old, NULL) != 0) child_die(CHILD_ERR_SIGPROCMASK); /* * 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'. */ execve(argv.argv[1], (char *const *) argv.argv + 1, (char *const *) childenv); if (errno == ENOEXEC) execve(argv.argv[0], (char *const *) argv.argv, (char *const *) childenv); if (errno == ENOENT) { if (cmd->silent_exec_failure) child_die(CHILD_ERR_SILENT); child_die(CHILD_ERR_ENOENT); } else { child_die(CHILD_ERR_ERRNO); } } atfork_parent(&as); if (cmd->pid < 0) error_errno("cannot fork() for %s", cmd->argv[0]); else if (cmd->clean_on_exit) mark_child_for_cleanup(cmd->pid, cmd); /* * 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 child_err struct. * Note that use of this infrastructure is completely advisory, * therefore, we keep error checks minimal. */ close(notify_pipe[1]); if (xread(notify_pipe[0], &cerr, sizeof(cerr)) == sizeof(cerr)) { /* * 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); child_err_spew(cmd, &cerr); failed_errno = errno; cmd->pid = -1; } close(notify_pipe[0]); if (null_fd >= 0) close(null_fd); argv_array_clear(&argv); free(childenv); } #else { int fhin = 0, fhout = 1, fherr = 2; const char **sargv = cmd->argv; struct argv_array nargv = ARGV_ARRAY_INIT; if (cmd->no_stdin) fhin = open("/dev/null", O_RDWR); else if (need_in) fhin = dup(fdin[0]); else if (cmd->in) fhin = dup(cmd->in); if (cmd->no_stderr) fherr = open("/dev/null", O_RDWR); else if (need_err) fherr = dup(fderr[1]); else if (cmd->err > 2) fherr = dup(cmd->err); if (cmd->no_stdout) fhout = open("/dev/null", O_RDWR); else if (cmd->stdout_to_stderr) fhout = dup(fherr); else if (need_out) fhout = dup(fdout[1]); else if (cmd->out > 1) fhout = dup(cmd->out); if (cmd->git_cmd) cmd->argv = prepare_git_cmd(&nargv, cmd->argv); else if (cmd->use_shell) cmd->argv = prepare_shell_cmd(&nargv, cmd->argv); cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env, cmd->dir, fhin, fhout, fherr); failed_errno = errno; if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT)) error_errno("cannot spawn %s", cmd->argv[0]); if (cmd->clean_on_exit && cmd->pid >= 0) mark_child_for_cleanup(cmd->pid, cmd); argv_array_clear(&nargv); cmd->argv = sargv; if (fhin != 0) close(fhin); if (fhout != 1) close(fhout); if (fherr != 2) close(fherr); } #endif if (cmd->pid < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); if (need_err) close_pair(fderr); else if (cmd->err) close(cmd->err); child_process_clear(cmd); errno = failed_errno; return -1; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); if (need_out) close(fdout[1]); else if (cmd->out) close(cmd->out); if (need_err) close(fderr[1]); else if (cmd->err) close(cmd->err); return 0; }
int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { if (cmd->out > 0) close(cmd->out); return -ERR_RUN_COMMAND_PIPE; } cmd->in = fdin[1]; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); return -ERR_RUN_COMMAND_PIPE; } cmd->out = fdout[0]; } need_err = !cmd->no_stderr && cmd->err < 0; if (need_err) { if (pipe(fderr) < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); return -ERR_RUN_COMMAND_PIPE; } cmd->err = fderr[0]; } trace_argv_printf(cmd->argv, "trace: run_command:"); #ifndef __MINGW32__ cmd->pid = fork(); if (!cmd->pid) { if (cmd->no_stdin) dup_devnull(0); else if (need_in) { dup2(fdin[0], 0); close_pair(fdin); } else if (cmd->in) { dup2(cmd->in, 0); close(cmd->in); } if (cmd->no_stderr) dup_devnull(2); else if (need_err) { dup2(fderr[1], 2); close_pair(fderr); } if (cmd->no_stdout) dup_devnull(1); else if (cmd->stdout_to_stderr) dup2(2, 1); else if (need_out) { dup2(fdout[1], 1); close_pair(fdout); } else if (cmd->out > 1) { dup2(cmd->out, 1); close(cmd->out); } if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) putenv((char*)*cmd->env); else unsetenv(*cmd->env); } } if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else { execvp(cmd->argv[0], (char *const*) cmd->argv); } die("exec %s failed.", cmd->argv[0]); } #else int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ const char *sargv0 = cmd->argv[0]; char **env = environ; struct strbuf git_cmd; if (cmd->no_stdin) { s0 = dup(0); dup_devnull(0); } else if (need_in) { s0 = dup(0); dup2(fdin[0], 0); } else if (cmd->in) { s0 = dup(0); dup2(cmd->in, 0); } if (cmd->no_stderr) { s2 = dup(2); dup_devnull(2); } else if (need_err) { s2 = dup(2); dup2(fderr[1], 2); } if (cmd->no_stdout) { s1 = dup(1); dup_devnull(1); } else if (cmd->stdout_to_stderr) { s1 = dup(1); dup2(2, 1); } else if (need_out) { s1 = dup(1); dup2(fdout[1], 1); } else if (cmd->out > 1) { s1 = dup(1); dup2(cmd->out, 1); } if (cmd->dir) die("chdir in start_command() not implemented"); if (cmd->env) { env = copy_environ(); for (; *cmd->env; cmd->env++) env = env_setenv(env, *cmd->env); } if (cmd->git_cmd) { strbuf_init(&git_cmd, 0); strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]); cmd->argv[0] = git_cmd.buf; } cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); if (cmd->env) free_environ(env); if (cmd->git_cmd) strbuf_release(&git_cmd); cmd->argv[0] = sargv0; if (s0 >= 0) dup2(s0, 0), close(s0); if (s1 >= 0) dup2(s1, 1), close(s1); if (s2 >= 0) dup2(s2, 2), close(s2); #endif if (cmd->pid < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); if (need_err) close_pair(fderr); return -ERR_RUN_COMMAND_FORK; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); if (need_out) close(fdout[1]); else if (cmd->out) close(cmd->out); if (need_err) close(fderr[1]); return 0; }
int start_command(struct child_process *cmd) { int need_in, need_out; int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; const char **env = (const char **)environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) return -ERR_RUN_COMMAND_PIPE; cmd->in = fdin[1]; cmd->close_in = 1; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); return -ERR_RUN_COMMAND_PIPE; } cmd->out = fdout[0]; cmd->close_out = 1; } { if (cmd->no_stdin) fdin[0] = open("/dev/null", O_RDWR); else if (need_in) { /* nothing */ } else if (cmd->in) { fdin[0] = cmd->in; } if (cmd->no_stdout) fdout[1] = open("/dev/null", O_RDWR); else if (cmd->stdout_to_stderr) fdout[1] = dup(2); else if (need_out) { /* nothing */ } else if (cmd->out > 1) { fdout[1] = cmd->out; } if (cmd->dir) die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { if (cmd->merge_env) { env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) die("setting environment in start_command() not implemented"); else env_unsetenv(env, *cmd->env); } } else env = cmd->env; } if (cmd->git_cmd) { cmd->pid = spawnve_git_cmd(cmd->argv, fdin, fdout, env); } else { cmd->pid = spawnvpe_pipe(cmd->cmd ? cmd->cmd : cmd->argv[0], cmd->argv, env, fdin, fdout); } } if (cmd->pid < 0) { if (need_in) close_pair(fdin); if (need_out) close_pair(fdout); return -ERR_RUN_COMMAND_FORK; } return 0; }