2 * Automated Testing Framework (atf)
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
40 #include "atf-c/defs.h"
41 #include "atf-c/error.h"
46 /* This prototype is not in the header file because this is a private
47 * function; however, we need to access it during testing. */
48 atf_error_t atf_process_status_init(atf_process_status_t *, int);
50 /* ---------------------------------------------------------------------
51 * The "stream_prepare" auxiliary type.
52 * --------------------------------------------------------------------- */
54 struct stream_prepare {
55 const atf_process_stream_t *m_sb;
60 typedef struct stream_prepare stream_prepare_t;
64 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
68 const int type = atf_process_stream_type(sb);
71 sp->m_pipefds_ok = false;
73 if (type == atf_process_stream_type_capture) {
74 if (pipe(sp->m_pipefds) == -1)
75 err = atf_libc_error(errno, "Failed to create pipe");
78 sp->m_pipefds_ok = true;
88 stream_prepare_fini(stream_prepare_t *sp)
90 if (sp->m_pipefds_ok) {
91 close(sp->m_pipefds[0]);
92 close(sp->m_pipefds[1]);
96 /* ---------------------------------------------------------------------
97 * The "atf_process_stream" type.
98 * --------------------------------------------------------------------- */
100 const int atf_process_stream_type_capture = 1;
101 const int atf_process_stream_type_connect = 2;
102 const int atf_process_stream_type_inherit = 3;
103 const int atf_process_stream_type_redirect_fd = 4;
104 const int atf_process_stream_type_redirect_path = 5;
108 stream_is_valid(const atf_process_stream_t *sb)
110 return (sb->m_type == atf_process_stream_type_capture) ||
111 (sb->m_type == atf_process_stream_type_connect) ||
112 (sb->m_type == atf_process_stream_type_inherit) ||
113 (sb->m_type == atf_process_stream_type_redirect_fd) ||
114 (sb->m_type == atf_process_stream_type_redirect_path);
118 atf_process_stream_init_capture(atf_process_stream_t *sb)
120 sb->m_type = atf_process_stream_type_capture;
122 POST(stream_is_valid(sb));
123 return atf_no_error();
127 atf_process_stream_init_connect(atf_process_stream_t *sb,
128 const int src_fd, const int tgt_fd)
132 PRE(src_fd != tgt_fd);
134 sb->m_type = atf_process_stream_type_connect;
135 sb->m_src_fd = src_fd;
136 sb->m_tgt_fd = tgt_fd;
138 POST(stream_is_valid(sb));
139 return atf_no_error();
143 atf_process_stream_init_inherit(atf_process_stream_t *sb)
145 sb->m_type = atf_process_stream_type_inherit;
147 POST(stream_is_valid(sb));
148 return atf_no_error();
152 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
155 sb->m_type = atf_process_stream_type_redirect_fd;
158 POST(stream_is_valid(sb));
159 return atf_no_error();
163 atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
164 const atf_fs_path_t *path)
166 sb->m_type = atf_process_stream_type_redirect_path;
169 POST(stream_is_valid(sb));
170 return atf_no_error();
174 atf_process_stream_fini(atf_process_stream_t *sb)
176 PRE(stream_is_valid(sb));
180 atf_process_stream_type(const atf_process_stream_t *sb)
182 PRE(stream_is_valid(sb));
187 /* ---------------------------------------------------------------------
188 * The "atf_process_status" type.
189 * --------------------------------------------------------------------- */
192 atf_process_status_init(atf_process_status_t *s, int status)
194 s->m_status = status;
196 return atf_no_error();
200 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
205 atf_process_status_exited(const atf_process_status_t *s)
207 int mutable_status = s->m_status;
208 return WIFEXITED(mutable_status);
212 atf_process_status_exitstatus(const atf_process_status_t *s)
214 PRE(atf_process_status_exited(s));
215 int mutable_status = s->m_status;
216 return WEXITSTATUS(mutable_status);
220 atf_process_status_signaled(const atf_process_status_t *s)
222 int mutable_status = s->m_status;
223 return WIFSIGNALED(mutable_status);
227 atf_process_status_termsig(const atf_process_status_t *s)
229 PRE(atf_process_status_signaled(s));
230 int mutable_status = s->m_status;
231 return WTERMSIG(mutable_status);
235 atf_process_status_coredump(const atf_process_status_t *s)
237 PRE(atf_process_status_signaled(s));
238 #if defined(WCOREDUMP)
239 int mutable_status = s->m_status;
240 return WCOREDUMP(mutable_status);
246 /* ---------------------------------------------------------------------
247 * The "atf_process_child" type.
248 * --------------------------------------------------------------------- */
252 atf_process_child_init(atf_process_child_t *c)
258 return atf_no_error();
263 atf_process_child_fini(atf_process_child_t *c)
265 if (c->m_stdout != -1)
267 if (c->m_stderr != -1)
272 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
277 if (waitpid(c->m_pid, &status, 0) == -1)
278 err = atf_libc_error(errno, "Failed waiting for process %d",
281 atf_process_child_fini(c);
282 err = atf_process_status_init(s, status);
289 atf_process_child_pid(const atf_process_child_t *c)
295 atf_process_child_stdout(atf_process_child_t *c)
297 PRE(c->m_stdout != -1);
302 atf_process_child_stderr(atf_process_child_t *c)
304 PRE(c->m_stderr != -1);
308 /* ---------------------------------------------------------------------
310 * --------------------------------------------------------------------- */
314 safe_dup(const int oldfd, const int newfd)
318 if (oldfd != newfd) {
319 if (dup2(oldfd, newfd) == -1) {
320 err = atf_libc_error(errno, "Could not allocate file descriptor");
323 err = atf_no_error();
326 err = atf_no_error();
333 child_connect(const stream_prepare_t *sp, int procfd)
336 const int type = atf_process_stream_type(sp->m_sb);
338 if (type == atf_process_stream_type_capture) {
339 close(sp->m_pipefds[0]);
340 err = safe_dup(sp->m_pipefds[1], procfd);
341 } else if (type == atf_process_stream_type_connect) {
342 if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
343 err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
344 sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
346 err = atf_no_error();
347 } else if (type == atf_process_stream_type_inherit) {
348 err = atf_no_error();
349 } else if (type == atf_process_stream_type_redirect_fd) {
350 err = safe_dup(sp->m_sb->m_fd, procfd);
351 } else if (type == atf_process_stream_type_redirect_path) {
352 int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
353 O_WRONLY | O_CREAT | O_TRUNC, 0644);
355 err = atf_libc_error(errno, "Could not create %s",
356 atf_fs_path_cstring(sp->m_sb->m_path));
358 err = safe_dup(aux, procfd);
359 if (atf_is_error(err))
364 err = atf_no_error();
372 parent_connect(const stream_prepare_t *sp, int *fd)
374 const int type = atf_process_stream_type(sp->m_sb);
376 if (type == atf_process_stream_type_capture) {
377 close(sp->m_pipefds[1]);
378 *fd = sp->m_pipefds[0];
379 } else if (type == atf_process_stream_type_connect) {
381 } else if (type == atf_process_stream_type_inherit) {
383 } else if (type == atf_process_stream_type_redirect_fd) {
385 } else if (type == atf_process_stream_type_redirect_path) {
394 do_parent(atf_process_child_t *c,
396 const stream_prepare_t *outsp,
397 const stream_prepare_t *errsp)
401 err = atf_process_child_init(c);
402 if (atf_is_error(err))
407 parent_connect(outsp, &c->m_stdout);
408 parent_connect(errsp, &c->m_stderr);
416 do_child(void (*)(void *),
418 const stream_prepare_t *,
419 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
423 do_child(void (*start)(void *),
425 const stream_prepare_t *outsp,
426 const stream_prepare_t *errsp)
430 err = child_connect(outsp, STDOUT_FILENO);
431 if (atf_is_error(err))
434 err = child_connect(errsp, STDERR_FILENO);
435 if (atf_is_error(err))
442 if (atf_is_error(err)) {
445 atf_error_format(err, buf, sizeof(buf));
446 fprintf(stderr, "Unhandled error: %s\n", buf);
456 fork_with_streams(atf_process_child_t *c,
457 void (*start)(void *),
458 const atf_process_stream_t *outsb,
459 const atf_process_stream_t *errsb,
463 stream_prepare_t outsp;
464 stream_prepare_t errsp;
467 err = stream_prepare_init(&outsp, outsb);
468 if (atf_is_error(err))
471 err = stream_prepare_init(&errsp, errsb);
472 if (atf_is_error(err))
477 err = atf_libc_error(errno, "Failed to fork");
482 do_child(start, v, &outsp, &errsp);
485 err = atf_no_error();
487 err = do_parent(c, pid, &outsp, &errsp);
488 if (atf_is_error(err))
495 stream_prepare_fini(&errsp);
497 stream_prepare_fini(&outsp);
505 init_stream_w_default(const atf_process_stream_t *usersb,
506 atf_process_stream_t *inheritsb,
507 const atf_process_stream_t **realsb)
511 if (usersb == NULL) {
512 err = atf_process_stream_init_inherit(inheritsb);
513 if (!atf_is_error(err))
516 err = atf_no_error();
524 atf_process_fork(atf_process_child_t *c,
525 void (*start)(void *),
526 const atf_process_stream_t *outsb,
527 const atf_process_stream_t *errsb,
531 atf_process_stream_t inherit_outsb, inherit_errsb;
532 const atf_process_stream_t *real_outsb, *real_errsb;
534 real_outsb = NULL; /* Shut up GCC warning. */
535 err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
536 if (atf_is_error(err))
539 real_errsb = NULL; /* Shut up GCC warning. */
540 err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
541 if (atf_is_error(err))
544 err = fork_with_streams(c, start, real_outsb, real_errsb, v);
547 atf_process_stream_fini(&inherit_errsb);
550 atf_process_stream_fini(&inherit_outsb);
557 const_execvp(const char *file, const char *const *argv)
559 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
560 return execvp(file, UNCONST(argv));
566 list_to_array(const atf_list_t *l, const char ***ap)
571 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
573 err = atf_no_memory_error();
576 atf_list_citer_t liter;
579 atf_list_for_each_c(liter, l) {
580 *aiter = (const char *)atf_list_citer_data(liter);
585 err = atf_no_error();
593 const atf_fs_path_t *m_prog;
594 const char *const *m_argv;
595 void (*m_prehook)(void);
602 struct exec_args *ea = v;
604 if (ea->m_prehook != NULL)
607 const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
608 const int errnocopy = errno;
610 fprintf(stderr, "exec(%s) failed: %s\n",
611 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
616 atf_process_exec_array(atf_process_status_t *s,
617 const atf_fs_path_t *prog,
618 const char *const *argv,
619 const atf_process_stream_t *outsb,
620 const atf_process_stream_t *errsb,
621 void (*prehook)(void))
624 atf_process_child_t c;
625 struct exec_args ea = { prog, argv, prehook };
628 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
630 atf_process_stream_type(errsb) != atf_process_stream_type_capture);
632 err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
633 if (atf_is_error(err))
637 err = atf_process_child_wait(&c, s);
638 if (atf_is_error(err)) {
639 INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
649 atf_process_exec_list(atf_process_status_t *s,
650 const atf_fs_path_t *prog,
651 const atf_list_t *argv,
652 const atf_process_stream_t *outsb,
653 const atf_process_stream_t *errsb,
654 void (*prehook)(void))
660 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
662 atf_process_stream_type(errsb) != atf_process_stream_type_capture);
664 argv2 = NULL; /* Silence GCC warning. */
665 err = list_to_array(argv, &argv2);
666 if (atf_is_error(err))
669 err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);