1*00b67f09SDavid van Moolenbroek /* $NetBSD: process.c,v 1.3 2014/12/10 04:38:03 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Automated Testing Framework (atf)
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Copyright (c) 2007 The NetBSD Foundation, Inc.
7*00b67f09SDavid van Moolenbroek * All rights reserved.
8*00b67f09SDavid van Moolenbroek *
9*00b67f09SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
10*00b67f09SDavid van Moolenbroek * modification, are permitted provided that the following conditions
11*00b67f09SDavid van Moolenbroek * are met:
12*00b67f09SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
13*00b67f09SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
14*00b67f09SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
15*00b67f09SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
16*00b67f09SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
17*00b67f09SDavid van Moolenbroek *
18*00b67f09SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
19*00b67f09SDavid van Moolenbroek * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20*00b67f09SDavid van Moolenbroek * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21*00b67f09SDavid van Moolenbroek * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22*00b67f09SDavid van Moolenbroek * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
23*00b67f09SDavid van Moolenbroek * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*00b67f09SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25*00b67f09SDavid van Moolenbroek * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*00b67f09SDavid van Moolenbroek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27*00b67f09SDavid van Moolenbroek * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28*00b67f09SDavid van Moolenbroek * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29*00b67f09SDavid van Moolenbroek * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*00b67f09SDavid van Moolenbroek */
31*00b67f09SDavid van Moolenbroek
32*00b67f09SDavid van Moolenbroek #include <sys/types.h>
33*00b67f09SDavid van Moolenbroek #include <sys/wait.h>
34*00b67f09SDavid van Moolenbroek
35*00b67f09SDavid van Moolenbroek #include <errno.h>
36*00b67f09SDavid van Moolenbroek #include <fcntl.h>
37*00b67f09SDavid van Moolenbroek #include <stdio.h>
38*00b67f09SDavid van Moolenbroek #include <stdlib.h>
39*00b67f09SDavid van Moolenbroek #include <string.h>
40*00b67f09SDavid van Moolenbroek #include <unistd.h>
41*00b67f09SDavid van Moolenbroek
42*00b67f09SDavid van Moolenbroek #include "atf-c/defs.h"
43*00b67f09SDavid van Moolenbroek #include "atf-c/error.h"
44*00b67f09SDavid van Moolenbroek
45*00b67f09SDavid van Moolenbroek #include "process.h"
46*00b67f09SDavid van Moolenbroek #include "sanity.h"
47*00b67f09SDavid van Moolenbroek
48*00b67f09SDavid van Moolenbroek /* This prototype is not in the header file because this is a private
49*00b67f09SDavid van Moolenbroek * function; however, we need to access it during testing. */
50*00b67f09SDavid van Moolenbroek atf_error_t atf_process_status_init(atf_process_status_t *, int);
51*00b67f09SDavid van Moolenbroek
52*00b67f09SDavid van Moolenbroek /* ---------------------------------------------------------------------
53*00b67f09SDavid van Moolenbroek * The "stream_prepare" auxiliary type.
54*00b67f09SDavid van Moolenbroek * --------------------------------------------------------------------- */
55*00b67f09SDavid van Moolenbroek
56*00b67f09SDavid van Moolenbroek struct stream_prepare {
57*00b67f09SDavid van Moolenbroek const atf_process_stream_t *m_sb;
58*00b67f09SDavid van Moolenbroek
59*00b67f09SDavid van Moolenbroek bool m_pipefds_ok;
60*00b67f09SDavid van Moolenbroek int m_pipefds[2];
61*00b67f09SDavid van Moolenbroek };
62*00b67f09SDavid van Moolenbroek typedef struct stream_prepare stream_prepare_t;
63*00b67f09SDavid van Moolenbroek
64*00b67f09SDavid van Moolenbroek static
65*00b67f09SDavid van Moolenbroek atf_error_t
stream_prepare_init(stream_prepare_t * sp,const atf_process_stream_t * sb)66*00b67f09SDavid van Moolenbroek stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
67*00b67f09SDavid van Moolenbroek {
68*00b67f09SDavid van Moolenbroek atf_error_t err;
69*00b67f09SDavid van Moolenbroek
70*00b67f09SDavid van Moolenbroek const int type = atf_process_stream_type(sb);
71*00b67f09SDavid van Moolenbroek
72*00b67f09SDavid van Moolenbroek sp->m_sb = sb;
73*00b67f09SDavid van Moolenbroek sp->m_pipefds_ok = false;
74*00b67f09SDavid van Moolenbroek
75*00b67f09SDavid van Moolenbroek if (type == atf_process_stream_type_capture) {
76*00b67f09SDavid van Moolenbroek if (pipe(sp->m_pipefds) == -1)
77*00b67f09SDavid van Moolenbroek err = atf_libc_error(errno, "Failed to create pipe");
78*00b67f09SDavid van Moolenbroek else {
79*00b67f09SDavid van Moolenbroek err = atf_no_error();
80*00b67f09SDavid van Moolenbroek sp->m_pipefds_ok = true;
81*00b67f09SDavid van Moolenbroek }
82*00b67f09SDavid van Moolenbroek } else
83*00b67f09SDavid van Moolenbroek err = atf_no_error();
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek return err;
86*00b67f09SDavid van Moolenbroek }
87*00b67f09SDavid van Moolenbroek
88*00b67f09SDavid van Moolenbroek static
89*00b67f09SDavid van Moolenbroek void
stream_prepare_fini(stream_prepare_t * sp)90*00b67f09SDavid van Moolenbroek stream_prepare_fini(stream_prepare_t *sp)
91*00b67f09SDavid van Moolenbroek {
92*00b67f09SDavid van Moolenbroek if (sp->m_pipefds_ok) {
93*00b67f09SDavid van Moolenbroek close(sp->m_pipefds[0]);
94*00b67f09SDavid van Moolenbroek close(sp->m_pipefds[1]);
95*00b67f09SDavid van Moolenbroek }
96*00b67f09SDavid van Moolenbroek }
97*00b67f09SDavid van Moolenbroek
98*00b67f09SDavid van Moolenbroek /* ---------------------------------------------------------------------
99*00b67f09SDavid van Moolenbroek * The "atf_process_stream" type.
100*00b67f09SDavid van Moolenbroek * --------------------------------------------------------------------- */
101*00b67f09SDavid van Moolenbroek
102*00b67f09SDavid van Moolenbroek const int atf_process_stream_type_capture = 1;
103*00b67f09SDavid van Moolenbroek const int atf_process_stream_type_connect = 2;
104*00b67f09SDavid van Moolenbroek const int atf_process_stream_type_inherit = 3;
105*00b67f09SDavid van Moolenbroek const int atf_process_stream_type_redirect_fd = 4;
106*00b67f09SDavid van Moolenbroek const int atf_process_stream_type_redirect_path = 5;
107*00b67f09SDavid van Moolenbroek
108*00b67f09SDavid van Moolenbroek static
109*00b67f09SDavid van Moolenbroek bool
stream_is_valid(const atf_process_stream_t * sb)110*00b67f09SDavid van Moolenbroek stream_is_valid(const atf_process_stream_t *sb)
111*00b67f09SDavid van Moolenbroek {
112*00b67f09SDavid van Moolenbroek return (sb->m_type == atf_process_stream_type_capture) ||
113*00b67f09SDavid van Moolenbroek (sb->m_type == atf_process_stream_type_connect) ||
114*00b67f09SDavid van Moolenbroek (sb->m_type == atf_process_stream_type_inherit) ||
115*00b67f09SDavid van Moolenbroek (sb->m_type == atf_process_stream_type_redirect_fd) ||
116*00b67f09SDavid van Moolenbroek (sb->m_type == atf_process_stream_type_redirect_path);
117*00b67f09SDavid van Moolenbroek }
118*00b67f09SDavid van Moolenbroek
119*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_stream_init_capture(atf_process_stream_t * sb)120*00b67f09SDavid van Moolenbroek atf_process_stream_init_capture(atf_process_stream_t *sb)
121*00b67f09SDavid van Moolenbroek {
122*00b67f09SDavid van Moolenbroek sb->m_type = atf_process_stream_type_capture;
123*00b67f09SDavid van Moolenbroek
124*00b67f09SDavid van Moolenbroek POST(stream_is_valid(sb));
125*00b67f09SDavid van Moolenbroek return atf_no_error();
126*00b67f09SDavid van Moolenbroek }
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_stream_init_connect(atf_process_stream_t * sb,const int src_fd,const int tgt_fd)129*00b67f09SDavid van Moolenbroek atf_process_stream_init_connect(atf_process_stream_t *sb,
130*00b67f09SDavid van Moolenbroek const int src_fd, const int tgt_fd)
131*00b67f09SDavid van Moolenbroek {
132*00b67f09SDavid van Moolenbroek PRE(src_fd >= 0);
133*00b67f09SDavid van Moolenbroek PRE(tgt_fd >= 0);
134*00b67f09SDavid van Moolenbroek PRE(src_fd != tgt_fd);
135*00b67f09SDavid van Moolenbroek
136*00b67f09SDavid van Moolenbroek sb->m_type = atf_process_stream_type_connect;
137*00b67f09SDavid van Moolenbroek sb->m_src_fd = src_fd;
138*00b67f09SDavid van Moolenbroek sb->m_tgt_fd = tgt_fd;
139*00b67f09SDavid van Moolenbroek
140*00b67f09SDavid van Moolenbroek POST(stream_is_valid(sb));
141*00b67f09SDavid van Moolenbroek return atf_no_error();
142*00b67f09SDavid van Moolenbroek }
143*00b67f09SDavid van Moolenbroek
144*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_stream_init_inherit(atf_process_stream_t * sb)145*00b67f09SDavid van Moolenbroek atf_process_stream_init_inherit(atf_process_stream_t *sb)
146*00b67f09SDavid van Moolenbroek {
147*00b67f09SDavid van Moolenbroek sb->m_type = atf_process_stream_type_inherit;
148*00b67f09SDavid van Moolenbroek
149*00b67f09SDavid van Moolenbroek POST(stream_is_valid(sb));
150*00b67f09SDavid van Moolenbroek return atf_no_error();
151*00b67f09SDavid van Moolenbroek }
152*00b67f09SDavid van Moolenbroek
153*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_stream_init_redirect_fd(atf_process_stream_t * sb,const int fd)154*00b67f09SDavid van Moolenbroek atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
155*00b67f09SDavid van Moolenbroek const int fd)
156*00b67f09SDavid van Moolenbroek {
157*00b67f09SDavid van Moolenbroek sb->m_type = atf_process_stream_type_redirect_fd;
158*00b67f09SDavid van Moolenbroek sb->m_fd = fd;
159*00b67f09SDavid van Moolenbroek
160*00b67f09SDavid van Moolenbroek POST(stream_is_valid(sb));
161*00b67f09SDavid van Moolenbroek return atf_no_error();
162*00b67f09SDavid van Moolenbroek }
163*00b67f09SDavid van Moolenbroek
164*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_stream_init_redirect_path(atf_process_stream_t * sb,const atf_fs_path_t * path)165*00b67f09SDavid van Moolenbroek atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
166*00b67f09SDavid van Moolenbroek const atf_fs_path_t *path)
167*00b67f09SDavid van Moolenbroek {
168*00b67f09SDavid van Moolenbroek sb->m_type = atf_process_stream_type_redirect_path;
169*00b67f09SDavid van Moolenbroek sb->m_path = path;
170*00b67f09SDavid van Moolenbroek
171*00b67f09SDavid van Moolenbroek POST(stream_is_valid(sb));
172*00b67f09SDavid van Moolenbroek return atf_no_error();
173*00b67f09SDavid van Moolenbroek }
174*00b67f09SDavid van Moolenbroek
175*00b67f09SDavid van Moolenbroek void
atf_process_stream_fini(atf_process_stream_t * sb)176*00b67f09SDavid van Moolenbroek atf_process_stream_fini(atf_process_stream_t *sb)
177*00b67f09SDavid van Moolenbroek {
178*00b67f09SDavid van Moolenbroek PRE(stream_is_valid(sb));
179*00b67f09SDavid van Moolenbroek }
180*00b67f09SDavid van Moolenbroek
181*00b67f09SDavid van Moolenbroek int
atf_process_stream_type(const atf_process_stream_t * sb)182*00b67f09SDavid van Moolenbroek atf_process_stream_type(const atf_process_stream_t *sb)
183*00b67f09SDavid van Moolenbroek {
184*00b67f09SDavid van Moolenbroek PRE(stream_is_valid(sb));
185*00b67f09SDavid van Moolenbroek
186*00b67f09SDavid van Moolenbroek return sb->m_type;
187*00b67f09SDavid van Moolenbroek }
188*00b67f09SDavid van Moolenbroek
189*00b67f09SDavid van Moolenbroek /* ---------------------------------------------------------------------
190*00b67f09SDavid van Moolenbroek * The "atf_process_status" type.
191*00b67f09SDavid van Moolenbroek * --------------------------------------------------------------------- */
192*00b67f09SDavid van Moolenbroek
193*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_status_init(atf_process_status_t * s,int status)194*00b67f09SDavid van Moolenbroek atf_process_status_init(atf_process_status_t *s, int status)
195*00b67f09SDavid van Moolenbroek {
196*00b67f09SDavid van Moolenbroek s->m_status = status;
197*00b67f09SDavid van Moolenbroek
198*00b67f09SDavid van Moolenbroek return atf_no_error();
199*00b67f09SDavid van Moolenbroek }
200*00b67f09SDavid van Moolenbroek
201*00b67f09SDavid van Moolenbroek void
atf_process_status_fini(atf_process_status_t * s ATF_DEFS_ATTRIBUTE_UNUSED)202*00b67f09SDavid van Moolenbroek atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
203*00b67f09SDavid van Moolenbroek {
204*00b67f09SDavid van Moolenbroek }
205*00b67f09SDavid van Moolenbroek
206*00b67f09SDavid van Moolenbroek bool
atf_process_status_exited(const atf_process_status_t * s)207*00b67f09SDavid van Moolenbroek atf_process_status_exited(const atf_process_status_t *s)
208*00b67f09SDavid van Moolenbroek {
209*00b67f09SDavid van Moolenbroek int mutable_status = s->m_status;
210*00b67f09SDavid van Moolenbroek return WIFEXITED(mutable_status);
211*00b67f09SDavid van Moolenbroek }
212*00b67f09SDavid van Moolenbroek
213*00b67f09SDavid van Moolenbroek int
atf_process_status_exitstatus(const atf_process_status_t * s)214*00b67f09SDavid van Moolenbroek atf_process_status_exitstatus(const atf_process_status_t *s)
215*00b67f09SDavid van Moolenbroek {
216*00b67f09SDavid van Moolenbroek PRE(atf_process_status_exited(s));
217*00b67f09SDavid van Moolenbroek int mutable_status = s->m_status;
218*00b67f09SDavid van Moolenbroek return WEXITSTATUS(mutable_status);
219*00b67f09SDavid van Moolenbroek }
220*00b67f09SDavid van Moolenbroek
221*00b67f09SDavid van Moolenbroek bool
atf_process_status_signaled(const atf_process_status_t * s)222*00b67f09SDavid van Moolenbroek atf_process_status_signaled(const atf_process_status_t *s)
223*00b67f09SDavid van Moolenbroek {
224*00b67f09SDavid van Moolenbroek int mutable_status = s->m_status;
225*00b67f09SDavid van Moolenbroek return WIFSIGNALED(mutable_status);
226*00b67f09SDavid van Moolenbroek }
227*00b67f09SDavid van Moolenbroek
228*00b67f09SDavid van Moolenbroek int
atf_process_status_termsig(const atf_process_status_t * s)229*00b67f09SDavid van Moolenbroek atf_process_status_termsig(const atf_process_status_t *s)
230*00b67f09SDavid van Moolenbroek {
231*00b67f09SDavid van Moolenbroek PRE(atf_process_status_signaled(s));
232*00b67f09SDavid van Moolenbroek int mutable_status = s->m_status;
233*00b67f09SDavid van Moolenbroek return WTERMSIG(mutable_status);
234*00b67f09SDavid van Moolenbroek }
235*00b67f09SDavid van Moolenbroek
236*00b67f09SDavid van Moolenbroek bool
atf_process_status_coredump(const atf_process_status_t * s)237*00b67f09SDavid van Moolenbroek atf_process_status_coredump(const atf_process_status_t *s)
238*00b67f09SDavid van Moolenbroek {
239*00b67f09SDavid van Moolenbroek PRE(atf_process_status_signaled(s));
240*00b67f09SDavid van Moolenbroek #if defined(WCOREDUMP)
241*00b67f09SDavid van Moolenbroek int mutable_status = s->m_status;
242*00b67f09SDavid van Moolenbroek return WCOREDUMP(mutable_status);
243*00b67f09SDavid van Moolenbroek #else
244*00b67f09SDavid van Moolenbroek return false;
245*00b67f09SDavid van Moolenbroek #endif
246*00b67f09SDavid van Moolenbroek }
247*00b67f09SDavid van Moolenbroek
248*00b67f09SDavid van Moolenbroek /* ---------------------------------------------------------------------
249*00b67f09SDavid van Moolenbroek * The "atf_process_child" type.
250*00b67f09SDavid van Moolenbroek * --------------------------------------------------------------------- */
251*00b67f09SDavid van Moolenbroek
252*00b67f09SDavid van Moolenbroek static
253*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_child_init(atf_process_child_t * c)254*00b67f09SDavid van Moolenbroek atf_process_child_init(atf_process_child_t *c)
255*00b67f09SDavid van Moolenbroek {
256*00b67f09SDavid van Moolenbroek c->m_pid = 0;
257*00b67f09SDavid van Moolenbroek c->m_stdout = -1;
258*00b67f09SDavid van Moolenbroek c->m_stderr = -1;
259*00b67f09SDavid van Moolenbroek
260*00b67f09SDavid van Moolenbroek return atf_no_error();
261*00b67f09SDavid van Moolenbroek }
262*00b67f09SDavid van Moolenbroek
263*00b67f09SDavid van Moolenbroek static
264*00b67f09SDavid van Moolenbroek void
atf_process_child_fini(atf_process_child_t * c)265*00b67f09SDavid van Moolenbroek atf_process_child_fini(atf_process_child_t *c)
266*00b67f09SDavid van Moolenbroek {
267*00b67f09SDavid van Moolenbroek if (c->m_stdout != -1)
268*00b67f09SDavid van Moolenbroek close(c->m_stdout);
269*00b67f09SDavid van Moolenbroek if (c->m_stderr != -1)
270*00b67f09SDavid van Moolenbroek close(c->m_stderr);
271*00b67f09SDavid van Moolenbroek }
272*00b67f09SDavid van Moolenbroek
273*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_child_wait(atf_process_child_t * c,atf_process_status_t * s)274*00b67f09SDavid van Moolenbroek atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
275*00b67f09SDavid van Moolenbroek {
276*00b67f09SDavid van Moolenbroek atf_error_t err;
277*00b67f09SDavid van Moolenbroek int status;
278*00b67f09SDavid van Moolenbroek
279*00b67f09SDavid van Moolenbroek if (waitpid(c->m_pid, &status, 0) == -1)
280*00b67f09SDavid van Moolenbroek err = atf_libc_error(errno, "Failed waiting for process %d",
281*00b67f09SDavid van Moolenbroek c->m_pid);
282*00b67f09SDavid van Moolenbroek else {
283*00b67f09SDavid van Moolenbroek atf_process_child_fini(c);
284*00b67f09SDavid van Moolenbroek err = atf_process_status_init(s, status);
285*00b67f09SDavid van Moolenbroek }
286*00b67f09SDavid van Moolenbroek
287*00b67f09SDavid van Moolenbroek return err;
288*00b67f09SDavid van Moolenbroek }
289*00b67f09SDavid van Moolenbroek
290*00b67f09SDavid van Moolenbroek pid_t
atf_process_child_pid(const atf_process_child_t * c)291*00b67f09SDavid van Moolenbroek atf_process_child_pid(const atf_process_child_t *c)
292*00b67f09SDavid van Moolenbroek {
293*00b67f09SDavid van Moolenbroek return c->m_pid;
294*00b67f09SDavid van Moolenbroek }
295*00b67f09SDavid van Moolenbroek
296*00b67f09SDavid van Moolenbroek int
atf_process_child_stdout(atf_process_child_t * c)297*00b67f09SDavid van Moolenbroek atf_process_child_stdout(atf_process_child_t *c)
298*00b67f09SDavid van Moolenbroek {
299*00b67f09SDavid van Moolenbroek PRE(c->m_stdout != -1);
300*00b67f09SDavid van Moolenbroek return c->m_stdout;
301*00b67f09SDavid van Moolenbroek }
302*00b67f09SDavid van Moolenbroek
303*00b67f09SDavid van Moolenbroek int
atf_process_child_stderr(atf_process_child_t * c)304*00b67f09SDavid van Moolenbroek atf_process_child_stderr(atf_process_child_t *c)
305*00b67f09SDavid van Moolenbroek {
306*00b67f09SDavid van Moolenbroek PRE(c->m_stderr != -1);
307*00b67f09SDavid van Moolenbroek return c->m_stderr;
308*00b67f09SDavid van Moolenbroek }
309*00b67f09SDavid van Moolenbroek
310*00b67f09SDavid van Moolenbroek /* ---------------------------------------------------------------------
311*00b67f09SDavid van Moolenbroek * Free functions.
312*00b67f09SDavid van Moolenbroek * --------------------------------------------------------------------- */
313*00b67f09SDavid van Moolenbroek
314*00b67f09SDavid van Moolenbroek static
315*00b67f09SDavid van Moolenbroek atf_error_t
safe_dup(const int oldfd,const int newfd)316*00b67f09SDavid van Moolenbroek safe_dup(const int oldfd, const int newfd)
317*00b67f09SDavid van Moolenbroek {
318*00b67f09SDavid van Moolenbroek atf_error_t err;
319*00b67f09SDavid van Moolenbroek
320*00b67f09SDavid van Moolenbroek if (oldfd != newfd) {
321*00b67f09SDavid van Moolenbroek if (dup2(oldfd, newfd) == -1) {
322*00b67f09SDavid van Moolenbroek err = atf_libc_error(errno, "Could not allocate file descriptor");
323*00b67f09SDavid van Moolenbroek } else {
324*00b67f09SDavid van Moolenbroek close(oldfd);
325*00b67f09SDavid van Moolenbroek err = atf_no_error();
326*00b67f09SDavid van Moolenbroek }
327*00b67f09SDavid van Moolenbroek } else
328*00b67f09SDavid van Moolenbroek err = atf_no_error();
329*00b67f09SDavid van Moolenbroek
330*00b67f09SDavid van Moolenbroek return err;
331*00b67f09SDavid van Moolenbroek }
332*00b67f09SDavid van Moolenbroek
333*00b67f09SDavid van Moolenbroek static
334*00b67f09SDavid van Moolenbroek atf_error_t
child_connect(const stream_prepare_t * sp,int procfd)335*00b67f09SDavid van Moolenbroek child_connect(const stream_prepare_t *sp, int procfd)
336*00b67f09SDavid van Moolenbroek {
337*00b67f09SDavid van Moolenbroek atf_error_t err;
338*00b67f09SDavid van Moolenbroek const int type = atf_process_stream_type(sp->m_sb);
339*00b67f09SDavid van Moolenbroek
340*00b67f09SDavid van Moolenbroek if (type == atf_process_stream_type_capture) {
341*00b67f09SDavid van Moolenbroek close(sp->m_pipefds[0]);
342*00b67f09SDavid van Moolenbroek err = safe_dup(sp->m_pipefds[1], procfd);
343*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_connect) {
344*00b67f09SDavid van Moolenbroek if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
345*00b67f09SDavid van Moolenbroek err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
346*00b67f09SDavid van Moolenbroek sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
347*00b67f09SDavid van Moolenbroek else
348*00b67f09SDavid van Moolenbroek err = atf_no_error();
349*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_inherit) {
350*00b67f09SDavid van Moolenbroek err = atf_no_error();
351*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_redirect_fd) {
352*00b67f09SDavid van Moolenbroek err = safe_dup(sp->m_sb->m_fd, procfd);
353*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_redirect_path) {
354*00b67f09SDavid van Moolenbroek int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
355*00b67f09SDavid van Moolenbroek O_WRONLY | O_CREAT | O_TRUNC, 0644);
356*00b67f09SDavid van Moolenbroek if (aux == -1)
357*00b67f09SDavid van Moolenbroek err = atf_libc_error(errno, "Could not create %s",
358*00b67f09SDavid van Moolenbroek atf_fs_path_cstring(sp->m_sb->m_path));
359*00b67f09SDavid van Moolenbroek else {
360*00b67f09SDavid van Moolenbroek err = safe_dup(aux, procfd);
361*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
362*00b67f09SDavid van Moolenbroek close(aux);
363*00b67f09SDavid van Moolenbroek }
364*00b67f09SDavid van Moolenbroek } else {
365*00b67f09SDavid van Moolenbroek UNREACHABLE;
366*00b67f09SDavid van Moolenbroek err = atf_no_error();
367*00b67f09SDavid van Moolenbroek }
368*00b67f09SDavid van Moolenbroek
369*00b67f09SDavid van Moolenbroek return err;
370*00b67f09SDavid van Moolenbroek }
371*00b67f09SDavid van Moolenbroek
372*00b67f09SDavid van Moolenbroek static
373*00b67f09SDavid van Moolenbroek void
parent_connect(const stream_prepare_t * sp,int * fd)374*00b67f09SDavid van Moolenbroek parent_connect(const stream_prepare_t *sp, int *fd)
375*00b67f09SDavid van Moolenbroek {
376*00b67f09SDavid van Moolenbroek const int type = atf_process_stream_type(sp->m_sb);
377*00b67f09SDavid van Moolenbroek
378*00b67f09SDavid van Moolenbroek if (type == atf_process_stream_type_capture) {
379*00b67f09SDavid van Moolenbroek close(sp->m_pipefds[1]);
380*00b67f09SDavid van Moolenbroek *fd = sp->m_pipefds[0];
381*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_connect) {
382*00b67f09SDavid van Moolenbroek /* Do nothing. */
383*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_inherit) {
384*00b67f09SDavid van Moolenbroek /* Do nothing. */
385*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_redirect_fd) {
386*00b67f09SDavid van Moolenbroek /* Do nothing. */
387*00b67f09SDavid van Moolenbroek } else if (type == atf_process_stream_type_redirect_path) {
388*00b67f09SDavid van Moolenbroek /* Do nothing. */
389*00b67f09SDavid van Moolenbroek } else {
390*00b67f09SDavid van Moolenbroek UNREACHABLE;
391*00b67f09SDavid van Moolenbroek }
392*00b67f09SDavid van Moolenbroek }
393*00b67f09SDavid van Moolenbroek
394*00b67f09SDavid van Moolenbroek static
395*00b67f09SDavid van Moolenbroek atf_error_t
do_parent(atf_process_child_t * c,const pid_t pid,const stream_prepare_t * outsp,const stream_prepare_t * errsp)396*00b67f09SDavid van Moolenbroek do_parent(atf_process_child_t *c,
397*00b67f09SDavid van Moolenbroek const pid_t pid,
398*00b67f09SDavid van Moolenbroek const stream_prepare_t *outsp,
399*00b67f09SDavid van Moolenbroek const stream_prepare_t *errsp)
400*00b67f09SDavid van Moolenbroek {
401*00b67f09SDavid van Moolenbroek atf_error_t err;
402*00b67f09SDavid van Moolenbroek
403*00b67f09SDavid van Moolenbroek err = atf_process_child_init(c);
404*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
405*00b67f09SDavid van Moolenbroek goto out;
406*00b67f09SDavid van Moolenbroek
407*00b67f09SDavid van Moolenbroek c->m_pid = pid;
408*00b67f09SDavid van Moolenbroek
409*00b67f09SDavid van Moolenbroek parent_connect(outsp, &c->m_stdout);
410*00b67f09SDavid van Moolenbroek parent_connect(errsp, &c->m_stderr);
411*00b67f09SDavid van Moolenbroek
412*00b67f09SDavid van Moolenbroek out:
413*00b67f09SDavid van Moolenbroek return err;
414*00b67f09SDavid van Moolenbroek }
415*00b67f09SDavid van Moolenbroek
416*00b67f09SDavid van Moolenbroek static
417*00b67f09SDavid van Moolenbroek void
418*00b67f09SDavid van Moolenbroek do_child(void (*)(void *),
419*00b67f09SDavid van Moolenbroek void *,
420*00b67f09SDavid van Moolenbroek const stream_prepare_t *,
421*00b67f09SDavid van Moolenbroek const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
422*00b67f09SDavid van Moolenbroek
423*00b67f09SDavid van Moolenbroek static
424*00b67f09SDavid van Moolenbroek void
do_child(void (* start)(void *),void * v,const stream_prepare_t * outsp,const stream_prepare_t * errsp)425*00b67f09SDavid van Moolenbroek do_child(void (*start)(void *),
426*00b67f09SDavid van Moolenbroek void *v,
427*00b67f09SDavid van Moolenbroek const stream_prepare_t *outsp,
428*00b67f09SDavid van Moolenbroek const stream_prepare_t *errsp)
429*00b67f09SDavid van Moolenbroek {
430*00b67f09SDavid van Moolenbroek atf_error_t err;
431*00b67f09SDavid van Moolenbroek
432*00b67f09SDavid van Moolenbroek err = child_connect(outsp, STDOUT_FILENO);
433*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
434*00b67f09SDavid van Moolenbroek goto out;
435*00b67f09SDavid van Moolenbroek
436*00b67f09SDavid van Moolenbroek err = child_connect(errsp, STDERR_FILENO);
437*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
438*00b67f09SDavid van Moolenbroek goto out;
439*00b67f09SDavid van Moolenbroek
440*00b67f09SDavid van Moolenbroek start(v);
441*00b67f09SDavid van Moolenbroek UNREACHABLE;
442*00b67f09SDavid van Moolenbroek
443*00b67f09SDavid van Moolenbroek out:
444*00b67f09SDavid van Moolenbroek if (atf_is_error(err)) {
445*00b67f09SDavid van Moolenbroek char buf[1024];
446*00b67f09SDavid van Moolenbroek
447*00b67f09SDavid van Moolenbroek atf_error_format(err, buf, sizeof(buf));
448*00b67f09SDavid van Moolenbroek fprintf(stderr, "Unhandled error: %s\n", buf);
449*00b67f09SDavid van Moolenbroek atf_error_free(err);
450*00b67f09SDavid van Moolenbroek
451*00b67f09SDavid van Moolenbroek exit(EXIT_FAILURE);
452*00b67f09SDavid van Moolenbroek } else
453*00b67f09SDavid van Moolenbroek exit(EXIT_SUCCESS);
454*00b67f09SDavid van Moolenbroek }
455*00b67f09SDavid van Moolenbroek
456*00b67f09SDavid van Moolenbroek static
457*00b67f09SDavid van Moolenbroek atf_error_t
fork_with_streams(atf_process_child_t * c,void (* start)(void *),const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void * v)458*00b67f09SDavid van Moolenbroek fork_with_streams(atf_process_child_t *c,
459*00b67f09SDavid van Moolenbroek void (*start)(void *),
460*00b67f09SDavid van Moolenbroek const atf_process_stream_t *outsb,
461*00b67f09SDavid van Moolenbroek const atf_process_stream_t *errsb,
462*00b67f09SDavid van Moolenbroek void *v)
463*00b67f09SDavid van Moolenbroek {
464*00b67f09SDavid van Moolenbroek atf_error_t err;
465*00b67f09SDavid van Moolenbroek stream_prepare_t outsp;
466*00b67f09SDavid van Moolenbroek stream_prepare_t errsp;
467*00b67f09SDavid van Moolenbroek pid_t pid;
468*00b67f09SDavid van Moolenbroek
469*00b67f09SDavid van Moolenbroek err = stream_prepare_init(&outsp, outsb);
470*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
471*00b67f09SDavid van Moolenbroek goto out;
472*00b67f09SDavid van Moolenbroek
473*00b67f09SDavid van Moolenbroek err = stream_prepare_init(&errsp, errsb);
474*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
475*00b67f09SDavid van Moolenbroek goto err_outpipe;
476*00b67f09SDavid van Moolenbroek
477*00b67f09SDavid van Moolenbroek pid = fork();
478*00b67f09SDavid van Moolenbroek if (pid == -1) {
479*00b67f09SDavid van Moolenbroek err = atf_libc_error(errno, "Failed to fork");
480*00b67f09SDavid van Moolenbroek goto err_errpipe;
481*00b67f09SDavid van Moolenbroek }
482*00b67f09SDavid van Moolenbroek
483*00b67f09SDavid van Moolenbroek if (pid == 0) {
484*00b67f09SDavid van Moolenbroek do_child(start, v, &outsp, &errsp);
485*00b67f09SDavid van Moolenbroek UNREACHABLE;
486*00b67f09SDavid van Moolenbroek abort();
487*00b67f09SDavid van Moolenbroek err = atf_no_error();
488*00b67f09SDavid van Moolenbroek } else {
489*00b67f09SDavid van Moolenbroek err = do_parent(c, pid, &outsp, &errsp);
490*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
491*00b67f09SDavid van Moolenbroek goto err_errpipe;
492*00b67f09SDavid van Moolenbroek }
493*00b67f09SDavid van Moolenbroek
494*00b67f09SDavid van Moolenbroek goto out;
495*00b67f09SDavid van Moolenbroek
496*00b67f09SDavid van Moolenbroek err_errpipe:
497*00b67f09SDavid van Moolenbroek stream_prepare_fini(&errsp);
498*00b67f09SDavid van Moolenbroek err_outpipe:
499*00b67f09SDavid van Moolenbroek stream_prepare_fini(&outsp);
500*00b67f09SDavid van Moolenbroek
501*00b67f09SDavid van Moolenbroek out:
502*00b67f09SDavid van Moolenbroek return err;
503*00b67f09SDavid van Moolenbroek }
504*00b67f09SDavid van Moolenbroek
505*00b67f09SDavid van Moolenbroek static
506*00b67f09SDavid van Moolenbroek atf_error_t
init_stream_w_default(const atf_process_stream_t * usersb,atf_process_stream_t * inheritsb,const atf_process_stream_t ** realsb)507*00b67f09SDavid van Moolenbroek init_stream_w_default(const atf_process_stream_t *usersb,
508*00b67f09SDavid van Moolenbroek atf_process_stream_t *inheritsb,
509*00b67f09SDavid van Moolenbroek const atf_process_stream_t **realsb)
510*00b67f09SDavid van Moolenbroek {
511*00b67f09SDavid van Moolenbroek atf_error_t err;
512*00b67f09SDavid van Moolenbroek
513*00b67f09SDavid van Moolenbroek if (usersb == NULL) {
514*00b67f09SDavid van Moolenbroek err = atf_process_stream_init_inherit(inheritsb);
515*00b67f09SDavid van Moolenbroek if (!atf_is_error(err))
516*00b67f09SDavid van Moolenbroek *realsb = inheritsb;
517*00b67f09SDavid van Moolenbroek } else {
518*00b67f09SDavid van Moolenbroek err = atf_no_error();
519*00b67f09SDavid van Moolenbroek *realsb = usersb;
520*00b67f09SDavid van Moolenbroek }
521*00b67f09SDavid van Moolenbroek
522*00b67f09SDavid van Moolenbroek return err;
523*00b67f09SDavid van Moolenbroek }
524*00b67f09SDavid van Moolenbroek
525*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_fork(atf_process_child_t * c,void (* start)(void *),const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void * v)526*00b67f09SDavid van Moolenbroek atf_process_fork(atf_process_child_t *c,
527*00b67f09SDavid van Moolenbroek void (*start)(void *),
528*00b67f09SDavid van Moolenbroek const atf_process_stream_t *outsb,
529*00b67f09SDavid van Moolenbroek const atf_process_stream_t *errsb,
530*00b67f09SDavid van Moolenbroek void *v)
531*00b67f09SDavid van Moolenbroek {
532*00b67f09SDavid van Moolenbroek atf_error_t err;
533*00b67f09SDavid van Moolenbroek atf_process_stream_t inherit_outsb, inherit_errsb;
534*00b67f09SDavid van Moolenbroek const atf_process_stream_t *real_outsb, *real_errsb;
535*00b67f09SDavid van Moolenbroek
536*00b67f09SDavid van Moolenbroek real_outsb = NULL; /* Shut up GCC warning. */
537*00b67f09SDavid van Moolenbroek err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
538*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
539*00b67f09SDavid van Moolenbroek goto out;
540*00b67f09SDavid van Moolenbroek
541*00b67f09SDavid van Moolenbroek real_errsb = NULL; /* Shut up GCC warning. */
542*00b67f09SDavid van Moolenbroek err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
543*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
544*00b67f09SDavid van Moolenbroek goto out_out;
545*00b67f09SDavid van Moolenbroek
546*00b67f09SDavid van Moolenbroek err = fork_with_streams(c, start, real_outsb, real_errsb, v);
547*00b67f09SDavid van Moolenbroek
548*00b67f09SDavid van Moolenbroek if (errsb == NULL)
549*00b67f09SDavid van Moolenbroek atf_process_stream_fini(&inherit_errsb);
550*00b67f09SDavid van Moolenbroek out_out:
551*00b67f09SDavid van Moolenbroek if (outsb == NULL)
552*00b67f09SDavid van Moolenbroek atf_process_stream_fini(&inherit_outsb);
553*00b67f09SDavid van Moolenbroek out:
554*00b67f09SDavid van Moolenbroek return err;
555*00b67f09SDavid van Moolenbroek }
556*00b67f09SDavid van Moolenbroek
557*00b67f09SDavid van Moolenbroek static
558*00b67f09SDavid van Moolenbroek int
const_execvp(const char * file,const char * const * argv)559*00b67f09SDavid van Moolenbroek const_execvp(const char *file, const char *const *argv)
560*00b67f09SDavid van Moolenbroek {
561*00b67f09SDavid van Moolenbroek #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
562*00b67f09SDavid van Moolenbroek return execvp(file, UNCONST(argv));
563*00b67f09SDavid van Moolenbroek #undef UNCONST
564*00b67f09SDavid van Moolenbroek }
565*00b67f09SDavid van Moolenbroek
566*00b67f09SDavid van Moolenbroek static
567*00b67f09SDavid van Moolenbroek atf_error_t
list_to_array(const atf_list_t * l,const char *** ap)568*00b67f09SDavid van Moolenbroek list_to_array(const atf_list_t *l, const char ***ap)
569*00b67f09SDavid van Moolenbroek {
570*00b67f09SDavid van Moolenbroek atf_error_t err;
571*00b67f09SDavid van Moolenbroek const char **a;
572*00b67f09SDavid van Moolenbroek
573*00b67f09SDavid van Moolenbroek a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
574*00b67f09SDavid van Moolenbroek if (a == NULL)
575*00b67f09SDavid van Moolenbroek err = atf_no_memory_error();
576*00b67f09SDavid van Moolenbroek else {
577*00b67f09SDavid van Moolenbroek const char **aiter;
578*00b67f09SDavid van Moolenbroek atf_list_citer_t liter;
579*00b67f09SDavid van Moolenbroek
580*00b67f09SDavid van Moolenbroek aiter = a;
581*00b67f09SDavid van Moolenbroek atf_list_for_each_c(liter, l) {
582*00b67f09SDavid van Moolenbroek *aiter = (const char *)atf_list_citer_data(liter);
583*00b67f09SDavid van Moolenbroek aiter++;
584*00b67f09SDavid van Moolenbroek }
585*00b67f09SDavid van Moolenbroek *aiter = NULL;
586*00b67f09SDavid van Moolenbroek
587*00b67f09SDavid van Moolenbroek err = atf_no_error();
588*00b67f09SDavid van Moolenbroek *ap = a;
589*00b67f09SDavid van Moolenbroek }
590*00b67f09SDavid van Moolenbroek
591*00b67f09SDavid van Moolenbroek return err;
592*00b67f09SDavid van Moolenbroek }
593*00b67f09SDavid van Moolenbroek
594*00b67f09SDavid van Moolenbroek struct exec_args {
595*00b67f09SDavid van Moolenbroek const atf_fs_path_t *m_prog;
596*00b67f09SDavid van Moolenbroek const char *const *m_argv;
597*00b67f09SDavid van Moolenbroek void (*m_prehook)(void);
598*00b67f09SDavid van Moolenbroek };
599*00b67f09SDavid van Moolenbroek
600*00b67f09SDavid van Moolenbroek static
601*00b67f09SDavid van Moolenbroek void
do_exec(void * v)602*00b67f09SDavid van Moolenbroek do_exec(void *v)
603*00b67f09SDavid van Moolenbroek {
604*00b67f09SDavid van Moolenbroek struct exec_args *ea = v;
605*00b67f09SDavid van Moolenbroek
606*00b67f09SDavid van Moolenbroek if (ea->m_prehook != NULL)
607*00b67f09SDavid van Moolenbroek ea->m_prehook();
608*00b67f09SDavid van Moolenbroek
609*00b67f09SDavid van Moolenbroek const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
610*00b67f09SDavid van Moolenbroek const int errnocopy = errno;
611*00b67f09SDavid van Moolenbroek INV(ret == -1);
612*00b67f09SDavid van Moolenbroek fprintf(stderr, "exec(%s) failed: %s\n",
613*00b67f09SDavid van Moolenbroek atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
614*00b67f09SDavid van Moolenbroek exit(EXIT_FAILURE);
615*00b67f09SDavid van Moolenbroek }
616*00b67f09SDavid van Moolenbroek
617*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_exec_array(atf_process_status_t * s,const atf_fs_path_t * prog,const char * const * argv,const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void (* prehook)(void))618*00b67f09SDavid van Moolenbroek atf_process_exec_array(atf_process_status_t *s,
619*00b67f09SDavid van Moolenbroek const atf_fs_path_t *prog,
620*00b67f09SDavid van Moolenbroek const char *const *argv,
621*00b67f09SDavid van Moolenbroek const atf_process_stream_t *outsb,
622*00b67f09SDavid van Moolenbroek const atf_process_stream_t *errsb,
623*00b67f09SDavid van Moolenbroek void (*prehook)(void))
624*00b67f09SDavid van Moolenbroek {
625*00b67f09SDavid van Moolenbroek atf_error_t err;
626*00b67f09SDavid van Moolenbroek atf_process_child_t c;
627*00b67f09SDavid van Moolenbroek struct exec_args ea = { prog, argv, prehook };
628*00b67f09SDavid van Moolenbroek
629*00b67f09SDavid van Moolenbroek PRE(outsb == NULL ||
630*00b67f09SDavid van Moolenbroek atf_process_stream_type(outsb) != atf_process_stream_type_capture);
631*00b67f09SDavid van Moolenbroek PRE(errsb == NULL ||
632*00b67f09SDavid van Moolenbroek atf_process_stream_type(errsb) != atf_process_stream_type_capture);
633*00b67f09SDavid van Moolenbroek
634*00b67f09SDavid van Moolenbroek err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
635*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
636*00b67f09SDavid van Moolenbroek goto out;
637*00b67f09SDavid van Moolenbroek
638*00b67f09SDavid van Moolenbroek again:
639*00b67f09SDavid van Moolenbroek err = atf_process_child_wait(&c, s);
640*00b67f09SDavid van Moolenbroek if (atf_is_error(err)) {
641*00b67f09SDavid van Moolenbroek INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
642*00b67f09SDavid van Moolenbroek atf_error_free(err);
643*00b67f09SDavid van Moolenbroek goto again;
644*00b67f09SDavid van Moolenbroek }
645*00b67f09SDavid van Moolenbroek
646*00b67f09SDavid van Moolenbroek out:
647*00b67f09SDavid van Moolenbroek return err;
648*00b67f09SDavid van Moolenbroek }
649*00b67f09SDavid van Moolenbroek
650*00b67f09SDavid van Moolenbroek atf_error_t
atf_process_exec_list(atf_process_status_t * s,const atf_fs_path_t * prog,const atf_list_t * argv,const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void (* prehook)(void))651*00b67f09SDavid van Moolenbroek atf_process_exec_list(atf_process_status_t *s,
652*00b67f09SDavid van Moolenbroek const atf_fs_path_t *prog,
653*00b67f09SDavid van Moolenbroek const atf_list_t *argv,
654*00b67f09SDavid van Moolenbroek const atf_process_stream_t *outsb,
655*00b67f09SDavid van Moolenbroek const atf_process_stream_t *errsb,
656*00b67f09SDavid van Moolenbroek void (*prehook)(void))
657*00b67f09SDavid van Moolenbroek {
658*00b67f09SDavid van Moolenbroek atf_error_t err;
659*00b67f09SDavid van Moolenbroek const char **argv2;
660*00b67f09SDavid van Moolenbroek
661*00b67f09SDavid van Moolenbroek PRE(outsb == NULL ||
662*00b67f09SDavid van Moolenbroek atf_process_stream_type(outsb) != atf_process_stream_type_capture);
663*00b67f09SDavid van Moolenbroek PRE(errsb == NULL ||
664*00b67f09SDavid van Moolenbroek atf_process_stream_type(errsb) != atf_process_stream_type_capture);
665*00b67f09SDavid van Moolenbroek
666*00b67f09SDavid van Moolenbroek argv2 = NULL; /* Silence GCC warning. */
667*00b67f09SDavid van Moolenbroek err = list_to_array(argv, &argv2);
668*00b67f09SDavid van Moolenbroek if (atf_is_error(err))
669*00b67f09SDavid van Moolenbroek goto out;
670*00b67f09SDavid van Moolenbroek
671*00b67f09SDavid van Moolenbroek err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
672*00b67f09SDavid van Moolenbroek
673*00b67f09SDavid van Moolenbroek free(argv2);
674*00b67f09SDavid van Moolenbroek out:
675*00b67f09SDavid van Moolenbroek return err;
676*00b67f09SDavid van Moolenbroek }
677