Merge branch 'master' of http://repo.or.cz/r/msysgit into devel
[msysgit/historical-msysgit.git] / git / run-command.c
blob5964e7d4ddb355d351607163a421c36e967be449
1 #include "cache.h"
2 #include "run-command.h"
3 #include "exec_cmd.h"
4 #include "spawn-pipe.h"
6 static inline void close_pair(int fd[2])
8 close(fd[0]);
9 close(fd[1]);
12 int start_command(struct child_process *cmd)
14 int need_in, need_out;
15 int fdin[2] = { -1, -1 };
16 int fdout[2] = { -1, -1 };
17 char **env = environ;
19 need_in = !cmd->no_stdin && cmd->in < 0;
20 if (need_in) {
21 if (pipe(fdin) < 0)
22 return -ERR_RUN_COMMAND_PIPE;
23 cmd->in = fdin[1];
24 cmd->close_in = 1;
27 need_out = !cmd->no_stdout
28 && !cmd->stdout_to_stderr
29 && cmd->out < 0;
30 if (need_out) {
31 if (pipe(fdout) < 0) {
32 if (need_in)
33 close_pair(fdin);
34 return -ERR_RUN_COMMAND_PIPE;
36 cmd->out = fdout[0];
37 cmd->close_out = 1;
41 if (cmd->no_stdin)
42 fdin[0] = open("/dev/null", O_RDWR);
43 else if (need_in) {
44 /* nothing */
45 } else if (cmd->in) {
46 fdin[0] = cmd->in;
49 if (cmd->no_stdout)
50 fdout[1] = open("/dev/null", O_RDWR);
51 else if (cmd->stdout_to_stderr)
52 fdout[1] = dup(2);
53 else if (need_out) {
54 /* nothing */
55 } else if (cmd->out > 1) {
56 fdout[1] = cmd->out;
59 if (cmd->dir)
60 die("chdir in start_command() not implemented");
61 if (cmd->dir && chdir(cmd->dir))
62 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
63 cmd->dir, strerror(errno));
64 if (cmd->env) {
65 if (cmd->git_cmd)
66 die("modifying environment for git_cmd in start_command() not implemented");
67 env = copy_environ();
68 for (; *cmd->env; cmd->env++) {
69 if (strchr(*cmd->env, '='))
70 die("setting environment in start_command() not implemented");
71 else
72 env_unsetenv(env, *cmd->env);
75 if (cmd->git_cmd) {
76 cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout);
77 } else {
78 cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout);
81 if (cmd->pid < 0) {
82 if (need_in)
83 close_pair(fdin);
84 if (need_out)
85 close_pair(fdout);
86 return -ERR_RUN_COMMAND_FORK;
89 return 0;
92 int finish_command(struct child_process *cmd)
94 if (cmd->close_in)
95 close(cmd->in);
96 if (cmd->close_out)
97 close(cmd->out);
99 for (;;) {
100 int status, code;
101 pid_t waiting = waitpid(cmd->pid, &status, 0);
103 if (waiting < 0) {
104 if (errno == EINTR)
105 continue;
106 error("waitpid failed (%s)", strerror(errno));
107 return -ERR_RUN_COMMAND_WAITPID;
109 if (waiting != cmd->pid)
110 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
111 if (WIFSIGNALED(status))
112 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
114 if (!WIFEXITED(status))
115 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
116 code = WEXITSTATUS(status);
117 if (code)
118 return -code;
119 return 0;
123 int run_command(struct child_process *cmd)
125 int code = start_command(cmd);
126 if (code)
127 return code;
128 return finish_command(cmd);
131 static void prepare_run_command_v_opt(struct child_process *cmd,
132 const char **argv,
133 int opt)
135 memset(cmd, 0, sizeof(*cmd));
136 cmd->argv = argv;
137 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
138 cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
139 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
142 int run_command_v_opt(const char **argv, int opt)
144 struct child_process cmd;
145 prepare_run_command_v_opt(&cmd, argv, opt);
146 return run_command(&cmd);
149 int run_command_v_opt_cd(const char **argv, int opt, const char *dir)
151 struct child_process cmd;
152 prepare_run_command_v_opt(&cmd, argv, opt);
153 cmd.dir = dir;
154 return run_command(&cmd);
157 int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
159 struct child_process cmd;
160 prepare_run_command_v_opt(&cmd, argv, opt);
161 cmd.dir = dir;
162 cmd.env = env;
163 return run_command(&cmd);