1#include "cache.h"2#include "run-command.h"3#include "exec_cmd.h"45static inline void close_pair(int fd[2])6{7close(fd[0]);8close(fd[1]);9}1011static inline void dup_devnull(int to)12{13int fd = open("/dev/null", O_RDWR);14dup2(fd, to);15close(fd);16}1718int start_command(struct child_process *cmd)19{20int need_in, need_out;21int fdin[2], fdout[2];2223need_in = !cmd->no_stdin && cmd->in < 0;24if (need_in) {25if (pipe(fdin) < 0)26return -ERR_RUN_COMMAND_PIPE;27cmd->in = fdin[1];28cmd->close_in = 1;29}3031need_out = !cmd->no_stdout32&& !cmd->stdout_to_stderr33&& cmd->out < 0;34if (need_out) {35if (pipe(fdout) < 0) {36if (need_in)37close_pair(fdin);38return -ERR_RUN_COMMAND_PIPE;39}40cmd->out = fdout[0];41cmd->close_out = 1;42}4344cmd->pid = fork();45if (cmd->pid < 0) {46if (need_in)47close_pair(fdin);48if (need_out)49close_pair(fdout);50return -ERR_RUN_COMMAND_FORK;51}5253if (!cmd->pid) {54if (cmd->no_stdin)55dup_devnull(0);56else if (need_in) {57dup2(fdin[0], 0);58close_pair(fdin);59} else if (cmd->in) {60dup2(cmd->in, 0);61close(cmd->in);62}6364if (cmd->no_stdout)65dup_devnull(1);66else if (cmd->stdout_to_stderr)67dup2(2, 1);68else if (need_out) {69dup2(fdout[1], 1);70close_pair(fdout);71} else if (cmd->out > 1) {72dup2(cmd->out, 1);73close(cmd->out);74}7576if (cmd->git_cmd) {77execv_git_cmd(cmd->argv);78} else {79execvp(cmd->argv[0], (char *const*) cmd->argv);80}81die("exec %s failed.", cmd->argv[0]);82}8384if (need_in)85close(fdin[0]);86else if (cmd->in)87close(cmd->in);8889if (need_out)90close(fdout[1]);91else if (cmd->out > 1)92close(cmd->out);9394return 0;95}9697int finish_command(struct child_process *cmd)98{99if (cmd->close_in)100close(cmd->in);101if (cmd->close_out)102close(cmd->out);103104for (;;) {105int status, code;106pid_t waiting = waitpid(cmd->pid, &status, 0);107108if (waiting < 0) {109if (errno == EINTR)110continue;111error("waitpid failed (%s)", strerror(errno));112return -ERR_RUN_COMMAND_WAITPID;113}114if (waiting != cmd->pid)115return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;116if (WIFSIGNALED(status))117return -ERR_RUN_COMMAND_WAITPID_SIGNAL;118119if (!WIFEXITED(status))120return -ERR_RUN_COMMAND_WAITPID_NOEXIT;121code = WEXITSTATUS(status);122if (code)123return -code;124return 0;125}126}127128int run_command(struct child_process *cmd)129{130int code = start_command(cmd);131if (code)132return code;133return finish_command(cmd);134}135136int run_command_v_opt(const char **argv, int opt)137{138struct child_process cmd;139memset(&cmd, 0, sizeof(cmd));140cmd.argv = argv;141cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;142cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;143cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;144return run_command(&cmd);145}