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