1275988Sngie/* Copyright (c) 2007 The NetBSD Foundation, Inc.
2240116Smarcel * All rights reserved.
3240116Smarcel *
4240116Smarcel * Redistribution and use in source and binary forms, with or without
5240116Smarcel * modification, are permitted provided that the following conditions
6240116Smarcel * are met:
7240116Smarcel * 1. Redistributions of source code must retain the above copyright
8240116Smarcel *    notice, this list of conditions and the following disclaimer.
9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer in the
11240116Smarcel *    documentation and/or other materials provided with the distribution.
12240116Smarcel *
13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24275988Sngie * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25240116Smarcel
26275988Sngie#include "atf-c/detail/process.h"
27275988Sngie
28240116Smarcel#include <sys/types.h>
29240116Smarcel#include <sys/wait.h>
30240116Smarcel
31240116Smarcel#include <errno.h>
32240116Smarcel#include <fcntl.h>
33240116Smarcel#include <stdio.h>
34240116Smarcel#include <stdlib.h>
35240116Smarcel#include <string.h>
36240116Smarcel#include <unistd.h>
37240116Smarcel
38240116Smarcel#include "atf-c/defs.h"
39275988Sngie#include "atf-c/detail/sanity.h"
40240116Smarcel#include "atf-c/error.h"
41240116Smarcel
42240116Smarcel/* This prototype is not in the header file because this is a private
43240116Smarcel * function; however, we need to access it during testing. */
44240116Smarcelatf_error_t atf_process_status_init(atf_process_status_t *, int);
45240116Smarcel
46240116Smarcel/* ---------------------------------------------------------------------
47240116Smarcel * The "stream_prepare" auxiliary type.
48240116Smarcel * --------------------------------------------------------------------- */
49240116Smarcel
50240116Smarcelstruct stream_prepare {
51240116Smarcel    const atf_process_stream_t *m_sb;
52240116Smarcel
53240116Smarcel    bool m_pipefds_ok;
54240116Smarcel    int m_pipefds[2];
55240116Smarcel};
56240116Smarceltypedef struct stream_prepare stream_prepare_t;
57240116Smarcel
58240116Smarcelstatic
59240116Smarcelatf_error_t
60240116Smarcelstream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
61240116Smarcel{
62240116Smarcel    atf_error_t err;
63240116Smarcel
64240116Smarcel    const int type = atf_process_stream_type(sb);
65240116Smarcel
66240116Smarcel    sp->m_sb = sb;
67240116Smarcel    sp->m_pipefds_ok = false;
68240116Smarcel
69240116Smarcel    if (type == atf_process_stream_type_capture) {
70240116Smarcel        if (pipe(sp->m_pipefds) == -1)
71240116Smarcel            err = atf_libc_error(errno, "Failed to create pipe");
72240116Smarcel        else {
73240116Smarcel            err = atf_no_error();
74240116Smarcel            sp->m_pipefds_ok = true;
75240116Smarcel        }
76240116Smarcel    } else
77240116Smarcel        err = atf_no_error();
78240116Smarcel
79240116Smarcel    return err;
80240116Smarcel}
81240116Smarcel
82240116Smarcelstatic
83240116Smarcelvoid
84240116Smarcelstream_prepare_fini(stream_prepare_t *sp)
85240116Smarcel{
86240116Smarcel    if (sp->m_pipefds_ok) {
87240116Smarcel        close(sp->m_pipefds[0]);
88240116Smarcel        close(sp->m_pipefds[1]);
89240116Smarcel    }
90240116Smarcel}
91240116Smarcel
92240116Smarcel/* ---------------------------------------------------------------------
93240116Smarcel * The "atf_process_stream" type.
94240116Smarcel * --------------------------------------------------------------------- */
95240116Smarcel
96240116Smarcelconst int atf_process_stream_type_capture = 1;
97240116Smarcelconst int atf_process_stream_type_connect = 2;
98240116Smarcelconst int atf_process_stream_type_inherit = 3;
99240116Smarcelconst int atf_process_stream_type_redirect_fd = 4;
100240116Smarcelconst int atf_process_stream_type_redirect_path = 5;
101240116Smarcel
102240116Smarcelstatic
103240116Smarcelbool
104240116Smarcelstream_is_valid(const atf_process_stream_t *sb)
105240116Smarcel{
106240116Smarcel    return (sb->m_type == atf_process_stream_type_capture) ||
107240116Smarcel           (sb->m_type == atf_process_stream_type_connect) ||
108240116Smarcel           (sb->m_type == atf_process_stream_type_inherit) ||
109240116Smarcel           (sb->m_type == atf_process_stream_type_redirect_fd) ||
110240116Smarcel           (sb->m_type == atf_process_stream_type_redirect_path);
111240116Smarcel}
112240116Smarcel
113240116Smarcelatf_error_t
114240116Smarcelatf_process_stream_init_capture(atf_process_stream_t *sb)
115240116Smarcel{
116240116Smarcel    sb->m_type = atf_process_stream_type_capture;
117240116Smarcel
118240116Smarcel    POST(stream_is_valid(sb));
119240116Smarcel    return atf_no_error();
120240116Smarcel}
121240116Smarcel
122240116Smarcelatf_error_t
123240116Smarcelatf_process_stream_init_connect(atf_process_stream_t *sb,
124240116Smarcel                                const int src_fd, const int tgt_fd)
125240116Smarcel{
126240116Smarcel    PRE(src_fd >= 0);
127240116Smarcel    PRE(tgt_fd >= 0);
128240116Smarcel    PRE(src_fd != tgt_fd);
129240116Smarcel
130240116Smarcel    sb->m_type = atf_process_stream_type_connect;
131240116Smarcel    sb->m_src_fd = src_fd;
132240116Smarcel    sb->m_tgt_fd = tgt_fd;
133240116Smarcel
134240116Smarcel    POST(stream_is_valid(sb));
135240116Smarcel    return atf_no_error();
136240116Smarcel}
137240116Smarcel
138240116Smarcelatf_error_t
139240116Smarcelatf_process_stream_init_inherit(atf_process_stream_t *sb)
140240116Smarcel{
141240116Smarcel    sb->m_type = atf_process_stream_type_inherit;
142240116Smarcel
143240116Smarcel    POST(stream_is_valid(sb));
144240116Smarcel    return atf_no_error();
145240116Smarcel}
146240116Smarcel
147240116Smarcelatf_error_t
148240116Smarcelatf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
149240116Smarcel                                    const int fd)
150240116Smarcel{
151240116Smarcel    sb->m_type = atf_process_stream_type_redirect_fd;
152240116Smarcel    sb->m_fd = fd;
153240116Smarcel
154240116Smarcel    POST(stream_is_valid(sb));
155240116Smarcel    return atf_no_error();
156240116Smarcel}
157240116Smarcel
158240116Smarcelatf_error_t
159240116Smarcelatf_process_stream_init_redirect_path(atf_process_stream_t *sb,
160240116Smarcel                                      const atf_fs_path_t *path)
161240116Smarcel{
162240116Smarcel    sb->m_type = atf_process_stream_type_redirect_path;
163240116Smarcel    sb->m_path = path;
164240116Smarcel
165240116Smarcel    POST(stream_is_valid(sb));
166240116Smarcel    return atf_no_error();
167240116Smarcel}
168240116Smarcel
169240116Smarcelvoid
170240116Smarcelatf_process_stream_fini(atf_process_stream_t *sb)
171240116Smarcel{
172240116Smarcel    PRE(stream_is_valid(sb));
173240116Smarcel}
174240116Smarcel
175240116Smarcelint
176240116Smarcelatf_process_stream_type(const atf_process_stream_t *sb)
177240116Smarcel{
178240116Smarcel    PRE(stream_is_valid(sb));
179240116Smarcel
180240116Smarcel    return sb->m_type;
181240116Smarcel}
182240116Smarcel
183240116Smarcel/* ---------------------------------------------------------------------
184240116Smarcel * The "atf_process_status" type.
185240116Smarcel * --------------------------------------------------------------------- */
186240116Smarcel
187240116Smarcelatf_error_t
188240116Smarcelatf_process_status_init(atf_process_status_t *s, int status)
189240116Smarcel{
190240116Smarcel    s->m_status = status;
191240116Smarcel
192240116Smarcel    return atf_no_error();
193240116Smarcel}
194240116Smarcel
195240116Smarcelvoid
196240116Smarcelatf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
197240116Smarcel{
198240116Smarcel}
199240116Smarcel
200240116Smarcelbool
201240116Smarcelatf_process_status_exited(const atf_process_status_t *s)
202240116Smarcel{
203240116Smarcel    int mutable_status = s->m_status;
204240116Smarcel    return WIFEXITED(mutable_status);
205240116Smarcel}
206240116Smarcel
207240116Smarcelint
208240116Smarcelatf_process_status_exitstatus(const atf_process_status_t *s)
209240116Smarcel{
210240116Smarcel    PRE(atf_process_status_exited(s));
211240116Smarcel    int mutable_status = s->m_status;
212240116Smarcel    return WEXITSTATUS(mutable_status);
213240116Smarcel}
214240116Smarcel
215240116Smarcelbool
216240116Smarcelatf_process_status_signaled(const atf_process_status_t *s)
217240116Smarcel{
218240116Smarcel    int mutable_status = s->m_status;
219240116Smarcel    return WIFSIGNALED(mutable_status);
220240116Smarcel}
221240116Smarcel
222240116Smarcelint
223240116Smarcelatf_process_status_termsig(const atf_process_status_t *s)
224240116Smarcel{
225240116Smarcel    PRE(atf_process_status_signaled(s));
226240116Smarcel    int mutable_status = s->m_status;
227240116Smarcel    return WTERMSIG(mutable_status);
228240116Smarcel}
229240116Smarcel
230240116Smarcelbool
231240116Smarcelatf_process_status_coredump(const atf_process_status_t *s)
232240116Smarcel{
233240116Smarcel    PRE(atf_process_status_signaled(s));
234240116Smarcel#if defined(WCOREDUMP)
235240116Smarcel    int mutable_status = s->m_status;
236240116Smarcel    return WCOREDUMP(mutable_status);
237240116Smarcel#else
238240116Smarcel    return false;
239240116Smarcel#endif
240240116Smarcel}
241240116Smarcel
242240116Smarcel/* ---------------------------------------------------------------------
243240116Smarcel * The "atf_process_child" type.
244240116Smarcel * --------------------------------------------------------------------- */
245240116Smarcel
246240116Smarcelstatic
247240116Smarcelatf_error_t
248240116Smarcelatf_process_child_init(atf_process_child_t *c)
249240116Smarcel{
250240116Smarcel    c->m_pid = 0;
251240116Smarcel    c->m_stdout = -1;
252240116Smarcel    c->m_stderr = -1;
253240116Smarcel
254240116Smarcel    return atf_no_error();
255240116Smarcel}
256240116Smarcel
257240116Smarcelstatic
258240116Smarcelvoid
259240116Smarcelatf_process_child_fini(atf_process_child_t *c)
260240116Smarcel{
261240116Smarcel    if (c->m_stdout != -1)
262240116Smarcel        close(c->m_stdout);
263240116Smarcel    if (c->m_stderr != -1)
264240116Smarcel        close(c->m_stderr);
265240116Smarcel}
266240116Smarcel
267240116Smarcelatf_error_t
268240116Smarcelatf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
269240116Smarcel{
270240116Smarcel    atf_error_t err;
271240116Smarcel    int status;
272240116Smarcel
273240116Smarcel    if (waitpid(c->m_pid, &status, 0) == -1)
274240116Smarcel        err = atf_libc_error(errno, "Failed waiting for process %d",
275240116Smarcel                             c->m_pid);
276240116Smarcel    else {
277240116Smarcel        atf_process_child_fini(c);
278240116Smarcel        err = atf_process_status_init(s, status);
279240116Smarcel    }
280240116Smarcel
281240116Smarcel    return err;
282240116Smarcel}
283240116Smarcel
284240116Smarcelpid_t
285240116Smarcelatf_process_child_pid(const atf_process_child_t *c)
286240116Smarcel{
287240116Smarcel    return c->m_pid;
288240116Smarcel}
289240116Smarcel
290240116Smarcelint
291240116Smarcelatf_process_child_stdout(atf_process_child_t *c)
292240116Smarcel{
293240116Smarcel    PRE(c->m_stdout != -1);
294240116Smarcel    return c->m_stdout;
295240116Smarcel}
296240116Smarcel
297240116Smarcelint
298240116Smarcelatf_process_child_stderr(atf_process_child_t *c)
299240116Smarcel{
300240116Smarcel    PRE(c->m_stderr != -1);
301240116Smarcel    return c->m_stderr;
302240116Smarcel}
303240116Smarcel
304240116Smarcel/* ---------------------------------------------------------------------
305240116Smarcel * Free functions.
306240116Smarcel * --------------------------------------------------------------------- */
307240116Smarcel
308240116Smarcelstatic
309240116Smarcelatf_error_t
310240116Smarcelsafe_dup(const int oldfd, const int newfd)
311240116Smarcel{
312240116Smarcel    atf_error_t err;
313240116Smarcel
314240116Smarcel    if (oldfd != newfd) {
315240116Smarcel        if (dup2(oldfd, newfd) == -1) {
316240116Smarcel            err = atf_libc_error(errno, "Could not allocate file descriptor");
317240116Smarcel        } else {
318240116Smarcel            close(oldfd);
319240116Smarcel            err = atf_no_error();
320240116Smarcel        }
321240116Smarcel    } else
322240116Smarcel        err = atf_no_error();
323240116Smarcel
324240116Smarcel    return err;
325240116Smarcel}
326240116Smarcel
327240116Smarcelstatic
328240116Smarcelatf_error_t
329240116Smarcelchild_connect(const stream_prepare_t *sp, int procfd)
330240116Smarcel{
331240116Smarcel    atf_error_t err;
332240116Smarcel    const int type = atf_process_stream_type(sp->m_sb);
333240116Smarcel
334240116Smarcel    if (type == atf_process_stream_type_capture) {
335240116Smarcel        close(sp->m_pipefds[0]);
336240116Smarcel        err = safe_dup(sp->m_pipefds[1], procfd);
337240116Smarcel    } else if (type == atf_process_stream_type_connect) {
338240116Smarcel        if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
339240116Smarcel            err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
340240116Smarcel                                 sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
341240116Smarcel        else
342240116Smarcel            err = atf_no_error();
343240116Smarcel    } else if (type == atf_process_stream_type_inherit) {
344240116Smarcel        err = atf_no_error();
345240116Smarcel    } else if (type == atf_process_stream_type_redirect_fd) {
346240116Smarcel        err = safe_dup(sp->m_sb->m_fd, procfd);
347240116Smarcel    } else if (type == atf_process_stream_type_redirect_path) {
348240116Smarcel        int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
349240116Smarcel                       O_WRONLY | O_CREAT | O_TRUNC, 0644);
350240116Smarcel        if (aux == -1)
351240116Smarcel            err = atf_libc_error(errno, "Could not create %s",
352240116Smarcel                                 atf_fs_path_cstring(sp->m_sb->m_path));
353240116Smarcel        else {
354240116Smarcel            err = safe_dup(aux, procfd);
355240116Smarcel            if (atf_is_error(err))
356240116Smarcel                close(aux);
357240116Smarcel        }
358240116Smarcel    } else {
359240116Smarcel        UNREACHABLE;
360240116Smarcel        err = atf_no_error();
361240116Smarcel    }
362240116Smarcel
363240116Smarcel    return err;
364240116Smarcel}
365240116Smarcel
366240116Smarcelstatic
367240116Smarcelvoid
368240116Smarcelparent_connect(const stream_prepare_t *sp, int *fd)
369240116Smarcel{
370240116Smarcel    const int type = atf_process_stream_type(sp->m_sb);
371240116Smarcel
372240116Smarcel    if (type == atf_process_stream_type_capture) {
373240116Smarcel        close(sp->m_pipefds[1]);
374240116Smarcel        *fd = sp->m_pipefds[0];
375240116Smarcel    } else if (type == atf_process_stream_type_connect) {
376240116Smarcel        /* Do nothing. */
377240116Smarcel    } else if (type == atf_process_stream_type_inherit) {
378240116Smarcel        /* Do nothing. */
379240116Smarcel    } else if (type == atf_process_stream_type_redirect_fd) {
380240116Smarcel        /* Do nothing. */
381240116Smarcel    } else if (type == atf_process_stream_type_redirect_path) {
382240116Smarcel        /* Do nothing. */
383240116Smarcel    } else {
384240116Smarcel        UNREACHABLE;
385240116Smarcel    }
386240116Smarcel}
387240116Smarcel
388240116Smarcelstatic
389240116Smarcelatf_error_t
390240116Smarceldo_parent(atf_process_child_t *c,
391240116Smarcel          const pid_t pid,
392240116Smarcel          const stream_prepare_t *outsp,
393240116Smarcel          const stream_prepare_t *errsp)
394240116Smarcel{
395240116Smarcel    atf_error_t err;
396240116Smarcel
397240116Smarcel    err = atf_process_child_init(c);
398240116Smarcel    if (atf_is_error(err))
399240116Smarcel        goto out;
400240116Smarcel
401240116Smarcel    c->m_pid = pid;
402240116Smarcel
403240116Smarcel    parent_connect(outsp, &c->m_stdout);
404240116Smarcel    parent_connect(errsp, &c->m_stderr);
405240116Smarcel
406240116Smarcelout:
407240116Smarcel    return err;
408240116Smarcel}
409240116Smarcel
410240116Smarcelstatic
411240116Smarcelvoid
412240116Smarceldo_child(void (*)(void *),
413240116Smarcel         void *,
414240116Smarcel         const stream_prepare_t *,
415240116Smarcel         const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
416240116Smarcel
417240116Smarcelstatic
418240116Smarcelvoid
419240116Smarceldo_child(void (*start)(void *),
420240116Smarcel         void *v,
421240116Smarcel         const stream_prepare_t *outsp,
422240116Smarcel         const stream_prepare_t *errsp)
423240116Smarcel{
424240116Smarcel    atf_error_t err;
425240116Smarcel
426240116Smarcel    err = child_connect(outsp, STDOUT_FILENO);
427240116Smarcel    if (atf_is_error(err))
428240116Smarcel        goto out;
429240116Smarcel
430240116Smarcel    err = child_connect(errsp, STDERR_FILENO);
431240116Smarcel    if (atf_is_error(err))
432240116Smarcel        goto out;
433240116Smarcel
434240116Smarcel    start(v);
435240116Smarcel    UNREACHABLE;
436240116Smarcel
437240116Smarcelout:
438240116Smarcel    if (atf_is_error(err)) {
439240116Smarcel        char buf[1024];
440240116Smarcel
441240116Smarcel        atf_error_format(err, buf, sizeof(buf));
442240116Smarcel        fprintf(stderr, "Unhandled error: %s\n", buf);
443240116Smarcel        atf_error_free(err);
444240116Smarcel
445240116Smarcel        exit(EXIT_FAILURE);
446240116Smarcel    } else
447240116Smarcel        exit(EXIT_SUCCESS);
448240116Smarcel}
449240116Smarcel
450240116Smarcelstatic
451240116Smarcelatf_error_t
452240116Smarcelfork_with_streams(atf_process_child_t *c,
453240116Smarcel                  void (*start)(void *),
454240116Smarcel                  const atf_process_stream_t *outsb,
455240116Smarcel                  const atf_process_stream_t *errsb,
456240116Smarcel                  void *v)
457240116Smarcel{
458240116Smarcel    atf_error_t err;
459240116Smarcel    stream_prepare_t outsp;
460240116Smarcel    stream_prepare_t errsp;
461240116Smarcel    pid_t pid;
462240116Smarcel
463240116Smarcel    err = stream_prepare_init(&outsp, outsb);
464240116Smarcel    if (atf_is_error(err))
465240116Smarcel        goto out;
466240116Smarcel
467240116Smarcel    err = stream_prepare_init(&errsp, errsb);
468240116Smarcel    if (atf_is_error(err))
469240116Smarcel        goto err_outpipe;
470240116Smarcel
471240116Smarcel    pid = fork();
472240116Smarcel    if (pid == -1) {
473240116Smarcel        err = atf_libc_error(errno, "Failed to fork");
474240116Smarcel        goto err_errpipe;
475240116Smarcel    }
476240116Smarcel
477240116Smarcel    if (pid == 0) {
478240116Smarcel        do_child(start, v, &outsp, &errsp);
479240116Smarcel        UNREACHABLE;
480240116Smarcel        abort();
481240116Smarcel        err = atf_no_error();
482240116Smarcel    } else {
483240116Smarcel        err = do_parent(c, pid, &outsp, &errsp);
484240116Smarcel        if (atf_is_error(err))
485240116Smarcel            goto err_errpipe;
486240116Smarcel    }
487240116Smarcel
488240116Smarcel    goto out;
489240116Smarcel
490240116Smarcelerr_errpipe:
491240116Smarcel    stream_prepare_fini(&errsp);
492240116Smarcelerr_outpipe:
493240116Smarcel    stream_prepare_fini(&outsp);
494240116Smarcel
495240116Smarcelout:
496240116Smarcel    return err;
497240116Smarcel}
498240116Smarcel
499240116Smarcelstatic
500240116Smarcelatf_error_t
501240116Smarcelinit_stream_w_default(const atf_process_stream_t *usersb,
502240116Smarcel                      atf_process_stream_t *inheritsb,
503240116Smarcel                      const atf_process_stream_t **realsb)
504240116Smarcel{
505240116Smarcel    atf_error_t err;
506240116Smarcel
507240116Smarcel    if (usersb == NULL) {
508240116Smarcel        err = atf_process_stream_init_inherit(inheritsb);
509240116Smarcel        if (!atf_is_error(err))
510240116Smarcel            *realsb = inheritsb;
511240116Smarcel    } else {
512240116Smarcel        err = atf_no_error();
513240116Smarcel        *realsb = usersb;
514240116Smarcel    }
515240116Smarcel
516240116Smarcel    return err;
517240116Smarcel}
518240116Smarcel
519240116Smarcelatf_error_t
520240116Smarcelatf_process_fork(atf_process_child_t *c,
521240116Smarcel                 void (*start)(void *),
522240116Smarcel                 const atf_process_stream_t *outsb,
523240116Smarcel                 const atf_process_stream_t *errsb,
524240116Smarcel                 void *v)
525240116Smarcel{
526240116Smarcel    atf_error_t err;
527240116Smarcel    atf_process_stream_t inherit_outsb, inherit_errsb;
528240116Smarcel    const atf_process_stream_t *real_outsb, *real_errsb;
529240116Smarcel
530240116Smarcel    real_outsb = NULL;  /* Shut up GCC warning. */
531240116Smarcel    err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
532240116Smarcel    if (atf_is_error(err))
533240116Smarcel        goto out;
534240116Smarcel
535240116Smarcel    real_errsb = NULL;  /* Shut up GCC warning. */
536240116Smarcel    err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
537240116Smarcel    if (atf_is_error(err))
538240116Smarcel        goto out_out;
539240116Smarcel
540240116Smarcel    err = fork_with_streams(c, start, real_outsb, real_errsb, v);
541240116Smarcel
542240116Smarcel    if (errsb == NULL)
543240116Smarcel        atf_process_stream_fini(&inherit_errsb);
544240116Smarcelout_out:
545240116Smarcel    if (outsb == NULL)
546240116Smarcel        atf_process_stream_fini(&inherit_outsb);
547240116Smarcelout:
548240116Smarcel    return err;
549240116Smarcel}
550240116Smarcel
551240116Smarcelstatic
552240116Smarcelint
553240116Smarcelconst_execvp(const char *file, const char *const *argv)
554240116Smarcel{
555240116Smarcel#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
556240116Smarcel    return execvp(file, UNCONST(argv));
557240116Smarcel#undef UNCONST
558240116Smarcel}
559240116Smarcel
560240116Smarcelstatic
561240116Smarcelatf_error_t
562240116Smarcellist_to_array(const atf_list_t *l, const char ***ap)
563240116Smarcel{
564240116Smarcel    atf_error_t err;
565240116Smarcel    const char **a;
566240116Smarcel
567240116Smarcel    a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
568240116Smarcel    if (a == NULL)
569240116Smarcel        err = atf_no_memory_error();
570240116Smarcel    else {
571240116Smarcel        const char **aiter;
572240116Smarcel        atf_list_citer_t liter;
573240116Smarcel
574240116Smarcel        aiter = a;
575240116Smarcel        atf_list_for_each_c(liter, l) {
576240116Smarcel            *aiter = (const char *)atf_list_citer_data(liter);
577240116Smarcel            aiter++;
578240116Smarcel        }
579240116Smarcel        *aiter = NULL;
580240116Smarcel
581240116Smarcel        err = atf_no_error();
582240116Smarcel        *ap = a;
583240116Smarcel    }
584240116Smarcel
585240116Smarcel    return err;
586240116Smarcel}
587240116Smarcel
588240116Smarcelstruct exec_args {
589240116Smarcel    const atf_fs_path_t *m_prog;
590240116Smarcel    const char *const *m_argv;
591240116Smarcel    void (*m_prehook)(void);
592240116Smarcel};
593240116Smarcel
594240116Smarcelstatic
595240116Smarcelvoid
596240116Smarceldo_exec(void *v)
597240116Smarcel{
598240116Smarcel    struct exec_args *ea = v;
599240116Smarcel
600240116Smarcel    if (ea->m_prehook != NULL)
601240116Smarcel        ea->m_prehook();
602240116Smarcel
603240116Smarcel    const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
604240116Smarcel    const int errnocopy = errno;
605240116Smarcel    INV(ret == -1);
606240116Smarcel    fprintf(stderr, "exec(%s) failed: %s\n",
607240116Smarcel            atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
608240116Smarcel    exit(EXIT_FAILURE);
609240116Smarcel}
610240116Smarcel
611240116Smarcelatf_error_t
612240116Smarcelatf_process_exec_array(atf_process_status_t *s,
613240116Smarcel                       const atf_fs_path_t *prog,
614240116Smarcel                       const char *const *argv,
615240116Smarcel                       const atf_process_stream_t *outsb,
616240116Smarcel                       const atf_process_stream_t *errsb,
617240116Smarcel                       void (*prehook)(void))
618240116Smarcel{
619240116Smarcel    atf_error_t err;
620240116Smarcel    atf_process_child_t c;
621240116Smarcel    struct exec_args ea = { prog, argv, prehook };
622240116Smarcel
623240116Smarcel    PRE(outsb == NULL ||
624240116Smarcel        atf_process_stream_type(outsb) != atf_process_stream_type_capture);
625240116Smarcel    PRE(errsb == NULL ||
626240116Smarcel        atf_process_stream_type(errsb) != atf_process_stream_type_capture);
627240116Smarcel
628240116Smarcel    err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
629240116Smarcel    if (atf_is_error(err))
630240116Smarcel        goto out;
631240116Smarcel
632240116Smarcelagain:
633240116Smarcel    err = atf_process_child_wait(&c, s);
634240116Smarcel    if (atf_is_error(err)) {
635240116Smarcel        INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
636240116Smarcel        atf_error_free(err);
637240116Smarcel        goto again;
638240116Smarcel    }
639240116Smarcel
640240116Smarcelout:
641240116Smarcel    return err;
642240116Smarcel}
643240116Smarcel
644240116Smarcelatf_error_t
645240116Smarcelatf_process_exec_list(atf_process_status_t *s,
646240116Smarcel                      const atf_fs_path_t *prog,
647240116Smarcel                      const atf_list_t *argv,
648240116Smarcel                      const atf_process_stream_t *outsb,
649240116Smarcel                      const atf_process_stream_t *errsb,
650240116Smarcel                      void (*prehook)(void))
651240116Smarcel{
652240116Smarcel    atf_error_t err;
653240116Smarcel    const char **argv2;
654240116Smarcel
655240116Smarcel    PRE(outsb == NULL ||
656240116Smarcel        atf_process_stream_type(outsb) != atf_process_stream_type_capture);
657240116Smarcel    PRE(errsb == NULL ||
658240116Smarcel        atf_process_stream_type(errsb) != atf_process_stream_type_capture);
659240116Smarcel
660240116Smarcel    argv2 = NULL; /* Silence GCC warning. */
661240116Smarcel    err = list_to_array(argv, &argv2);
662240116Smarcel    if (atf_is_error(err))
663240116Smarcel        goto out;
664240116Smarcel
665240116Smarcel    err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
666240116Smarcel
667240116Smarcel    free(argv2);
668240116Smarcelout:
669240116Smarcel    return err;
670240116Smarcel}
671