Add expat
[git/pclouds.git] / run-command.c
blob8a69c8856b6c5feb82a85fbff303353f0a516638
1 #include "cache.h"
2 #include "run-command.h"
3 #include "exec_cmd.h"
4 #include "spawn-pipe.h"
6 extern char **environ;
7 static inline void close_pair(int fd[2])
9 close(fd[0]);
10 close(fd[1]);
13 int start_command(struct child_process *cmd)
15 int need_in, need_out;
16 int fdin[2] = { -1, -1 };
17 int fdout[2] = { -1, -1 };
18 char **env = environ;
20 need_in = !cmd->no_stdin && cmd->in < 0;
21 if (need_in) {
22 if (pipe(fdin) < 0)
23 return -ERR_RUN_COMMAND_PIPE;
24 cmd->in = fdin[1];
25 cmd->close_in = 1;
28 need_out = !cmd->no_stdout
29 && !cmd->stdout_to_stderr
30 && cmd->out < 0;
31 if (need_out) {
32 if (pipe(fdout) < 0) {
33 if (need_in)
34 close_pair(fdin);
35 return -ERR_RUN_COMMAND_PIPE;
37 cmd->out = fdout[0];
38 cmd->close_out = 1;
42 if (cmd->no_stdin)
43 fdin[0] = open("/dev/null", O_RDWR);
44 else if (need_in) {
45 /* nothing */
46 } else if (cmd->in) {
47 fdin[0] = cmd->in;
50 if (cmd->no_stdout)
51 fdout[1] = open("/dev/null", O_RDWR);
52 else if (cmd->stdout_to_stderr)
53 fdout[1] = dup(2);
54 else if (need_out) {
55 /* nothing */
56 } else if (cmd->out > 1) {
57 fdout[1] = cmd->out;
60 if (cmd->dir)
61 die("chdir in start_command() not implemented");
62 if (cmd->dir && chdir(cmd->dir))
63 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
64 cmd->dir, strerror(errno));
65 if (cmd->env) {
66 if (cmd->merge_env) {
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 else
76 env = cmd->env;
78 if (cmd->git_cmd) {
79 cmd->pid = spawnve_git_cmd(cmd->argv, fdin, fdout, env);
80 } else {
81 cmd->pid = spawnvpe_pipe(cmd->cmd ? cmd->cmd : cmd->argv[0], cmd->argv, env, fdin, fdout);
84 if (cmd->pid < 0) {
85 if (need_in)
86 close_pair(fdin);
87 if (need_out)
88 close_pair(fdout);
89 return -ERR_RUN_COMMAND_FORK;
92 return 0;
95 int finish_command(struct child_process *cmd)
97 if (cmd->close_in)
98 close(cmd->in);
99 if (cmd->close_out)
100 close(cmd->out);
102 for (;;) {
103 int status, code;
104 pid_t waiting = waitpid(cmd->pid, &status, 0);
106 if (waiting < 0) {
107 if (errno == EINTR)
108 continue;
109 error("waitpid failed (%s)", strerror(errno));
110 return -ERR_RUN_COMMAND_WAITPID;
112 if (waiting != cmd->pid)
113 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
114 if (WIFSIGNALED(status))
115 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
117 if (!WIFEXITED(status))
118 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
119 code = WEXITSTATUS(status);
120 if (code)
121 return -code;
122 return 0;
126 int run_command(struct child_process *cmd)
128 int code = start_command(cmd);
129 if (code)
130 return code;
131 return finish_command(cmd);
134 static void prepare_run_command_v_opt(struct child_process *cmd,
135 const char **argv,
136 int opt)
138 memset(cmd, 0, sizeof(*cmd));
139 cmd->argv = argv;
140 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
141 cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
142 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
143 cmd->merge_env = opt & RUN_COMMAND_NO_MERGE_ENV ? 0 : 1;
146 int run_command_v_opt(const char **argv, int opt)
148 struct child_process cmd;
149 prepare_run_command_v_opt(&cmd, argv, opt);
150 return run_command(&cmd);
153 int run_command_v_opt_cd(const char **argv, int opt, const char *dir)
155 struct child_process cmd;
156 prepare_run_command_v_opt(&cmd, argv, opt);
157 cmd.dir = dir;
158 return run_command(&cmd);
161 int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
163 struct child_process cmd;
164 prepare_run_command_v_opt(&cmd, argv, opt);
165 cmd.dir = dir;
166 cmd.env = env;
167 return run_command(&cmd);