• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "cache.h"
2 #include "run-command.h"
3 #include "exec_cmd.h"
4 
close_pair(int fd[2])5 static inline void close_pair(int fd[2])
6 {
7 	close(fd[0]);
8 	close(fd[1]);
9 }
10 
dup_devnull(int to)11 static inline void dup_devnull(int to)
12 {
13 	int fd = open("/dev/null", O_RDWR);
14 	dup2(fd, to);
15 	close(fd);
16 }
17 
start_command(struct child_process * cmd)18 int 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 
wait_or_whine(pid_t pid)154 static 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 
finish_command(struct child_process * cmd)185 int finish_command(struct child_process *cmd)
186 {
187 	return wait_or_whine(cmd->pid);
188 }
189 
run_command(struct child_process * cmd)190 int 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 
prepare_run_command_v_opt(struct child_process * cmd,const char ** argv,int opt)198 static 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 
run_command_v_opt(const char ** argv,int opt)209 int 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