Linux Audio

Check our new training course

Embedded Linux training

Mar 31-Apr 8, 2025
Register
Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2#include <unistd.h>
  3#include <sys/types.h>
  4#include <sys/stat.h>
 
  5#include <fcntl.h>
  6#include <string.h>
  7#include <linux/string.h>
  8#include <errno.h>
  9#include <sys/wait.h>
 10#include "subcmd-util.h"
 11#include "run-command.h"
 12#include "exec-cmd.h"
 13
 14#define STRERR_BUFSIZE 128
 15
 16static inline void close_pair(int fd[2])
 17{
 18	close(fd[0]);
 19	close(fd[1]);
 20}
 21
 22static inline void dup_devnull(int to)
 23{
 24	int fd = open("/dev/null", O_RDWR);
 25	dup2(fd, to);
 26	close(fd);
 27}
 28
 29int start_command(struct child_process *cmd)
 30{
 31	int need_in, need_out, need_err;
 32	int fdin[2], fdout[2], fderr[2];
 33	char sbuf[STRERR_BUFSIZE];
 34
 35	/*
 36	 * In case of errors we must keep the promise to close FDs
 37	 * that have been passed in via ->in and ->out.
 38	 */
 39
 40	need_in = !cmd->no_stdin && cmd->in < 0;
 41	if (need_in) {
 42		if (pipe(fdin) < 0) {
 43			if (cmd->out > 0)
 44				close(cmd->out);
 45			return -ERR_RUN_COMMAND_PIPE;
 46		}
 47		cmd->in = fdin[1];
 48	}
 49
 50	need_out = !cmd->no_stdout
 51		&& !cmd->stdout_to_stderr
 52		&& cmd->out < 0;
 53	if (need_out) {
 54		if (pipe(fdout) < 0) {
 55			if (need_in)
 56				close_pair(fdin);
 57			else if (cmd->in)
 58				close(cmd->in);
 59			return -ERR_RUN_COMMAND_PIPE;
 60		}
 61		cmd->out = fdout[0];
 62	}
 63
 64	need_err = !cmd->no_stderr && cmd->err < 0;
 65	if (need_err) {
 66		if (pipe(fderr) < 0) {
 67			if (need_in)
 68				close_pair(fdin);
 69			else if (cmd->in)
 70				close(cmd->in);
 71			if (need_out)
 72				close_pair(fdout);
 73			else if (cmd->out)
 74				close(cmd->out);
 75			return -ERR_RUN_COMMAND_PIPE;
 76		}
 77		cmd->err = fderr[0];
 78	}
 79
 80	fflush(NULL);
 81	cmd->pid = fork();
 82	if (!cmd->pid) {
 83		if (cmd->no_stdin)
 84			dup_devnull(0);
 85		else if (need_in) {
 86			dup2(fdin[0], 0);
 87			close_pair(fdin);
 88		} else if (cmd->in) {
 89			dup2(cmd->in, 0);
 90			close(cmd->in);
 91		}
 92
 93		if (cmd->no_stderr)
 94			dup_devnull(2);
 95		else if (need_err) {
 96			dup2(fderr[1], 2);
 97			close_pair(fderr);
 98		}
 99
100		if (cmd->no_stdout)
101			dup_devnull(1);
102		else if (cmd->stdout_to_stderr)
103			dup2(2, 1);
104		else if (need_out) {
105			dup2(fdout[1], 1);
106			close_pair(fdout);
107		} else if (cmd->out > 1) {
108			dup2(cmd->out, 1);
109			close(cmd->out);
110		}
111
112		if (cmd->dir && chdir(cmd->dir))
113			die("exec %s: cd to %s failed (%s)", cmd->argv[0],
114			    cmd->dir, str_error_r(errno, sbuf, sizeof(sbuf)));
115		if (cmd->env) {
116			for (; *cmd->env; cmd->env++) {
117				if (strchr(*cmd->env, '='))
118					putenv((char*)*cmd->env);
119				else
120					unsetenv(*cmd->env);
121			}
122		}
123		if (cmd->preexec_cb)
124			cmd->preexec_cb();
 
 
125		if (cmd->exec_cmd) {
126			execv_cmd(cmd->argv);
127		} else {
128			execvp(cmd->argv[0], (char *const*) cmd->argv);
129		}
130		exit(127);
131	}
132
133	if (cmd->pid < 0) {
134		int err = errno;
135		if (need_in)
136			close_pair(fdin);
137		else if (cmd->in)
138			close(cmd->in);
139		if (need_out)
140			close_pair(fdout);
141		else if (cmd->out)
142			close(cmd->out);
143		if (need_err)
144			close_pair(fderr);
145		return err == ENOENT ?
146			-ERR_RUN_COMMAND_EXEC :
147			-ERR_RUN_COMMAND_FORK;
148	}
149
150	if (need_in)
151		close(fdin[0]);
152	else if (cmd->in)
153		close(cmd->in);
154
155	if (need_out)
156		close(fdout[1]);
157	else if (cmd->out)
158		close(cmd->out);
159
160	if (need_err)
161		close(fderr[1]);
162
163	return 0;
164}
165
166static int wait_or_whine(pid_t pid)
167{
168	char sbuf[STRERR_BUFSIZE];
 
169
170	for (;;) {
171		int status, code;
172		pid_t waiting = waitpid(pid, &status, 0);
 
 
 
173
 
 
 
 
174		if (waiting < 0) {
175			if (errno == EINTR)
176				continue;
177			fprintf(stderr, " Error: waitpid failed (%s)",
178				str_error_r(errno, sbuf, sizeof(sbuf)));
179			return -ERR_RUN_COMMAND_WAITPID;
180		}
181		if (waiting != pid)
182			return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
183		if (WIFSIGNALED(status))
184			return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
185
186		if (!WIFEXITED(status))
187			return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
188		code = WEXITSTATUS(status);
189		switch (code) {
190		case 127:
191			return -ERR_RUN_COMMAND_EXEC;
192		case 0:
193			return 0;
194		default:
195			return -code;
 
 
 
196		}
197	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198}
199
200int finish_command(struct child_process *cmd)
201{
202	return wait_or_whine(cmd->pid);
203}
204
205int run_command(struct child_process *cmd)
206{
207	int code = start_command(cmd);
208	if (code)
209		return code;
210	return finish_command(cmd);
211}
212
213static void prepare_run_command_v_opt(struct child_process *cmd,
214				      const char **argv,
215				      int opt)
216{
217	memset(cmd, 0, sizeof(*cmd));
218	cmd->argv = argv;
219	cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
220	cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
221	cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
222}
223
224int run_command_v_opt(const char **argv, int opt)
225{
226	struct child_process cmd;
227	prepare_run_command_v_opt(&cmd, argv, opt);
228	return run_command(&cmd);
229}
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2#include <unistd.h>
  3#include <sys/types.h>
  4#include <sys/stat.h>
  5#include <ctype.h>
  6#include <fcntl.h>
  7#include <string.h>
  8#include <linux/string.h>
  9#include <errno.h>
 10#include <sys/wait.h>
 11#include "subcmd-util.h"
 12#include "run-command.h"
 13#include "exec-cmd.h"
 14
 15#define STRERR_BUFSIZE 128
 16
 17static inline void close_pair(int fd[2])
 18{
 19	close(fd[0]);
 20	close(fd[1]);
 21}
 22
 23static inline void dup_devnull(int to)
 24{
 25	int fd = open("/dev/null", O_RDWR);
 26	dup2(fd, to);
 27	close(fd);
 28}
 29
 30int start_command(struct child_process *cmd)
 31{
 32	int need_in, need_out, need_err;
 33	int fdin[2], fdout[2], fderr[2];
 34	char sbuf[STRERR_BUFSIZE];
 35
 36	/*
 37	 * In case of errors we must keep the promise to close FDs
 38	 * that have been passed in via ->in and ->out.
 39	 */
 40
 41	need_in = !cmd->no_stdin && cmd->in < 0;
 42	if (need_in) {
 43		if (pipe(fdin) < 0) {
 44			if (cmd->out > 0)
 45				close(cmd->out);
 46			return -ERR_RUN_COMMAND_PIPE;
 47		}
 48		cmd->in = fdin[1];
 49	}
 50
 51	need_out = !cmd->no_stdout
 52		&& !cmd->stdout_to_stderr
 53		&& cmd->out < 0;
 54	if (need_out) {
 55		if (pipe(fdout) < 0) {
 56			if (need_in)
 57				close_pair(fdin);
 58			else if (cmd->in)
 59				close(cmd->in);
 60			return -ERR_RUN_COMMAND_PIPE;
 61		}
 62		cmd->out = fdout[0];
 63	}
 64
 65	need_err = !cmd->no_stderr && cmd->err < 0;
 66	if (need_err) {
 67		if (pipe(fderr) < 0) {
 68			if (need_in)
 69				close_pair(fdin);
 70			else if (cmd->in)
 71				close(cmd->in);
 72			if (need_out)
 73				close_pair(fdout);
 74			else if (cmd->out)
 75				close(cmd->out);
 76			return -ERR_RUN_COMMAND_PIPE;
 77		}
 78		cmd->err = fderr[0];
 79	}
 80
 81	fflush(NULL);
 82	cmd->pid = fork();
 83	if (!cmd->pid) {
 84		if (cmd->no_stdin)
 85			dup_devnull(0);
 86		else if (need_in) {
 87			dup2(fdin[0], 0);
 88			close_pair(fdin);
 89		} else if (cmd->in) {
 90			dup2(cmd->in, 0);
 91			close(cmd->in);
 92		}
 93
 94		if (cmd->no_stderr)
 95			dup_devnull(2);
 96		else if (need_err) {
 97			dup2(fderr[1], 2);
 98			close_pair(fderr);
 99		}
100
101		if (cmd->no_stdout)
102			dup_devnull(1);
103		else if (cmd->stdout_to_stderr)
104			dup2(2, 1);
105		else if (need_out) {
106			dup2(fdout[1], 1);
107			close_pair(fdout);
108		} else if (cmd->out > 1) {
109			dup2(cmd->out, 1);
110			close(cmd->out);
111		}
112
113		if (cmd->dir && chdir(cmd->dir))
114			die("exec %s: cd to %s failed (%s)", cmd->argv[0],
115			    cmd->dir, str_error_r(errno, sbuf, sizeof(sbuf)));
116		if (cmd->env) {
117			for (; *cmd->env; cmd->env++) {
118				if (strchr(*cmd->env, '='))
119					putenv((char*)*cmd->env);
120				else
121					unsetenv(*cmd->env);
122			}
123		}
124		if (cmd->preexec_cb)
125			cmd->preexec_cb();
126		if (cmd->no_exec_cmd)
127			exit(cmd->no_exec_cmd(cmd));
128		if (cmd->exec_cmd) {
129			execv_cmd(cmd->argv);
130		} else {
131			execvp(cmd->argv[0], (char *const*) cmd->argv);
132		}
133		exit(127);
134	}
135
136	if (cmd->pid < 0) {
137		int err = errno;
138		if (need_in)
139			close_pair(fdin);
140		else if (cmd->in)
141			close(cmd->in);
142		if (need_out)
143			close_pair(fdout);
144		else if (cmd->out)
145			close(cmd->out);
146		if (need_err)
147			close_pair(fderr);
148		return err == ENOENT ?
149			-ERR_RUN_COMMAND_EXEC :
150			-ERR_RUN_COMMAND_FORK;
151	}
152
153	if (need_in)
154		close(fdin[0]);
155	else if (cmd->in)
156		close(cmd->in);
157
158	if (need_out)
159		close(fdout[1]);
160	else if (cmd->out)
161		close(cmd->out);
162
163	if (need_err)
164		close(fderr[1]);
165
166	return 0;
167}
168
169static int wait_or_whine(struct child_process *cmd, bool block)
170{
171	bool finished = cmd->finished;
172	int result = cmd->finish_result;
173
174	while (!finished) {
175		int status, code;
176		pid_t waiting = waitpid(cmd->pid, &status, block ? 0 : WNOHANG);
177
178		if (!block && waiting == 0)
179			break;
180
181		if (waiting < 0 && errno == EINTR)
182			continue;
183
184		finished = true;
185		if (waiting < 0) {
186			char sbuf[STRERR_BUFSIZE];
187
188			fprintf(stderr, " Error: waitpid failed (%s)",
189				str_error_r(errno, sbuf, sizeof(sbuf)));
190			result = -ERR_RUN_COMMAND_WAITPID;
191		} else if (waiting != cmd->pid) {
192			result = -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
193		} else if (WIFSIGNALED(status)) {
194			result = -ERR_RUN_COMMAND_WAITPID_SIGNAL;
195		} else if (!WIFEXITED(status)) {
196			result = -ERR_RUN_COMMAND_WAITPID_NOEXIT;
197		} else {
198			code = WEXITSTATUS(status);
199			switch (code) {
200			case 127:
201				result = -ERR_RUN_COMMAND_EXEC;
202				break;
203			case 0:
204				result = 0;
205				break;
206			default:
207				result = -code;
208				break;
209			}
210		}
211	}
212	if (finished) {
213		cmd->finished = 1;
214		cmd->finish_result = result;
215	}
216	return result;
217}
218
219int check_if_command_finished(struct child_process *cmd)
220{
221#ifdef __linux__
222	char filename[FILENAME_MAX + 12];
223	char status_line[256];
224	FILE *status_file;
225
226	/*
227	 * Check by reading /proc/<pid>/status as calling waitpid causes
228	 * stdout/stderr to be closed and data lost.
229	 */
230	sprintf(filename, "/proc/%d/status", cmd->pid);
231	status_file = fopen(filename, "r");
232	if (status_file == NULL) {
233		/* Open failed assume finish_command was called. */
234		return true;
235	}
236	while (fgets(status_line, sizeof(status_line), status_file) != NULL) {
237		char *p;
238
239		if (strncmp(status_line, "State:", 6))
240			continue;
241
242		fclose(status_file);
243		p = status_line + 6;
244		while (isspace(*p))
245			p++;
246		return *p == 'Z' ? 1 : 0;
247	}
248	/* Read failed assume finish_command was called. */
249	fclose(status_file);
250	return 1;
251#else
252	wait_or_whine(cmd, /*block=*/false);
253	return cmd->finished;
254#endif
255}
256
257int finish_command(struct child_process *cmd)
258{
259	return wait_or_whine(cmd, /*block=*/true);
260}
261
262int run_command(struct child_process *cmd)
263{
264	int code = start_command(cmd);
265	if (code)
266		return code;
267	return finish_command(cmd);
268}
269
270static void prepare_run_command_v_opt(struct child_process *cmd,
271				      const char **argv,
272				      int opt)
273{
274	memset(cmd, 0, sizeof(*cmd));
275	cmd->argv = argv;
276	cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
277	cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
278	cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
279}
280
281int run_command_v_opt(const char **argv, int opt)
282{
283	struct child_process cmd;
284	prepare_run_command_v_opt(&cmd, argv, opt);
285	return run_command(&cmd);
286}