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