xref: /aosp_15_r20/external/vboot_reference/host/lib/subprocess.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2019 The ChromiumOS Authors
2*8617a60dSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
3*8617a60dSAndroid Build Coastguard Worker  * found in the LICENSE file.
4*8617a60dSAndroid Build Coastguard Worker  */
5*8617a60dSAndroid Build Coastguard Worker 
6*8617a60dSAndroid Build Coastguard Worker #include <errno.h>
7*8617a60dSAndroid Build Coastguard Worker #include <fcntl.h>
8*8617a60dSAndroid Build Coastguard Worker #include <stdbool.h>
9*8617a60dSAndroid Build Coastguard Worker #include <stdlib.h>
10*8617a60dSAndroid Build Coastguard Worker #include <string.h>
11*8617a60dSAndroid Build Coastguard Worker #include <sys/wait.h>
12*8617a60dSAndroid Build Coastguard Worker #include <unistd.h>
13*8617a60dSAndroid Build Coastguard Worker 
14*8617a60dSAndroid Build Coastguard Worker #include "2common.h"
15*8617a60dSAndroid Build Coastguard Worker #include "subprocess.h"
16*8617a60dSAndroid Build Coastguard Worker 
17*8617a60dSAndroid Build Coastguard Worker #define MAX_CB_BUF_SIZE 2048
18*8617a60dSAndroid Build Coastguard Worker 
init_target_private(struct subprocess_target * target)19*8617a60dSAndroid Build Coastguard Worker static int init_target_private(struct subprocess_target *target)
20*8617a60dSAndroid Build Coastguard Worker {
21*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
22*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
23*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
24*8617a60dSAndroid Build Coastguard Worker 	case TARGET_CALLBACK:
25*8617a60dSAndroid Build Coastguard Worker 		return pipe(target->priv.pipefd);
26*8617a60dSAndroid Build Coastguard Worker 	default:
27*8617a60dSAndroid Build Coastguard Worker 		return 0;
28*8617a60dSAndroid Build Coastguard Worker 	}
29*8617a60dSAndroid Build Coastguard Worker }
30*8617a60dSAndroid Build Coastguard Worker 
flags_for_fd(int fd)31*8617a60dSAndroid Build Coastguard Worker static int flags_for_fd(int fd)
32*8617a60dSAndroid Build Coastguard Worker {
33*8617a60dSAndroid Build Coastguard Worker 	switch (fd) {
34*8617a60dSAndroid Build Coastguard Worker 	case STDIN_FILENO:
35*8617a60dSAndroid Build Coastguard Worker 		return O_RDONLY;
36*8617a60dSAndroid Build Coastguard Worker 	case STDOUT_FILENO:
37*8617a60dSAndroid Build Coastguard Worker 	case STDERR_FILENO:
38*8617a60dSAndroid Build Coastguard Worker 		return O_WRONLY;
39*8617a60dSAndroid Build Coastguard Worker 	default:
40*8617a60dSAndroid Build Coastguard Worker 		return -1;
41*8617a60dSAndroid Build Coastguard Worker 	}
42*8617a60dSAndroid Build Coastguard Worker }
43*8617a60dSAndroid Build Coastguard Worker 
connect_process_target(struct subprocess_target * target,int fd)44*8617a60dSAndroid Build Coastguard Worker static int connect_process_target(struct subprocess_target *target, int fd)
45*8617a60dSAndroid Build Coastguard Worker {
46*8617a60dSAndroid Build Coastguard Worker 	int target_fd;
47*8617a60dSAndroid Build Coastguard Worker 
48*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
49*8617a60dSAndroid Build Coastguard Worker 	case TARGET_NULL:
50*8617a60dSAndroid Build Coastguard Worker 		target_fd = open("/dev/null", flags_for_fd(fd));
51*8617a60dSAndroid Build Coastguard Worker 		break;
52*8617a60dSAndroid Build Coastguard Worker 	case TARGET_FD:
53*8617a60dSAndroid Build Coastguard Worker 		target_fd = target->fd;
54*8617a60dSAndroid Build Coastguard Worker 		break;
55*8617a60dSAndroid Build Coastguard Worker 	case TARGET_FILE:
56*8617a60dSAndroid Build Coastguard Worker 		target_fd = fileno(target->file);
57*8617a60dSAndroid Build Coastguard Worker 		break;
58*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
59*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
60*8617a60dSAndroid Build Coastguard Worker 	case TARGET_CALLBACK:
61*8617a60dSAndroid Build Coastguard Worker 		switch (fd) {
62*8617a60dSAndroid Build Coastguard Worker 		case STDIN_FILENO:
63*8617a60dSAndroid Build Coastguard Worker 			target_fd = target->priv.pipefd[0];
64*8617a60dSAndroid Build Coastguard Worker 			close(target->priv.pipefd[1]);
65*8617a60dSAndroid Build Coastguard Worker 			break;
66*8617a60dSAndroid Build Coastguard Worker 		case STDOUT_FILENO:
67*8617a60dSAndroid Build Coastguard Worker 		case STDERR_FILENO:
68*8617a60dSAndroid Build Coastguard Worker 			target_fd = target->priv.pipefd[1];
69*8617a60dSAndroid Build Coastguard Worker 			close(target->priv.pipefd[0]);
70*8617a60dSAndroid Build Coastguard Worker 			break;
71*8617a60dSAndroid Build Coastguard Worker 		default:
72*8617a60dSAndroid Build Coastguard Worker 			return -1;
73*8617a60dSAndroid Build Coastguard Worker 		}
74*8617a60dSAndroid Build Coastguard Worker 		break;
75*8617a60dSAndroid Build Coastguard Worker 	default:
76*8617a60dSAndroid Build Coastguard Worker 		return -1;
77*8617a60dSAndroid Build Coastguard Worker 	}
78*8617a60dSAndroid Build Coastguard Worker 
79*8617a60dSAndroid Build Coastguard Worker 	return dup2(target_fd, fd);
80*8617a60dSAndroid Build Coastguard Worker }
81*8617a60dSAndroid Build Coastguard Worker 
process_target_input_buffer(struct subprocess_target * target)82*8617a60dSAndroid Build Coastguard Worker static int process_target_input_buffer(struct subprocess_target *target)
83*8617a60dSAndroid Build Coastguard Worker {
84*8617a60dSAndroid Build Coastguard Worker 	ssize_t write_rv;
85*8617a60dSAndroid Build Coastguard Worker 	size_t bytes_to_write;
86*8617a60dSAndroid Build Coastguard Worker 	char *buf;
87*8617a60dSAndroid Build Coastguard Worker 
88*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
89*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
90*8617a60dSAndroid Build Coastguard Worker 		bytes_to_write = target->buffer.size;
91*8617a60dSAndroid Build Coastguard Worker 		break;
92*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
93*8617a60dSAndroid Build Coastguard Worker 		bytes_to_write = strlen(target->buffer.buf);
94*8617a60dSAndroid Build Coastguard Worker 		break;
95*8617a60dSAndroid Build Coastguard Worker 	default:
96*8617a60dSAndroid Build Coastguard Worker 		return -1;
97*8617a60dSAndroid Build Coastguard Worker 	}
98*8617a60dSAndroid Build Coastguard Worker 
99*8617a60dSAndroid Build Coastguard Worker 	buf = target->buffer.buf;
100*8617a60dSAndroid Build Coastguard Worker 	while (bytes_to_write) {
101*8617a60dSAndroid Build Coastguard Worker 		write_rv = write(target->priv.pipefd[1], buf, bytes_to_write);
102*8617a60dSAndroid Build Coastguard Worker 		if (write_rv <= 0)
103*8617a60dSAndroid Build Coastguard Worker 			return -1;
104*8617a60dSAndroid Build Coastguard Worker 		buf += write_rv;
105*8617a60dSAndroid Build Coastguard Worker 		bytes_to_write -= write_rv;
106*8617a60dSAndroid Build Coastguard Worker 	}
107*8617a60dSAndroid Build Coastguard Worker 
108*8617a60dSAndroid Build Coastguard Worker 	return 0;
109*8617a60dSAndroid Build Coastguard Worker }
110*8617a60dSAndroid Build Coastguard Worker 
process_target_input_cb(struct subprocess_target * target)111*8617a60dSAndroid Build Coastguard Worker static int process_target_input_cb(struct subprocess_target *target)
112*8617a60dSAndroid Build Coastguard Worker {
113*8617a60dSAndroid Build Coastguard Worker 	ssize_t write_rv, bytes_to_write;
114*8617a60dSAndroid Build Coastguard Worker 	char buf[MAX_CB_BUF_SIZE];
115*8617a60dSAndroid Build Coastguard Worker 	char *bufptr;
116*8617a60dSAndroid Build Coastguard Worker 
117*8617a60dSAndroid Build Coastguard Worker 	for (;;) {
118*8617a60dSAndroid Build Coastguard Worker 		bytes_to_write = target->callback.cb(buf, MAX_CB_BUF_SIZE,
119*8617a60dSAndroid Build Coastguard Worker 						     target->callback.data);
120*8617a60dSAndroid Build Coastguard Worker 		if (bytes_to_write < 0 || bytes_to_write > MAX_CB_BUF_SIZE)
121*8617a60dSAndroid Build Coastguard Worker 			return -1;
122*8617a60dSAndroid Build Coastguard Worker 		if (bytes_to_write == 0)
123*8617a60dSAndroid Build Coastguard Worker 			return 0;
124*8617a60dSAndroid Build Coastguard Worker 
125*8617a60dSAndroid Build Coastguard Worker 		bufptr = buf;
126*8617a60dSAndroid Build Coastguard Worker 		while (bytes_to_write) {
127*8617a60dSAndroid Build Coastguard Worker 			write_rv = write(target->priv.pipefd[1], bufptr,
128*8617a60dSAndroid Build Coastguard Worker 					 bytes_to_write);
129*8617a60dSAndroid Build Coastguard Worker 			if (write_rv <= 0)
130*8617a60dSAndroid Build Coastguard Worker 				return -1;
131*8617a60dSAndroid Build Coastguard Worker 			bufptr += write_rv;
132*8617a60dSAndroid Build Coastguard Worker 			bytes_to_write -= write_rv;
133*8617a60dSAndroid Build Coastguard Worker 		}
134*8617a60dSAndroid Build Coastguard Worker 	}
135*8617a60dSAndroid Build Coastguard Worker }
136*8617a60dSAndroid Build Coastguard Worker 
process_target_input(struct subprocess_target * target)137*8617a60dSAndroid Build Coastguard Worker static int process_target_input(struct subprocess_target *target)
138*8617a60dSAndroid Build Coastguard Worker {
139*8617a60dSAndroid Build Coastguard Worker 	int rv;
140*8617a60dSAndroid Build Coastguard Worker 
141*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
142*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
143*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
144*8617a60dSAndroid Build Coastguard Worker 	case TARGET_CALLBACK:
145*8617a60dSAndroid Build Coastguard Worker 		break;
146*8617a60dSAndroid Build Coastguard Worker 	default:
147*8617a60dSAndroid Build Coastguard Worker 		return 0;
148*8617a60dSAndroid Build Coastguard Worker 	}
149*8617a60dSAndroid Build Coastguard Worker 
150*8617a60dSAndroid Build Coastguard Worker 	close(target->priv.pipefd[0]);
151*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
152*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
153*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
154*8617a60dSAndroid Build Coastguard Worker 		rv = process_target_input_buffer(target);
155*8617a60dSAndroid Build Coastguard Worker 		break;
156*8617a60dSAndroid Build Coastguard Worker 	case TARGET_CALLBACK:
157*8617a60dSAndroid Build Coastguard Worker 		rv = process_target_input_cb(target);
158*8617a60dSAndroid Build Coastguard Worker 		break;
159*8617a60dSAndroid Build Coastguard Worker 	default:
160*8617a60dSAndroid Build Coastguard Worker 		return -1;
161*8617a60dSAndroid Build Coastguard Worker 	}
162*8617a60dSAndroid Build Coastguard Worker 
163*8617a60dSAndroid Build Coastguard Worker 	close(target->priv.pipefd[1]);
164*8617a60dSAndroid Build Coastguard Worker 	return rv;
165*8617a60dSAndroid Build Coastguard Worker }
166*8617a60dSAndroid Build Coastguard Worker 
process_target_output_buffer(struct subprocess_target * target)167*8617a60dSAndroid Build Coastguard Worker static int process_target_output_buffer(struct subprocess_target *target)
168*8617a60dSAndroid Build Coastguard Worker {
169*8617a60dSAndroid Build Coastguard Worker 	ssize_t read_rv;
170*8617a60dSAndroid Build Coastguard Worker 	size_t bytes_remaining;
171*8617a60dSAndroid Build Coastguard Worker 
172*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
173*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
174*8617a60dSAndroid Build Coastguard Worker 		bytes_remaining = target->buffer.size;
175*8617a60dSAndroid Build Coastguard Worker 		break;
176*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
177*8617a60dSAndroid Build Coastguard Worker 		if (target->buffer.size == 0)
178*8617a60dSAndroid Build Coastguard Worker 			return -1;
179*8617a60dSAndroid Build Coastguard Worker 		bytes_remaining = target->buffer.size - 1;
180*8617a60dSAndroid Build Coastguard Worker 		break;
181*8617a60dSAndroid Build Coastguard Worker 	default:
182*8617a60dSAndroid Build Coastguard Worker 		return 0;
183*8617a60dSAndroid Build Coastguard Worker 	}
184*8617a60dSAndroid Build Coastguard Worker 
185*8617a60dSAndroid Build Coastguard Worker 	target->buffer.bytes_consumed = 0;
186*8617a60dSAndroid Build Coastguard Worker 	while (bytes_remaining) {
187*8617a60dSAndroid Build Coastguard Worker 		read_rv = read(
188*8617a60dSAndroid Build Coastguard Worker 			target->priv.pipefd[0],
189*8617a60dSAndroid Build Coastguard Worker 			target->buffer.buf + target->buffer.bytes_consumed,
190*8617a60dSAndroid Build Coastguard Worker 			bytes_remaining);
191*8617a60dSAndroid Build Coastguard Worker 		if (read_rv < 0)
192*8617a60dSAndroid Build Coastguard Worker 			return -1;
193*8617a60dSAndroid Build Coastguard Worker 		if (read_rv == 0)
194*8617a60dSAndroid Build Coastguard Worker 			break;
195*8617a60dSAndroid Build Coastguard Worker 		target->buffer.bytes_consumed += read_rv;
196*8617a60dSAndroid Build Coastguard Worker 		bytes_remaining -= read_rv;
197*8617a60dSAndroid Build Coastguard Worker 	}
198*8617a60dSAndroid Build Coastguard Worker 
199*8617a60dSAndroid Build Coastguard Worker 	if (target->type == TARGET_BUFFER_NULL_TERMINATED)
200*8617a60dSAndroid Build Coastguard Worker 		target->buffer.buf[target->buffer.bytes_consumed] = '\0';
201*8617a60dSAndroid Build Coastguard Worker 	return 0;
202*8617a60dSAndroid Build Coastguard Worker }
203*8617a60dSAndroid Build Coastguard Worker 
process_target_output_cb(struct subprocess_target * target)204*8617a60dSAndroid Build Coastguard Worker static int process_target_output_cb(struct subprocess_target *target)
205*8617a60dSAndroid Build Coastguard Worker {
206*8617a60dSAndroid Build Coastguard Worker 	char buf[MAX_CB_BUF_SIZE];
207*8617a60dSAndroid Build Coastguard Worker 	ssize_t rv;
208*8617a60dSAndroid Build Coastguard Worker 
209*8617a60dSAndroid Build Coastguard Worker 	for (;;) {
210*8617a60dSAndroid Build Coastguard Worker 		rv = read(target->priv.pipefd[0], buf, MAX_CB_BUF_SIZE);
211*8617a60dSAndroid Build Coastguard Worker 		if (rv < 0)
212*8617a60dSAndroid Build Coastguard Worker 			return -1;
213*8617a60dSAndroid Build Coastguard Worker 		if (rv == 0)
214*8617a60dSAndroid Build Coastguard Worker 			break;
215*8617a60dSAndroid Build Coastguard Worker 		if (target->callback.cb(buf, rv, target->callback.data) < 0)
216*8617a60dSAndroid Build Coastguard Worker 			return -1;
217*8617a60dSAndroid Build Coastguard Worker 	}
218*8617a60dSAndroid Build Coastguard Worker 
219*8617a60dSAndroid Build Coastguard Worker 	return 0;
220*8617a60dSAndroid Build Coastguard Worker }
221*8617a60dSAndroid Build Coastguard Worker 
process_target_output(struct subprocess_target * target)222*8617a60dSAndroid Build Coastguard Worker static int process_target_output(struct subprocess_target *target)
223*8617a60dSAndroid Build Coastguard Worker {
224*8617a60dSAndroid Build Coastguard Worker 	int rv;
225*8617a60dSAndroid Build Coastguard Worker 
226*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
227*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
228*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
229*8617a60dSAndroid Build Coastguard Worker 	case TARGET_CALLBACK:
230*8617a60dSAndroid Build Coastguard Worker 		break;
231*8617a60dSAndroid Build Coastguard Worker 	default:
232*8617a60dSAndroid Build Coastguard Worker 		return 0;
233*8617a60dSAndroid Build Coastguard Worker 	}
234*8617a60dSAndroid Build Coastguard Worker 
235*8617a60dSAndroid Build Coastguard Worker 	close(target->priv.pipefd[1]);
236*8617a60dSAndroid Build Coastguard Worker 	switch (target->type) {
237*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER:
238*8617a60dSAndroid Build Coastguard Worker 	case TARGET_BUFFER_NULL_TERMINATED:
239*8617a60dSAndroid Build Coastguard Worker 		rv = process_target_output_buffer(target);
240*8617a60dSAndroid Build Coastguard Worker 		break;
241*8617a60dSAndroid Build Coastguard Worker 	case TARGET_CALLBACK:
242*8617a60dSAndroid Build Coastguard Worker 		rv = process_target_output_cb(target);
243*8617a60dSAndroid Build Coastguard Worker 		break;
244*8617a60dSAndroid Build Coastguard Worker 	default:
245*8617a60dSAndroid Build Coastguard Worker 		return -1;
246*8617a60dSAndroid Build Coastguard Worker 	}
247*8617a60dSAndroid Build Coastguard Worker 
248*8617a60dSAndroid Build Coastguard Worker 	close(target->priv.pipefd[0]);
249*8617a60dSAndroid Build Coastguard Worker 	return rv;
250*8617a60dSAndroid Build Coastguard Worker }
251*8617a60dSAndroid Build Coastguard Worker 
contains_spaces(const char * s)252*8617a60dSAndroid Build Coastguard Worker static bool contains_spaces(const char *s)
253*8617a60dSAndroid Build Coastguard Worker {
254*8617a60dSAndroid Build Coastguard Worker 	for (size_t i = 0; s[i]; i++) {
255*8617a60dSAndroid Build Coastguard Worker 		if (isspace(s[i]))
256*8617a60dSAndroid Build Coastguard Worker 			return true;
257*8617a60dSAndroid Build Coastguard Worker 	}
258*8617a60dSAndroid Build Coastguard Worker 	return false;
259*8617a60dSAndroid Build Coastguard Worker }
260*8617a60dSAndroid Build Coastguard Worker 
subprocess_log_call(const char * const argv[])261*8617a60dSAndroid Build Coastguard Worker static void subprocess_log_call(const char *const argv[])
262*8617a60dSAndroid Build Coastguard Worker {
263*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("Run:");
264*8617a60dSAndroid Build Coastguard Worker 
265*8617a60dSAndroid Build Coastguard Worker 	for (size_t i = 0; argv[i]; i++) {
266*8617a60dSAndroid Build Coastguard Worker 		if (contains_spaces(argv[i]))
267*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG_RAW(" '%s'", argv[i]);
268*8617a60dSAndroid Build Coastguard Worker 		else
269*8617a60dSAndroid Build Coastguard Worker 			VB2_DEBUG_RAW(" %s", argv[i]);
270*8617a60dSAndroid Build Coastguard Worker 	}
271*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG_RAW("\n");
272*8617a60dSAndroid Build Coastguard Worker }
273*8617a60dSAndroid Build Coastguard Worker 
274*8617a60dSAndroid Build Coastguard Worker struct subprocess_target subprocess_null = {
275*8617a60dSAndroid Build Coastguard Worker 	.type = TARGET_NULL,
276*8617a60dSAndroid Build Coastguard Worker };
277*8617a60dSAndroid Build Coastguard Worker 
278*8617a60dSAndroid Build Coastguard Worker struct subprocess_target subprocess_stdin = {
279*8617a60dSAndroid Build Coastguard Worker 	.type = TARGET_FD,
280*8617a60dSAndroid Build Coastguard Worker 	.fd = STDIN_FILENO,
281*8617a60dSAndroid Build Coastguard Worker };
282*8617a60dSAndroid Build Coastguard Worker 
283*8617a60dSAndroid Build Coastguard Worker struct subprocess_target subprocess_stdout = {
284*8617a60dSAndroid Build Coastguard Worker 	.type = TARGET_FD,
285*8617a60dSAndroid Build Coastguard Worker 	.fd = STDOUT_FILENO,
286*8617a60dSAndroid Build Coastguard Worker };
287*8617a60dSAndroid Build Coastguard Worker 
288*8617a60dSAndroid Build Coastguard Worker struct subprocess_target subprocess_stderr = {
289*8617a60dSAndroid Build Coastguard Worker 	.type = TARGET_FD,
290*8617a60dSAndroid Build Coastguard Worker 	.fd = STDERR_FILENO,
291*8617a60dSAndroid Build Coastguard Worker };
292*8617a60dSAndroid Build Coastguard Worker 
293*8617a60dSAndroid Build Coastguard Worker test_mockable
subprocess_run(const char * const argv[],struct subprocess_target * input,struct subprocess_target * output,struct subprocess_target * error)294*8617a60dSAndroid Build Coastguard Worker int subprocess_run(const char *const argv[],
295*8617a60dSAndroid Build Coastguard Worker 		   struct subprocess_target *input,
296*8617a60dSAndroid Build Coastguard Worker 		   struct subprocess_target *output,
297*8617a60dSAndroid Build Coastguard Worker 		   struct subprocess_target *error)
298*8617a60dSAndroid Build Coastguard Worker {
299*8617a60dSAndroid Build Coastguard Worker 	int status;
300*8617a60dSAndroid Build Coastguard Worker 	pid_t pid = -1;
301*8617a60dSAndroid Build Coastguard Worker 
302*8617a60dSAndroid Build Coastguard Worker 	subprocess_log_call(argv);
303*8617a60dSAndroid Build Coastguard Worker 
304*8617a60dSAndroid Build Coastguard Worker 	if (!input)
305*8617a60dSAndroid Build Coastguard Worker 		input = &subprocess_stdin;
306*8617a60dSAndroid Build Coastguard Worker 	if (!output)
307*8617a60dSAndroid Build Coastguard Worker 		output = &subprocess_stdout;
308*8617a60dSAndroid Build Coastguard Worker 	if (!error)
309*8617a60dSAndroid Build Coastguard Worker 		error = &subprocess_stderr;
310*8617a60dSAndroid Build Coastguard Worker 
311*8617a60dSAndroid Build Coastguard Worker 	if (init_target_private(input) < 0)
312*8617a60dSAndroid Build Coastguard Worker 		goto fail;
313*8617a60dSAndroid Build Coastguard Worker 	if (init_target_private(output) < 0)
314*8617a60dSAndroid Build Coastguard Worker 		goto fail;
315*8617a60dSAndroid Build Coastguard Worker 	if (init_target_private(error) < 0)
316*8617a60dSAndroid Build Coastguard Worker 		goto fail;
317*8617a60dSAndroid Build Coastguard Worker 
318*8617a60dSAndroid Build Coastguard Worker 	if ((pid = fork()) < 0)
319*8617a60dSAndroid Build Coastguard Worker 		goto fail;
320*8617a60dSAndroid Build Coastguard Worker 	if (pid == 0) {
321*8617a60dSAndroid Build Coastguard Worker 		/* Child process */
322*8617a60dSAndroid Build Coastguard Worker 		if (connect_process_target(input, STDIN_FILENO) < 0)
323*8617a60dSAndroid Build Coastguard Worker 			goto fail;
324*8617a60dSAndroid Build Coastguard Worker 		if (connect_process_target(output, STDOUT_FILENO) < 0)
325*8617a60dSAndroid Build Coastguard Worker 			goto fail;
326*8617a60dSAndroid Build Coastguard Worker 		if (connect_process_target(error, STDERR_FILENO) < 0)
327*8617a60dSAndroid Build Coastguard Worker 			goto fail;
328*8617a60dSAndroid Build Coastguard Worker 		execvp(*argv, (char *const *)argv);
329*8617a60dSAndroid Build Coastguard Worker 		goto fail;
330*8617a60dSAndroid Build Coastguard Worker 	}
331*8617a60dSAndroid Build Coastguard Worker 
332*8617a60dSAndroid Build Coastguard Worker 	/* Parent process */
333*8617a60dSAndroid Build Coastguard Worker 	if (process_target_input(input) < 0)
334*8617a60dSAndroid Build Coastguard Worker 		goto fail;
335*8617a60dSAndroid Build Coastguard Worker 	if (process_target_output(output) < 0)
336*8617a60dSAndroid Build Coastguard Worker 		goto fail;
337*8617a60dSAndroid Build Coastguard Worker 	if (process_target_output(error) < 0)
338*8617a60dSAndroid Build Coastguard Worker 		goto fail;
339*8617a60dSAndroid Build Coastguard Worker 
340*8617a60dSAndroid Build Coastguard Worker 	if (waitpid(pid, &status, 0) < 0)
341*8617a60dSAndroid Build Coastguard Worker 		goto fail;
342*8617a60dSAndroid Build Coastguard Worker 
343*8617a60dSAndroid Build Coastguard Worker 	if (WIFEXITED(status))
344*8617a60dSAndroid Build Coastguard Worker 		return WEXITSTATUS(status);
345*8617a60dSAndroid Build Coastguard Worker 
346*8617a60dSAndroid Build Coastguard Worker  fail:
347*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("Failed to execute external command: %s\n", strerror(errno));
348*8617a60dSAndroid Build Coastguard Worker 	if (pid == 0)
349*8617a60dSAndroid Build Coastguard Worker 		exit(127);
350*8617a60dSAndroid Build Coastguard Worker 	return -1;
351*8617a60dSAndroid Build Coastguard Worker }
352