1 /* Copyright (c) 2007 The NetBSD Foundation, Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
26 #include "atf-c/detail/process.h"
28 #include <sys/types.h>
38 #include "atf-c/defs.h"
39 #include "atf-c/detail/sanity.h"
40 #include "atf-c/error.h"
42 /* This prototype is not in the header file because this is a private
43 * function; however, we need to access it during testing. */
44 atf_error_t atf_process_status_init(atf_process_status_t *, int);
46 /* ---------------------------------------------------------------------
47 * The "stream_prepare" auxiliary type.
48 * --------------------------------------------------------------------- */
50 struct stream_prepare {
51 const atf_process_stream_t *m_sb;
56 typedef struct stream_prepare stream_prepare_t;
60 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
64 const int type = atf_process_stream_type(sb);
67 sp->m_pipefds_ok = false;
69 if (type == atf_process_stream_type_capture) {
70 if (pipe(sp->m_pipefds) == -1)
71 err = atf_libc_error(errno, "Failed to create pipe");
74 sp->m_pipefds_ok = true;
84 stream_prepare_fini(stream_prepare_t *sp)
86 if (sp->m_pipefds_ok) {
87 close(sp->m_pipefds[0]);
88 close(sp->m_pipefds[1]);
92 /* ---------------------------------------------------------------------
93 * The "atf_process_stream" type.
94 * --------------------------------------------------------------------- */
96 const int atf_process_stream_type_capture = 1;
97 const int atf_process_stream_type_connect = 2;
98 const int atf_process_stream_type_inherit = 3;
99 const int atf_process_stream_type_redirect_fd = 4;
100 const int atf_process_stream_type_redirect_path = 5;
104 stream_is_valid(const atf_process_stream_t *sb)
106 return (sb->m_type == atf_process_stream_type_capture) ||
107 (sb->m_type == atf_process_stream_type_connect) ||
108 (sb->m_type == atf_process_stream_type_inherit) ||
109 (sb->m_type == atf_process_stream_type_redirect_fd) ||
110 (sb->m_type == atf_process_stream_type_redirect_path);
114 atf_process_stream_init_capture(atf_process_stream_t *sb)
116 sb->m_type = atf_process_stream_type_capture;
118 POST(stream_is_valid(sb));
119 return atf_no_error();
123 atf_process_stream_init_connect(atf_process_stream_t *sb,
124 const int src_fd, const int tgt_fd)
128 PRE(src_fd != tgt_fd);
130 sb->m_type = atf_process_stream_type_connect;
131 sb->m_src_fd = src_fd;
132 sb->m_tgt_fd = tgt_fd;
134 POST(stream_is_valid(sb));
135 return atf_no_error();
139 atf_process_stream_init_inherit(atf_process_stream_t *sb)
141 sb->m_type = atf_process_stream_type_inherit;
143 POST(stream_is_valid(sb));
144 return atf_no_error();
148 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
151 sb->m_type = atf_process_stream_type_redirect_fd;
154 POST(stream_is_valid(sb));
155 return atf_no_error();
159 atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
160 const atf_fs_path_t *path)
162 sb->m_type = atf_process_stream_type_redirect_path;
165 POST(stream_is_valid(sb));
166 return atf_no_error();
170 atf_process_stream_fini(atf_process_stream_t *sb)
172 PRE(stream_is_valid(sb));
176 atf_process_stream_type(const atf_process_stream_t *sb)
178 PRE(stream_is_valid(sb));
183 /* ---------------------------------------------------------------------
184 * The "atf_process_status" type.
185 * --------------------------------------------------------------------- */
188 atf_process_status_init(atf_process_status_t *s, int status)
190 s->m_status = status;
192 return atf_no_error();
196 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
201 atf_process_status_exited(const atf_process_status_t *s)
203 int mutable_status = s->m_status;
204 return WIFEXITED(mutable_status);
208 atf_process_status_exitstatus(const atf_process_status_t *s)
210 PRE(atf_process_status_exited(s));
211 int mutable_status = s->m_status;
212 return WEXITSTATUS(mutable_status);
216 atf_process_status_signaled(const atf_process_status_t *s)
218 int mutable_status = s->m_status;
219 return WIFSIGNALED(mutable_status);
223 atf_process_status_termsig(const atf_process_status_t *s)
225 PRE(atf_process_status_signaled(s));
226 int mutable_status = s->m_status;
227 return WTERMSIG(mutable_status);
231 atf_process_status_coredump(const atf_process_status_t *s)
233 PRE(atf_process_status_signaled(s));
234 #if defined(WCOREDUMP)
235 int mutable_status = s->m_status;
236 return WCOREDUMP(mutable_status);
242 /* ---------------------------------------------------------------------
243 * The "atf_process_child" type.
244 * --------------------------------------------------------------------- */
248 atf_process_child_init(atf_process_child_t *c)
254 return atf_no_error();
259 atf_process_child_fini(atf_process_child_t *c)
261 if (c->m_stdout != -1)
263 if (c->m_stderr != -1)
268 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
273 if (waitpid(c->m_pid, &status, 0) == -1)
274 err = atf_libc_error(errno, "Failed waiting for process %d",
277 atf_process_child_fini(c);
278 err = atf_process_status_init(s, status);
285 atf_process_child_pid(const atf_process_child_t *c)
291 atf_process_child_stdout(atf_process_child_t *c)
293 PRE(c->m_stdout != -1);
298 atf_process_child_stderr(atf_process_child_t *c)
300 PRE(c->m_stderr != -1);
304 /* ---------------------------------------------------------------------
306 * --------------------------------------------------------------------- */
310 safe_dup(const int oldfd, const int newfd)
314 if (oldfd != newfd) {
315 if (dup2(oldfd, newfd) == -1) {
316 err = atf_libc_error(errno, "Could not allocate file descriptor");
319 err = atf_no_error();
322 err = atf_no_error();
329 child_connect(const stream_prepare_t *sp, int procfd)
332 const int type = atf_process_stream_type(sp->m_sb);
334 if (type == atf_process_stream_type_capture) {
335 close(sp->m_pipefds[0]);
336 err = safe_dup(sp->m_pipefds[1], procfd);
337 } else if (type == atf_process_stream_type_connect) {
338 if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
339 err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
340 sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
342 err = atf_no_error();
343 } else if (type == atf_process_stream_type_inherit) {
344 err = atf_no_error();
345 } else if (type == atf_process_stream_type_redirect_fd) {
346 err = safe_dup(sp->m_sb->m_fd, procfd);
347 } else if (type == atf_process_stream_type_redirect_path) {
348 int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
349 O_WRONLY | O_CREAT | O_TRUNC, 0644);
351 err = atf_libc_error(errno, "Could not create %s",
352 atf_fs_path_cstring(sp->m_sb->m_path));
354 err = safe_dup(aux, procfd);
355 if (atf_is_error(err))
360 err = atf_no_error();
368 parent_connect(const stream_prepare_t *sp, int *fd)
370 const int type = atf_process_stream_type(sp->m_sb);
372 if (type == atf_process_stream_type_capture) {
373 close(sp->m_pipefds[1]);
374 *fd = sp->m_pipefds[0];
375 } else if (type == atf_process_stream_type_connect) {
377 } else if (type == atf_process_stream_type_inherit) {
379 } else if (type == atf_process_stream_type_redirect_fd) {
381 } else if (type == atf_process_stream_type_redirect_path) {
390 do_parent(atf_process_child_t *c,
392 const stream_prepare_t *outsp,
393 const stream_prepare_t *errsp)
397 err = atf_process_child_init(c);
398 if (atf_is_error(err))
403 parent_connect(outsp, &c->m_stdout);
404 parent_connect(errsp, &c->m_stderr);
412 do_child(void (*)(void *),
414 const stream_prepare_t *,
415 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
419 do_child(void (*start)(void *),
421 const stream_prepare_t *outsp,
422 const stream_prepare_t *errsp)
426 err = child_connect(outsp, STDOUT_FILENO);
427 if (atf_is_error(err))
430 err = child_connect(errsp, STDERR_FILENO);
431 if (atf_is_error(err))
438 if (atf_is_error(err)) {
441 atf_error_format(err, buf, sizeof(buf));
442 fprintf(stderr, "Unhandled error: %s\n", buf);
452 fork_with_streams(atf_process_child_t *c,
453 void (*start)(void *),
454 const atf_process_stream_t *outsb,
455 const atf_process_stream_t *errsb,
459 stream_prepare_t outsp;
460 stream_prepare_t errsp;
463 err = stream_prepare_init(&outsp, outsb);
464 if (atf_is_error(err))
467 err = stream_prepare_init(&errsp, errsb);
468 if (atf_is_error(err))
473 err = atf_libc_error(errno, "Failed to fork");
478 do_child(start, v, &outsp, &errsp);
481 err = atf_no_error();
483 err = do_parent(c, pid, &outsp, &errsp);
484 if (atf_is_error(err))
491 stream_prepare_fini(&errsp);
493 stream_prepare_fini(&outsp);
501 init_stream_w_default(const atf_process_stream_t *usersb,
502 atf_process_stream_t *inheritsb,
503 const atf_process_stream_t **realsb)
507 if (usersb == NULL) {
508 err = atf_process_stream_init_inherit(inheritsb);
509 if (!atf_is_error(err))
512 err = atf_no_error();
520 atf_process_fork(atf_process_child_t *c,
521 void (*start)(void *),
522 const atf_process_stream_t *outsb,
523 const atf_process_stream_t *errsb,
527 atf_process_stream_t inherit_outsb, inherit_errsb;
528 const atf_process_stream_t *real_outsb, *real_errsb;
530 real_outsb = NULL; /* Shut up GCC warning. */
531 err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
532 if (atf_is_error(err))
535 real_errsb = NULL; /* Shut up GCC warning. */
536 err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
537 if (atf_is_error(err))
540 err = fork_with_streams(c, start, real_outsb, real_errsb, v);
543 atf_process_stream_fini(&inherit_errsb);
546 atf_process_stream_fini(&inherit_outsb);
553 const_execvp(const char *file, const char *const *argv)
555 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
556 return execvp(file, UNCONST(argv));
562 list_to_array(const atf_list_t *l, const char ***ap)
567 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
569 err = atf_no_memory_error();
572 atf_list_citer_t liter;
575 atf_list_for_each_c(liter, l) {
576 *aiter = (const char *)atf_list_citer_data(liter);
581 err = atf_no_error();
589 const atf_fs_path_t *m_prog;
590 const char *const *m_argv;
591 void (*m_prehook)(void);
598 struct exec_args *ea = v;
600 if (ea->m_prehook != NULL)
603 const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
604 const int errnocopy = errno;
606 fprintf(stderr, "exec(%s) failed: %s\n",
607 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
612 atf_process_exec_array(atf_process_status_t *s,
613 const atf_fs_path_t *prog,
614 const char *const *argv,
615 const atf_process_stream_t *outsb,
616 const atf_process_stream_t *errsb,
617 void (*prehook)(void))
620 atf_process_child_t c;
621 struct exec_args ea = { prog, argv, prehook };
624 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
626 atf_process_stream_type(errsb) != atf_process_stream_type_capture);
628 err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
629 if (atf_is_error(err))
633 err = atf_process_child_wait(&c, s);
634 if (atf_is_error(err)) {
635 INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
645 atf_process_exec_list(atf_process_status_t *s,
646 const atf_fs_path_t *prog,
647 const atf_list_t *argv,
648 const atf_process_stream_t *outsb,
649 const atf_process_stream_t *errsb,
650 void (*prehook)(void))
656 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
658 atf_process_stream_type(errsb) != atf_process_stream_type_capture);
660 argv2 = NULL; /* Silence GCC warning. */
661 err = list_to_array(argv, &argv2);
662 if (atf_is_error(err))
665 err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);