Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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}