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