1#include "cache.h"
2#include "run-command.h"
3#include "exec_cmd.h"
4
5static inline void close_pair(int fd[2])
6{
7	close(fd[0]);
8	close(fd[1]);
9}
10
11static inline void dup_devnull(int to)
12{
13	int fd = open("/dev/null", O_RDWR);
14	dup2(fd, to);
15	close(fd);
16}
17
18int start_command(struct child_process *cmd)
19{
20	int need_in, need_out, need_err;
21	int fdin[2], fdout[2], fderr[2];
22
23	/*
24	 * In case of errors we must keep the promise to close FDs
25	 * that have been passed in via ->in and ->out.
26	 */
27
28	need_in = !cmd->no_stdin && cmd->in < 0;
29	if (need_in) {
30		if (pipe(fdin) < 0) {
31			if (cmd->out > 0)
32				close(cmd->out);
33			return -ERR_RUN_COMMAND_PIPE;
34		}
35		cmd->in = fdin[1];
36	}
37
38	need_out = !cmd->no_stdout
39		&& !cmd->stdout_to_stderr
40		&& cmd->out < 0;
41	if (need_out) {
42		if (pipe(fdout) < 0) {
43			if (need_in)
44				close_pair(fdin);
45			else if (cmd->in)
46				close(cmd->in);
47			return -ERR_RUN_COMMAND_PIPE;
48		}
49		cmd->out = fdout[0];
50	}
51
52	need_err = !cmd->no_stderr && cmd->err < 0;
53	if (need_err) {
54		if (pipe(fderr) < 0) {
55			if (need_in)
56				close_pair(fdin);
57			else if (cmd->in)
58				close(cmd->in);
59			if (need_out)
60				close_pair(fdout);
61			else if (cmd->out)
62				close(cmd->out);
63			return -ERR_RUN_COMMAND_PIPE;
64		}
65		cmd->err = fderr[0];
66	}
67
68	fflush(NULL);
69	cmd->pid = fork();
70	if (!cmd->pid) {
71		if (cmd->no_stdin)
72			dup_devnull(0);
73		else if (need_in) {
74			dup2(fdin[0], 0);
75			close_pair(fdin);
76		} else if (cmd->in) {
77			dup2(cmd->in, 0);
78			close(cmd->in);
79		}
80
81		if (cmd->no_stderr)
82			dup_devnull(2);
83		else if (need_err) {
84			dup2(fderr[1], 2);
85			close_pair(fderr);
86		}
87
88		if (cmd->no_stdout)
89			dup_devnull(1);
90		else if (cmd->stdout_to_stderr)
91			dup2(2, 1);
92		else if (need_out) {
93			dup2(fdout[1], 1);
94			close_pair(fdout);
95		} else if (cmd->out > 1) {
96			dup2(cmd->out, 1);
97			close(cmd->out);
98		}
99
100		if (cmd->dir && chdir(cmd->dir))
101			die("exec %s: cd to %s failed (%s)", cmd->argv[0],
102			    cmd->dir, strerror(errno));
103		if (cmd->env) {
104			for (; *cmd->env; cmd->env++) {
105				if (strchr(*cmd->env, '='))
106					putenv((char*)*cmd->env);
107				else
108					unsetenv(*cmd->env);
109			}
110		}
111		if (cmd->preexec_cb)
112			cmd->preexec_cb();
113		if (cmd->perf_cmd) {
114			execv_perf_cmd(cmd->argv);
115		} else {
116			execvp(cmd->argv[0], (char *const*) cmd->argv);
117		}
118		exit(127);
119	}
120
121	if (cmd->pid < 0) {
122		int err = errno;
123		if (need_in)
124			close_pair(fdin);
125		else if (cmd->in)
126			close(cmd->in);
127		if (need_out)
128			close_pair(fdout);
129		else if (cmd->out)
130			close(cmd->out);
131		if (need_err)
132			close_pair(fderr);
133		return err == ENOENT ?
134			-ERR_RUN_COMMAND_EXEC :
135			-ERR_RUN_COMMAND_FORK;
136	}
137
138	if (need_in)
139		close(fdin[0]);
140	else if (cmd->in)
141		close(cmd->in);
142
143	if (need_out)
144		close(fdout[1]);
145	else if (cmd->out)
146		close(cmd->out);
147
148	if (need_err)
149		close(fderr[1]);
150
151	return 0;
152}
153
154static int wait_or_whine(pid_t pid)
155{
156	for (;;) {
157		int status, code;
158		pid_t waiting = waitpid(pid, &status, 0);
159
160		if (waiting < 0) {
161			if (errno == EINTR)
162				continue;
163			error("waitpid failed (%s)", strerror(errno));
164			return -ERR_RUN_COMMAND_WAITPID;
165		}
166		if (waiting != pid)
167			return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
168		if (WIFSIGNALED(status))
169			return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
170
171		if (!WIFEXITED(status))
172			return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
173		code = WEXITSTATUS(status);
174		switch (code) {
175		case 127:
176			return -ERR_RUN_COMMAND_EXEC;
177		case 0:
178			return 0;
179		default:
180			return -code;
181		}
182	}
183}
184
185int finish_command(struct child_process *cmd)
186{
187	return wait_or_whine(cmd->pid);
188}
189
190int run_command(struct child_process *cmd)
191{
192	int code = start_command(cmd);
193	if (code)
194		return code;
195	return finish_command(cmd);
196}
197
198static void prepare_run_command_v_opt(struct child_process *cmd,
199				      const char **argv,
200				      int opt)
201{
202	memset(cmd, 0, sizeof(*cmd));
203	cmd->argv = argv;
204	cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
205	cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
206	cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
207}
208
209int run_command_v_opt(const char **argv, int opt)
210{
211	struct child_process cmd;
212	prepare_run_command_v_opt(&cmd, argv, opt);
213	return run_command(&cmd);
214}
215