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