xref: /minix3/external/bsd/atf/dist/atf-c/detail/process.c (revision 3260d16f34636651fb9ef891a1ffe03fd23b513d)
111be35a1SLionel Sambuc /*
211be35a1SLionel Sambuc  * Automated Testing Framework (atf)
311be35a1SLionel Sambuc  *
411be35a1SLionel Sambuc  * Copyright (c) 2007 The NetBSD Foundation, Inc.
511be35a1SLionel Sambuc  * All rights reserved.
611be35a1SLionel Sambuc  *
711be35a1SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
811be35a1SLionel Sambuc  * modification, are permitted provided that the following conditions
911be35a1SLionel Sambuc  * are met:
1011be35a1SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1111be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1211be35a1SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1311be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1411be35a1SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
1511be35a1SLionel Sambuc  *
1611be35a1SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
1711be35a1SLionel Sambuc  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1811be35a1SLionel Sambuc  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1911be35a1SLionel Sambuc  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2011be35a1SLionel Sambuc  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
2111be35a1SLionel Sambuc  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2211be35a1SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2311be35a1SLionel Sambuc  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2411be35a1SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2511be35a1SLionel Sambuc  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2611be35a1SLionel Sambuc  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2711be35a1SLionel Sambuc  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811be35a1SLionel Sambuc  */
2911be35a1SLionel Sambuc 
3011be35a1SLionel Sambuc #include <sys/types.h>
3111be35a1SLionel Sambuc #include <sys/wait.h>
3211be35a1SLionel Sambuc 
3311be35a1SLionel Sambuc #include <errno.h>
3411be35a1SLionel Sambuc #include <fcntl.h>
3511be35a1SLionel Sambuc #include <stdio.h>
3611be35a1SLionel Sambuc #include <stdlib.h>
3711be35a1SLionel Sambuc #include <string.h>
3811be35a1SLionel Sambuc #include <unistd.h>
3911be35a1SLionel Sambuc 
4011be35a1SLionel Sambuc #include "atf-c/defs.h"
4111be35a1SLionel Sambuc #include "atf-c/error.h"
4211be35a1SLionel Sambuc 
4311be35a1SLionel Sambuc #include "process.h"
4411be35a1SLionel Sambuc #include "sanity.h"
4511be35a1SLionel Sambuc 
4611be35a1SLionel Sambuc /* This prototype is not in the header file because this is a private
4711be35a1SLionel Sambuc  * function; however, we need to access it during testing. */
4811be35a1SLionel Sambuc atf_error_t atf_process_status_init(atf_process_status_t *, int);
4911be35a1SLionel Sambuc 
5011be35a1SLionel Sambuc /* ---------------------------------------------------------------------
5111be35a1SLionel Sambuc  * The "stream_prepare" auxiliary type.
5211be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
5311be35a1SLionel Sambuc 
5411be35a1SLionel Sambuc struct stream_prepare {
5511be35a1SLionel Sambuc     const atf_process_stream_t *m_sb;
5611be35a1SLionel Sambuc 
5711be35a1SLionel Sambuc     bool m_pipefds_ok;
5811be35a1SLionel Sambuc     int m_pipefds[2];
5911be35a1SLionel Sambuc };
6011be35a1SLionel Sambuc typedef struct stream_prepare stream_prepare_t;
6111be35a1SLionel Sambuc 
6211be35a1SLionel Sambuc static
6311be35a1SLionel Sambuc atf_error_t
stream_prepare_init(stream_prepare_t * sp,const atf_process_stream_t * sb)6411be35a1SLionel Sambuc stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
6511be35a1SLionel Sambuc {
6611be35a1SLionel Sambuc     atf_error_t err;
6711be35a1SLionel Sambuc 
6811be35a1SLionel Sambuc     const int type = atf_process_stream_type(sb);
6911be35a1SLionel Sambuc 
7011be35a1SLionel Sambuc     sp->m_sb = sb;
7111be35a1SLionel Sambuc     sp->m_pipefds_ok = false;
7211be35a1SLionel Sambuc 
7311be35a1SLionel Sambuc     if (type == atf_process_stream_type_capture) {
7411be35a1SLionel Sambuc         if (pipe(sp->m_pipefds) == -1)
7511be35a1SLionel Sambuc             err = atf_libc_error(errno, "Failed to create pipe");
7611be35a1SLionel Sambuc         else {
7711be35a1SLionel Sambuc             err = atf_no_error();
7811be35a1SLionel Sambuc             sp->m_pipefds_ok = true;
7911be35a1SLionel Sambuc         }
8011be35a1SLionel Sambuc     } else
8111be35a1SLionel Sambuc         err = atf_no_error();
8211be35a1SLionel Sambuc 
8311be35a1SLionel Sambuc     return err;
8411be35a1SLionel Sambuc }
8511be35a1SLionel Sambuc 
8611be35a1SLionel Sambuc static
8711be35a1SLionel Sambuc void
stream_prepare_fini(stream_prepare_t * sp)8811be35a1SLionel Sambuc stream_prepare_fini(stream_prepare_t *sp)
8911be35a1SLionel Sambuc {
9011be35a1SLionel Sambuc     if (sp->m_pipefds_ok) {
9111be35a1SLionel Sambuc         close(sp->m_pipefds[0]);
9211be35a1SLionel Sambuc         close(sp->m_pipefds[1]);
9311be35a1SLionel Sambuc     }
9411be35a1SLionel Sambuc }
9511be35a1SLionel Sambuc 
9611be35a1SLionel Sambuc /* ---------------------------------------------------------------------
9711be35a1SLionel Sambuc  * The "atf_process_stream" type.
9811be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
9911be35a1SLionel Sambuc 
10011be35a1SLionel Sambuc const int atf_process_stream_type_capture = 1;
10111be35a1SLionel Sambuc const int atf_process_stream_type_connect = 2;
10211be35a1SLionel Sambuc const int atf_process_stream_type_inherit = 3;
10311be35a1SLionel Sambuc const int atf_process_stream_type_redirect_fd = 4;
10411be35a1SLionel Sambuc const int atf_process_stream_type_redirect_path = 5;
10511be35a1SLionel Sambuc 
106*3260d16fSLionel Sambuc #if defined(__minix) && !defined(NDEBUG)
10711be35a1SLionel Sambuc static
10811be35a1SLionel Sambuc bool
stream_is_valid(const atf_process_stream_t * sb)10911be35a1SLionel Sambuc stream_is_valid(const atf_process_stream_t *sb)
11011be35a1SLionel Sambuc {
11111be35a1SLionel Sambuc     return (sb->m_type == atf_process_stream_type_capture) ||
11211be35a1SLionel Sambuc            (sb->m_type == atf_process_stream_type_connect) ||
11311be35a1SLionel Sambuc            (sb->m_type == atf_process_stream_type_inherit) ||
11411be35a1SLionel Sambuc            (sb->m_type == atf_process_stream_type_redirect_fd) ||
11511be35a1SLionel Sambuc            (sb->m_type == atf_process_stream_type_redirect_path);
11611be35a1SLionel Sambuc }
117*3260d16fSLionel Sambuc #endif /* defined(__minix) && !defined(NDEBUG) */
11811be35a1SLionel Sambuc 
11911be35a1SLionel Sambuc atf_error_t
atf_process_stream_init_capture(atf_process_stream_t * sb)12011be35a1SLionel Sambuc atf_process_stream_init_capture(atf_process_stream_t *sb)
12111be35a1SLionel Sambuc {
12211be35a1SLionel Sambuc     sb->m_type = atf_process_stream_type_capture;
12311be35a1SLionel Sambuc 
12411be35a1SLionel Sambuc     POST(stream_is_valid(sb));
12511be35a1SLionel Sambuc     return atf_no_error();
12611be35a1SLionel Sambuc }
12711be35a1SLionel Sambuc 
12811be35a1SLionel Sambuc atf_error_t
atf_process_stream_init_connect(atf_process_stream_t * sb,const int src_fd,const int tgt_fd)12911be35a1SLionel Sambuc atf_process_stream_init_connect(atf_process_stream_t *sb,
13011be35a1SLionel Sambuc                                 const int src_fd, const int tgt_fd)
13111be35a1SLionel Sambuc {
13211be35a1SLionel Sambuc     PRE(src_fd >= 0);
13311be35a1SLionel Sambuc     PRE(tgt_fd >= 0);
13411be35a1SLionel Sambuc     PRE(src_fd != tgt_fd);
13511be35a1SLionel Sambuc 
13611be35a1SLionel Sambuc     sb->m_type = atf_process_stream_type_connect;
13711be35a1SLionel Sambuc     sb->m_src_fd = src_fd;
13811be35a1SLionel Sambuc     sb->m_tgt_fd = tgt_fd;
13911be35a1SLionel Sambuc 
14011be35a1SLionel Sambuc     POST(stream_is_valid(sb));
14111be35a1SLionel Sambuc     return atf_no_error();
14211be35a1SLionel Sambuc }
14311be35a1SLionel Sambuc 
14411be35a1SLionel Sambuc atf_error_t
atf_process_stream_init_inherit(atf_process_stream_t * sb)14511be35a1SLionel Sambuc atf_process_stream_init_inherit(atf_process_stream_t *sb)
14611be35a1SLionel Sambuc {
14711be35a1SLionel Sambuc     sb->m_type = atf_process_stream_type_inherit;
14811be35a1SLionel Sambuc 
14911be35a1SLionel Sambuc     POST(stream_is_valid(sb));
15011be35a1SLionel Sambuc     return atf_no_error();
15111be35a1SLionel Sambuc }
15211be35a1SLionel Sambuc 
15311be35a1SLionel Sambuc atf_error_t
atf_process_stream_init_redirect_fd(atf_process_stream_t * sb,const int fd)15411be35a1SLionel Sambuc atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
15511be35a1SLionel Sambuc                                     const int fd)
15611be35a1SLionel Sambuc {
15711be35a1SLionel Sambuc     sb->m_type = atf_process_stream_type_redirect_fd;
15811be35a1SLionel Sambuc     sb->m_fd = fd;
15911be35a1SLionel Sambuc 
16011be35a1SLionel Sambuc     POST(stream_is_valid(sb));
16111be35a1SLionel Sambuc     return atf_no_error();
16211be35a1SLionel Sambuc }
16311be35a1SLionel Sambuc 
16411be35a1SLionel Sambuc atf_error_t
atf_process_stream_init_redirect_path(atf_process_stream_t * sb,const atf_fs_path_t * path)16511be35a1SLionel Sambuc atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
16611be35a1SLionel Sambuc                                       const atf_fs_path_t *path)
16711be35a1SLionel Sambuc {
16811be35a1SLionel Sambuc     sb->m_type = atf_process_stream_type_redirect_path;
16911be35a1SLionel Sambuc     sb->m_path = path;
17011be35a1SLionel Sambuc 
17111be35a1SLionel Sambuc     POST(stream_is_valid(sb));
17211be35a1SLionel Sambuc     return atf_no_error();
17311be35a1SLionel Sambuc }
17411be35a1SLionel Sambuc 
17511be35a1SLionel Sambuc void
atf_process_stream_fini(atf_process_stream_t * sb)17611be35a1SLionel Sambuc atf_process_stream_fini(atf_process_stream_t *sb)
17711be35a1SLionel Sambuc {
17811be35a1SLionel Sambuc     PRE(stream_is_valid(sb));
17911be35a1SLionel Sambuc }
18011be35a1SLionel Sambuc 
18111be35a1SLionel Sambuc int
atf_process_stream_type(const atf_process_stream_t * sb)18211be35a1SLionel Sambuc atf_process_stream_type(const atf_process_stream_t *sb)
18311be35a1SLionel Sambuc {
18411be35a1SLionel Sambuc     PRE(stream_is_valid(sb));
18511be35a1SLionel Sambuc 
18611be35a1SLionel Sambuc     return sb->m_type;
18711be35a1SLionel Sambuc }
18811be35a1SLionel Sambuc 
18911be35a1SLionel Sambuc /* ---------------------------------------------------------------------
19011be35a1SLionel Sambuc  * The "atf_process_status" type.
19111be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
19211be35a1SLionel Sambuc 
19311be35a1SLionel Sambuc atf_error_t
atf_process_status_init(atf_process_status_t * s,int status)19411be35a1SLionel Sambuc atf_process_status_init(atf_process_status_t *s, int status)
19511be35a1SLionel Sambuc {
19611be35a1SLionel Sambuc     s->m_status = status;
19711be35a1SLionel Sambuc 
19811be35a1SLionel Sambuc     return atf_no_error();
19911be35a1SLionel Sambuc }
20011be35a1SLionel Sambuc 
20111be35a1SLionel Sambuc void
atf_process_status_fini(atf_process_status_t * s ATF_DEFS_ATTRIBUTE_UNUSED)20211be35a1SLionel Sambuc atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
20311be35a1SLionel Sambuc {
20411be35a1SLionel Sambuc }
20511be35a1SLionel Sambuc 
20611be35a1SLionel Sambuc bool
atf_process_status_exited(const atf_process_status_t * s)20711be35a1SLionel Sambuc atf_process_status_exited(const atf_process_status_t *s)
20811be35a1SLionel Sambuc {
20911be35a1SLionel Sambuc     int mutable_status = s->m_status;
21011be35a1SLionel Sambuc     return WIFEXITED(mutable_status);
21111be35a1SLionel Sambuc }
21211be35a1SLionel Sambuc 
21311be35a1SLionel Sambuc int
atf_process_status_exitstatus(const atf_process_status_t * s)21411be35a1SLionel Sambuc atf_process_status_exitstatus(const atf_process_status_t *s)
21511be35a1SLionel Sambuc {
21611be35a1SLionel Sambuc     PRE(atf_process_status_exited(s));
21711be35a1SLionel Sambuc     int mutable_status = s->m_status;
21811be35a1SLionel Sambuc     return WEXITSTATUS(mutable_status);
21911be35a1SLionel Sambuc }
22011be35a1SLionel Sambuc 
22111be35a1SLionel Sambuc bool
atf_process_status_signaled(const atf_process_status_t * s)22211be35a1SLionel Sambuc atf_process_status_signaled(const atf_process_status_t *s)
22311be35a1SLionel Sambuc {
22411be35a1SLionel Sambuc     int mutable_status = s->m_status;
22511be35a1SLionel Sambuc     return WIFSIGNALED(mutable_status);
22611be35a1SLionel Sambuc }
22711be35a1SLionel Sambuc 
22811be35a1SLionel Sambuc int
atf_process_status_termsig(const atf_process_status_t * s)22911be35a1SLionel Sambuc atf_process_status_termsig(const atf_process_status_t *s)
23011be35a1SLionel Sambuc {
23111be35a1SLionel Sambuc     PRE(atf_process_status_signaled(s));
23211be35a1SLionel Sambuc     int mutable_status = s->m_status;
23311be35a1SLionel Sambuc     return WTERMSIG(mutable_status);
23411be35a1SLionel Sambuc }
23511be35a1SLionel Sambuc 
23611be35a1SLionel Sambuc bool
atf_process_status_coredump(const atf_process_status_t * s)23711be35a1SLionel Sambuc atf_process_status_coredump(const atf_process_status_t *s)
23811be35a1SLionel Sambuc {
23911be35a1SLionel Sambuc     PRE(atf_process_status_signaled(s));
24011be35a1SLionel Sambuc #if defined(WCOREDUMP)
24111be35a1SLionel Sambuc     int mutable_status = s->m_status;
24211be35a1SLionel Sambuc     return WCOREDUMP(mutable_status);
24311be35a1SLionel Sambuc #else
24411be35a1SLionel Sambuc     return false;
24511be35a1SLionel Sambuc #endif
24611be35a1SLionel Sambuc }
24711be35a1SLionel Sambuc 
24811be35a1SLionel Sambuc /* ---------------------------------------------------------------------
24911be35a1SLionel Sambuc  * The "atf_process_child" type.
25011be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
25111be35a1SLionel Sambuc 
25211be35a1SLionel Sambuc static
25311be35a1SLionel Sambuc atf_error_t
atf_process_child_init(atf_process_child_t * c)25411be35a1SLionel Sambuc atf_process_child_init(atf_process_child_t *c)
25511be35a1SLionel Sambuc {
25611be35a1SLionel Sambuc     c->m_pid = 0;
25711be35a1SLionel Sambuc     c->m_stdout = -1;
25811be35a1SLionel Sambuc     c->m_stderr = -1;
25911be35a1SLionel Sambuc 
26011be35a1SLionel Sambuc     return atf_no_error();
26111be35a1SLionel Sambuc }
26211be35a1SLionel Sambuc 
26311be35a1SLionel Sambuc static
26411be35a1SLionel Sambuc void
atf_process_child_fini(atf_process_child_t * c)26511be35a1SLionel Sambuc atf_process_child_fini(atf_process_child_t *c)
26611be35a1SLionel Sambuc {
26711be35a1SLionel Sambuc     if (c->m_stdout != -1)
26811be35a1SLionel Sambuc         close(c->m_stdout);
26911be35a1SLionel Sambuc     if (c->m_stderr != -1)
27011be35a1SLionel Sambuc         close(c->m_stderr);
27111be35a1SLionel Sambuc }
27211be35a1SLionel Sambuc 
27311be35a1SLionel Sambuc atf_error_t
atf_process_child_wait(atf_process_child_t * c,atf_process_status_t * s)27411be35a1SLionel Sambuc atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
27511be35a1SLionel Sambuc {
27611be35a1SLionel Sambuc     atf_error_t err;
27711be35a1SLionel Sambuc     int status;
27811be35a1SLionel Sambuc 
27911be35a1SLionel Sambuc     if (waitpid(c->m_pid, &status, 0) == -1)
28011be35a1SLionel Sambuc         err = atf_libc_error(errno, "Failed waiting for process %d",
28111be35a1SLionel Sambuc                              c->m_pid);
28211be35a1SLionel Sambuc     else {
28311be35a1SLionel Sambuc         atf_process_child_fini(c);
28411be35a1SLionel Sambuc         err = atf_process_status_init(s, status);
28511be35a1SLionel Sambuc     }
28611be35a1SLionel Sambuc 
28711be35a1SLionel Sambuc     return err;
28811be35a1SLionel Sambuc }
28911be35a1SLionel Sambuc 
29011be35a1SLionel Sambuc pid_t
atf_process_child_pid(const atf_process_child_t * c)29111be35a1SLionel Sambuc atf_process_child_pid(const atf_process_child_t *c)
29211be35a1SLionel Sambuc {
29311be35a1SLionel Sambuc     return c->m_pid;
29411be35a1SLionel Sambuc }
29511be35a1SLionel Sambuc 
29611be35a1SLionel Sambuc int
atf_process_child_stdout(atf_process_child_t * c)29711be35a1SLionel Sambuc atf_process_child_stdout(atf_process_child_t *c)
29811be35a1SLionel Sambuc {
29911be35a1SLionel Sambuc     PRE(c->m_stdout != -1);
30011be35a1SLionel Sambuc     return c->m_stdout;
30111be35a1SLionel Sambuc }
30211be35a1SLionel Sambuc 
30311be35a1SLionel Sambuc int
atf_process_child_stderr(atf_process_child_t * c)30411be35a1SLionel Sambuc atf_process_child_stderr(atf_process_child_t *c)
30511be35a1SLionel Sambuc {
30611be35a1SLionel Sambuc     PRE(c->m_stderr != -1);
30711be35a1SLionel Sambuc     return c->m_stderr;
30811be35a1SLionel Sambuc }
30911be35a1SLionel Sambuc 
31011be35a1SLionel Sambuc /* ---------------------------------------------------------------------
31111be35a1SLionel Sambuc  * Free functions.
31211be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
31311be35a1SLionel Sambuc 
31411be35a1SLionel Sambuc static
31511be35a1SLionel Sambuc atf_error_t
safe_dup(const int oldfd,const int newfd)31611be35a1SLionel Sambuc safe_dup(const int oldfd, const int newfd)
31711be35a1SLionel Sambuc {
31811be35a1SLionel Sambuc     atf_error_t err;
31911be35a1SLionel Sambuc 
32011be35a1SLionel Sambuc     if (oldfd != newfd) {
32111be35a1SLionel Sambuc         if (dup2(oldfd, newfd) == -1) {
32211be35a1SLionel Sambuc             err = atf_libc_error(errno, "Could not allocate file descriptor");
32311be35a1SLionel Sambuc         } else {
32411be35a1SLionel Sambuc             close(oldfd);
32511be35a1SLionel Sambuc             err = atf_no_error();
32611be35a1SLionel Sambuc         }
32711be35a1SLionel Sambuc     } else
32811be35a1SLionel Sambuc         err = atf_no_error();
32911be35a1SLionel Sambuc 
33011be35a1SLionel Sambuc     return err;
33111be35a1SLionel Sambuc }
33211be35a1SLionel Sambuc 
33311be35a1SLionel Sambuc static
33411be35a1SLionel Sambuc atf_error_t
child_connect(const stream_prepare_t * sp,int procfd)33511be35a1SLionel Sambuc child_connect(const stream_prepare_t *sp, int procfd)
33611be35a1SLionel Sambuc {
33711be35a1SLionel Sambuc     atf_error_t err;
33811be35a1SLionel Sambuc     const int type = atf_process_stream_type(sp->m_sb);
33911be35a1SLionel Sambuc 
34011be35a1SLionel Sambuc     if (type == atf_process_stream_type_capture) {
34111be35a1SLionel Sambuc         close(sp->m_pipefds[0]);
34211be35a1SLionel Sambuc         err = safe_dup(sp->m_pipefds[1], procfd);
34311be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_connect) {
34411be35a1SLionel Sambuc         if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
34511be35a1SLionel Sambuc             err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
34611be35a1SLionel Sambuc                                  sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
34711be35a1SLionel Sambuc         else
34811be35a1SLionel Sambuc             err = atf_no_error();
34911be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_inherit) {
35011be35a1SLionel Sambuc         err = atf_no_error();
35111be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_redirect_fd) {
35211be35a1SLionel Sambuc         err = safe_dup(sp->m_sb->m_fd, procfd);
35311be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_redirect_path) {
35411be35a1SLionel Sambuc         int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
35511be35a1SLionel Sambuc                        O_WRONLY | O_CREAT | O_TRUNC, 0644);
35611be35a1SLionel Sambuc         if (aux == -1)
35711be35a1SLionel Sambuc             err = atf_libc_error(errno, "Could not create %s",
35811be35a1SLionel Sambuc                                  atf_fs_path_cstring(sp->m_sb->m_path));
35911be35a1SLionel Sambuc         else {
36011be35a1SLionel Sambuc             err = safe_dup(aux, procfd);
36111be35a1SLionel Sambuc             if (atf_is_error(err))
36211be35a1SLionel Sambuc                 close(aux);
36311be35a1SLionel Sambuc         }
36411be35a1SLionel Sambuc     } else {
36511be35a1SLionel Sambuc         UNREACHABLE;
36611be35a1SLionel Sambuc         err = atf_no_error();
36711be35a1SLionel Sambuc     }
36811be35a1SLionel Sambuc 
36911be35a1SLionel Sambuc     return err;
37011be35a1SLionel Sambuc }
37111be35a1SLionel Sambuc 
37211be35a1SLionel Sambuc static
37311be35a1SLionel Sambuc void
parent_connect(const stream_prepare_t * sp,int * fd)37411be35a1SLionel Sambuc parent_connect(const stream_prepare_t *sp, int *fd)
37511be35a1SLionel Sambuc {
37611be35a1SLionel Sambuc     const int type = atf_process_stream_type(sp->m_sb);
37711be35a1SLionel Sambuc 
37811be35a1SLionel Sambuc     if (type == atf_process_stream_type_capture) {
37911be35a1SLionel Sambuc         close(sp->m_pipefds[1]);
38011be35a1SLionel Sambuc         *fd = sp->m_pipefds[0];
38111be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_connect) {
38211be35a1SLionel Sambuc         /* Do nothing. */
38311be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_inherit) {
38411be35a1SLionel Sambuc         /* Do nothing. */
38511be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_redirect_fd) {
38611be35a1SLionel Sambuc         /* Do nothing. */
38711be35a1SLionel Sambuc     } else if (type == atf_process_stream_type_redirect_path) {
38811be35a1SLionel Sambuc         /* Do nothing. */
38911be35a1SLionel Sambuc     } else {
39011be35a1SLionel Sambuc         UNREACHABLE;
39111be35a1SLionel Sambuc     }
39211be35a1SLionel Sambuc }
39311be35a1SLionel Sambuc 
39411be35a1SLionel Sambuc static
39511be35a1SLionel Sambuc atf_error_t
do_parent(atf_process_child_t * c,const pid_t pid,const stream_prepare_t * outsp,const stream_prepare_t * errsp)39611be35a1SLionel Sambuc do_parent(atf_process_child_t *c,
39711be35a1SLionel Sambuc           const pid_t pid,
39811be35a1SLionel Sambuc           const stream_prepare_t *outsp,
39911be35a1SLionel Sambuc           const stream_prepare_t *errsp)
40011be35a1SLionel Sambuc {
40111be35a1SLionel Sambuc     atf_error_t err;
40211be35a1SLionel Sambuc 
40311be35a1SLionel Sambuc     err = atf_process_child_init(c);
40411be35a1SLionel Sambuc     if (atf_is_error(err))
40511be35a1SLionel Sambuc         goto out;
40611be35a1SLionel Sambuc 
40711be35a1SLionel Sambuc     c->m_pid = pid;
40811be35a1SLionel Sambuc 
40911be35a1SLionel Sambuc     parent_connect(outsp, &c->m_stdout);
41011be35a1SLionel Sambuc     parent_connect(errsp, &c->m_stderr);
41111be35a1SLionel Sambuc 
41211be35a1SLionel Sambuc out:
41311be35a1SLionel Sambuc     return err;
41411be35a1SLionel Sambuc }
41511be35a1SLionel Sambuc 
41611be35a1SLionel Sambuc static
41711be35a1SLionel Sambuc void
41811be35a1SLionel Sambuc do_child(void (*)(void *),
41911be35a1SLionel Sambuc          void *,
42011be35a1SLionel Sambuc          const stream_prepare_t *,
42111be35a1SLionel Sambuc          const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
42211be35a1SLionel Sambuc 
42311be35a1SLionel Sambuc static
42411be35a1SLionel Sambuc void
do_child(void (* start)(void *),void * v,const stream_prepare_t * outsp,const stream_prepare_t * errsp)42511be35a1SLionel Sambuc do_child(void (*start)(void *),
42611be35a1SLionel Sambuc          void *v,
42711be35a1SLionel Sambuc          const stream_prepare_t *outsp,
42811be35a1SLionel Sambuc          const stream_prepare_t *errsp)
42911be35a1SLionel Sambuc {
43011be35a1SLionel Sambuc     atf_error_t err;
43111be35a1SLionel Sambuc 
43211be35a1SLionel Sambuc     err = child_connect(outsp, STDOUT_FILENO);
43311be35a1SLionel Sambuc     if (atf_is_error(err))
43411be35a1SLionel Sambuc         goto out;
43511be35a1SLionel Sambuc 
43611be35a1SLionel Sambuc     err = child_connect(errsp, STDERR_FILENO);
43711be35a1SLionel Sambuc     if (atf_is_error(err))
43811be35a1SLionel Sambuc         goto out;
43911be35a1SLionel Sambuc 
44011be35a1SLionel Sambuc     start(v);
44111be35a1SLionel Sambuc     UNREACHABLE;
44211be35a1SLionel Sambuc 
44311be35a1SLionel Sambuc out:
44411be35a1SLionel Sambuc     if (atf_is_error(err)) {
44511be35a1SLionel Sambuc         char buf[1024];
44611be35a1SLionel Sambuc 
44711be35a1SLionel Sambuc         atf_error_format(err, buf, sizeof(buf));
44811be35a1SLionel Sambuc         fprintf(stderr, "Unhandled error: %s\n", buf);
44911be35a1SLionel Sambuc         atf_error_free(err);
45011be35a1SLionel Sambuc 
45111be35a1SLionel Sambuc         exit(EXIT_FAILURE);
45211be35a1SLionel Sambuc     } else
45311be35a1SLionel Sambuc         exit(EXIT_SUCCESS);
45411be35a1SLionel Sambuc }
45511be35a1SLionel Sambuc 
45611be35a1SLionel Sambuc static
45711be35a1SLionel Sambuc 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)45811be35a1SLionel Sambuc fork_with_streams(atf_process_child_t *c,
45911be35a1SLionel Sambuc                   void (*start)(void *),
46011be35a1SLionel Sambuc                   const atf_process_stream_t *outsb,
46111be35a1SLionel Sambuc                   const atf_process_stream_t *errsb,
46211be35a1SLionel Sambuc                   void *v)
46311be35a1SLionel Sambuc {
46411be35a1SLionel Sambuc     atf_error_t err;
46511be35a1SLionel Sambuc     stream_prepare_t outsp;
46611be35a1SLionel Sambuc     stream_prepare_t errsp;
46711be35a1SLionel Sambuc     pid_t pid;
46811be35a1SLionel Sambuc 
46911be35a1SLionel Sambuc     err = stream_prepare_init(&outsp, outsb);
47011be35a1SLionel Sambuc     if (atf_is_error(err))
47111be35a1SLionel Sambuc         goto out;
47211be35a1SLionel Sambuc 
47311be35a1SLionel Sambuc     err = stream_prepare_init(&errsp, errsb);
47411be35a1SLionel Sambuc     if (atf_is_error(err))
47511be35a1SLionel Sambuc         goto err_outpipe;
47611be35a1SLionel Sambuc 
47711be35a1SLionel Sambuc     pid = fork();
47811be35a1SLionel Sambuc     if (pid == -1) {
47911be35a1SLionel Sambuc         err = atf_libc_error(errno, "Failed to fork");
48011be35a1SLionel Sambuc         goto err_errpipe;
48111be35a1SLionel Sambuc     }
48211be35a1SLionel Sambuc 
48311be35a1SLionel Sambuc     if (pid == 0) {
48411be35a1SLionel Sambuc         do_child(start, v, &outsp, &errsp);
48511be35a1SLionel Sambuc         UNREACHABLE;
48611be35a1SLionel Sambuc         abort();
48711be35a1SLionel Sambuc         err = atf_no_error();
48811be35a1SLionel Sambuc     } else {
48911be35a1SLionel Sambuc         err = do_parent(c, pid, &outsp, &errsp);
49011be35a1SLionel Sambuc         if (atf_is_error(err))
49111be35a1SLionel Sambuc             goto err_errpipe;
49211be35a1SLionel Sambuc     }
49311be35a1SLionel Sambuc 
49411be35a1SLionel Sambuc     goto out;
49511be35a1SLionel Sambuc 
49611be35a1SLionel Sambuc err_errpipe:
49711be35a1SLionel Sambuc     stream_prepare_fini(&errsp);
49811be35a1SLionel Sambuc err_outpipe:
49911be35a1SLionel Sambuc     stream_prepare_fini(&outsp);
50011be35a1SLionel Sambuc 
50111be35a1SLionel Sambuc out:
50211be35a1SLionel Sambuc     return err;
50311be35a1SLionel Sambuc }
50411be35a1SLionel Sambuc 
50511be35a1SLionel Sambuc static
50611be35a1SLionel Sambuc atf_error_t
init_stream_w_default(const atf_process_stream_t * usersb,atf_process_stream_t * inheritsb,const atf_process_stream_t ** realsb)50711be35a1SLionel Sambuc init_stream_w_default(const atf_process_stream_t *usersb,
50811be35a1SLionel Sambuc                       atf_process_stream_t *inheritsb,
50911be35a1SLionel Sambuc                       const atf_process_stream_t **realsb)
51011be35a1SLionel Sambuc {
51111be35a1SLionel Sambuc     atf_error_t err;
51211be35a1SLionel Sambuc 
51311be35a1SLionel Sambuc     if (usersb == NULL) {
51411be35a1SLionel Sambuc         err = atf_process_stream_init_inherit(inheritsb);
51511be35a1SLionel Sambuc         if (!atf_is_error(err))
51611be35a1SLionel Sambuc             *realsb = inheritsb;
51711be35a1SLionel Sambuc     } else {
51811be35a1SLionel Sambuc         err = atf_no_error();
51911be35a1SLionel Sambuc         *realsb = usersb;
52011be35a1SLionel Sambuc     }
52111be35a1SLionel Sambuc 
52211be35a1SLionel Sambuc     return err;
52311be35a1SLionel Sambuc }
52411be35a1SLionel Sambuc 
52511be35a1SLionel Sambuc 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)52611be35a1SLionel Sambuc atf_process_fork(atf_process_child_t *c,
52711be35a1SLionel Sambuc                  void (*start)(void *),
52811be35a1SLionel Sambuc                  const atf_process_stream_t *outsb,
52911be35a1SLionel Sambuc                  const atf_process_stream_t *errsb,
53011be35a1SLionel Sambuc                  void *v)
53111be35a1SLionel Sambuc {
53211be35a1SLionel Sambuc     atf_error_t err;
53311be35a1SLionel Sambuc     atf_process_stream_t inherit_outsb, inherit_errsb;
53411be35a1SLionel Sambuc     const atf_process_stream_t *real_outsb, *real_errsb;
53511be35a1SLionel Sambuc 
53611be35a1SLionel Sambuc     real_outsb = NULL;  /* Shut up GCC warning. */
53711be35a1SLionel Sambuc     err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
53811be35a1SLionel Sambuc     if (atf_is_error(err))
53911be35a1SLionel Sambuc         goto out;
54011be35a1SLionel Sambuc 
54111be35a1SLionel Sambuc     real_errsb = NULL;  /* Shut up GCC warning. */
54211be35a1SLionel Sambuc     err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
54311be35a1SLionel Sambuc     if (atf_is_error(err))
54411be35a1SLionel Sambuc         goto out_out;
54511be35a1SLionel Sambuc 
54611be35a1SLionel Sambuc     err = fork_with_streams(c, start, real_outsb, real_errsb, v);
54711be35a1SLionel Sambuc 
54811be35a1SLionel Sambuc     if (errsb == NULL)
54911be35a1SLionel Sambuc         atf_process_stream_fini(&inherit_errsb);
55011be35a1SLionel Sambuc out_out:
55111be35a1SLionel Sambuc     if (outsb == NULL)
55211be35a1SLionel Sambuc         atf_process_stream_fini(&inherit_outsb);
55311be35a1SLionel Sambuc out:
55411be35a1SLionel Sambuc     return err;
55511be35a1SLionel Sambuc }
55611be35a1SLionel Sambuc 
55711be35a1SLionel Sambuc static
55811be35a1SLionel Sambuc int
const_execvp(const char * file,const char * const * argv)55911be35a1SLionel Sambuc const_execvp(const char *file, const char *const *argv)
56011be35a1SLionel Sambuc {
56111be35a1SLionel Sambuc #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
56211be35a1SLionel Sambuc     return execvp(file, UNCONST(argv));
56311be35a1SLionel Sambuc #undef UNCONST
56411be35a1SLionel Sambuc }
56511be35a1SLionel Sambuc 
56611be35a1SLionel Sambuc static
56711be35a1SLionel Sambuc atf_error_t
list_to_array(const atf_list_t * l,const char *** ap)56811be35a1SLionel Sambuc list_to_array(const atf_list_t *l, const char ***ap)
56911be35a1SLionel Sambuc {
57011be35a1SLionel Sambuc     atf_error_t err;
57111be35a1SLionel Sambuc     const char **a;
57211be35a1SLionel Sambuc 
57311be35a1SLionel Sambuc     a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
57411be35a1SLionel Sambuc     if (a == NULL)
57511be35a1SLionel Sambuc         err = atf_no_memory_error();
57611be35a1SLionel Sambuc     else {
57711be35a1SLionel Sambuc         const char **aiter;
57811be35a1SLionel Sambuc         atf_list_citer_t liter;
57911be35a1SLionel Sambuc 
58011be35a1SLionel Sambuc         aiter = a;
58111be35a1SLionel Sambuc         atf_list_for_each_c(liter, l) {
58211be35a1SLionel Sambuc             *aiter = (const char *)atf_list_citer_data(liter);
58311be35a1SLionel Sambuc             aiter++;
58411be35a1SLionel Sambuc         }
58511be35a1SLionel Sambuc         *aiter = NULL;
58611be35a1SLionel Sambuc 
58711be35a1SLionel Sambuc         err = atf_no_error();
58811be35a1SLionel Sambuc         *ap = a;
58911be35a1SLionel Sambuc     }
59011be35a1SLionel Sambuc 
59111be35a1SLionel Sambuc     return err;
59211be35a1SLionel Sambuc }
59311be35a1SLionel Sambuc 
59411be35a1SLionel Sambuc struct exec_args {
59511be35a1SLionel Sambuc     const atf_fs_path_t *m_prog;
59611be35a1SLionel Sambuc     const char *const *m_argv;
59711be35a1SLionel Sambuc     void (*m_prehook)(void);
59811be35a1SLionel Sambuc };
59911be35a1SLionel Sambuc 
60011be35a1SLionel Sambuc static
60111be35a1SLionel Sambuc void
do_exec(void * v)60211be35a1SLionel Sambuc do_exec(void *v)
60311be35a1SLionel Sambuc {
60411be35a1SLionel Sambuc     struct exec_args *ea = v;
60511be35a1SLionel Sambuc 
60611be35a1SLionel Sambuc     if (ea->m_prehook != NULL)
60711be35a1SLionel Sambuc         ea->m_prehook();
60811be35a1SLionel Sambuc 
609*3260d16fSLionel Sambuc #if defined(__minix) && !defined(NDEBUG)
610*3260d16fSLionel Sambuc     const int ret =
611*3260d16fSLionel Sambuc #endif /* defined(__minix) && !defined(NDEBUG) */
612*3260d16fSLionel Sambuc     const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
61311be35a1SLionel Sambuc     const int errnocopy = errno;
61411be35a1SLionel Sambuc     INV(ret == -1);
61511be35a1SLionel Sambuc     fprintf(stderr, "exec(%s) failed: %s\n",
61611be35a1SLionel Sambuc             atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
61711be35a1SLionel Sambuc     exit(EXIT_FAILURE);
61811be35a1SLionel Sambuc }
61911be35a1SLionel Sambuc 
62011be35a1SLionel Sambuc 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))62111be35a1SLionel Sambuc atf_process_exec_array(atf_process_status_t *s,
62211be35a1SLionel Sambuc                        const atf_fs_path_t *prog,
62311be35a1SLionel Sambuc                        const char *const *argv,
62411be35a1SLionel Sambuc                        const atf_process_stream_t *outsb,
62511be35a1SLionel Sambuc                        const atf_process_stream_t *errsb,
62611be35a1SLionel Sambuc                        void (*prehook)(void))
62711be35a1SLionel Sambuc {
62811be35a1SLionel Sambuc     atf_error_t err;
62984d9c625SLionel Sambuc     atf_process_child_t c = { .m_pid = 0, .m_stdout = 1, .m_stderr = 2 }; /* MINIX: Complain in -O3 */
63011be35a1SLionel Sambuc     struct exec_args ea = { prog, argv, prehook };
63111be35a1SLionel Sambuc 
63211be35a1SLionel Sambuc     PRE(outsb == NULL ||
63311be35a1SLionel Sambuc         atf_process_stream_type(outsb) != atf_process_stream_type_capture);
63411be35a1SLionel Sambuc     PRE(errsb == NULL ||
63511be35a1SLionel Sambuc         atf_process_stream_type(errsb) != atf_process_stream_type_capture);
63611be35a1SLionel Sambuc 
63711be35a1SLionel Sambuc     err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
63811be35a1SLionel Sambuc     if (atf_is_error(err))
63911be35a1SLionel Sambuc         goto out;
64011be35a1SLionel Sambuc 
64111be35a1SLionel Sambuc again:
64211be35a1SLionel Sambuc     err = atf_process_child_wait(&c, s);
64311be35a1SLionel Sambuc     if (atf_is_error(err)) {
64411be35a1SLionel Sambuc         INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
64511be35a1SLionel Sambuc         atf_error_free(err);
64611be35a1SLionel Sambuc         goto again;
64711be35a1SLionel Sambuc     }
64811be35a1SLionel Sambuc 
64911be35a1SLionel Sambuc out:
65011be35a1SLionel Sambuc     return err;
65111be35a1SLionel Sambuc }
65211be35a1SLionel Sambuc 
65311be35a1SLionel Sambuc 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))65411be35a1SLionel Sambuc atf_process_exec_list(atf_process_status_t *s,
65511be35a1SLionel Sambuc                       const atf_fs_path_t *prog,
65611be35a1SLionel Sambuc                       const atf_list_t *argv,
65711be35a1SLionel Sambuc                       const atf_process_stream_t *outsb,
65811be35a1SLionel Sambuc                       const atf_process_stream_t *errsb,
65911be35a1SLionel Sambuc                       void (*prehook)(void))
66011be35a1SLionel Sambuc {
66111be35a1SLionel Sambuc     atf_error_t err;
66211be35a1SLionel Sambuc     const char **argv2;
66311be35a1SLionel Sambuc 
66411be35a1SLionel Sambuc     PRE(outsb == NULL ||
66511be35a1SLionel Sambuc         atf_process_stream_type(outsb) != atf_process_stream_type_capture);
66611be35a1SLionel Sambuc     PRE(errsb == NULL ||
66711be35a1SLionel Sambuc         atf_process_stream_type(errsb) != atf_process_stream_type_capture);
66811be35a1SLionel Sambuc 
66911be35a1SLionel Sambuc     argv2 = NULL; /* Silence GCC warning. */
67011be35a1SLionel Sambuc     err = list_to_array(argv, &argv2);
67111be35a1SLionel Sambuc     if (atf_is_error(err))
67211be35a1SLionel Sambuc         goto out;
67311be35a1SLionel Sambuc 
67411be35a1SLionel Sambuc     err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
67511be35a1SLionel Sambuc 
67611be35a1SLionel Sambuc     free(argv2);
67711be35a1SLionel Sambuc out:
67811be35a1SLionel Sambuc     return err;
67911be35a1SLionel Sambuc }
680