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;
106 #if defined(__minix) && !defined(NDEBUG)
109 stream_is_valid(const atf_process_stream_t
*sb
)
111 return (sb
->m_type
== atf_process_stream_type_capture
) ||
112 (sb
->m_type
== atf_process_stream_type_connect
) ||
113 (sb
->m_type
== atf_process_stream_type_inherit
) ||
114 (sb
->m_type
== atf_process_stream_type_redirect_fd
) ||
115 (sb
->m_type
== atf_process_stream_type_redirect_path
);
117 #endif /* defined(__minix) && !defined(NDEBUG) */
120 atf_process_stream_init_capture(atf_process_stream_t
*sb
)
122 sb
->m_type
= atf_process_stream_type_capture
;
124 POST(stream_is_valid(sb
));
125 return atf_no_error();
129 atf_process_stream_init_connect(atf_process_stream_t
*sb
,
130 const int src_fd
, const int tgt_fd
)
134 PRE(src_fd
!= tgt_fd
);
136 sb
->m_type
= atf_process_stream_type_connect
;
137 sb
->m_src_fd
= src_fd
;
138 sb
->m_tgt_fd
= tgt_fd
;
140 POST(stream_is_valid(sb
));
141 return atf_no_error();
145 atf_process_stream_init_inherit(atf_process_stream_t
*sb
)
147 sb
->m_type
= atf_process_stream_type_inherit
;
149 POST(stream_is_valid(sb
));
150 return atf_no_error();
154 atf_process_stream_init_redirect_fd(atf_process_stream_t
*sb
,
157 sb
->m_type
= atf_process_stream_type_redirect_fd
;
160 POST(stream_is_valid(sb
));
161 return atf_no_error();
165 atf_process_stream_init_redirect_path(atf_process_stream_t
*sb
,
166 const atf_fs_path_t
*path
)
168 sb
->m_type
= atf_process_stream_type_redirect_path
;
171 POST(stream_is_valid(sb
));
172 return atf_no_error();
176 atf_process_stream_fini(atf_process_stream_t
*sb
)
178 PRE(stream_is_valid(sb
));
182 atf_process_stream_type(const atf_process_stream_t
*sb
)
184 PRE(stream_is_valid(sb
));
189 /* ---------------------------------------------------------------------
190 * The "atf_process_status" type.
191 * --------------------------------------------------------------------- */
194 atf_process_status_init(atf_process_status_t
*s
, int status
)
196 s
->m_status
= status
;
198 return atf_no_error();
202 atf_process_status_fini(atf_process_status_t
*s ATF_DEFS_ATTRIBUTE_UNUSED
)
207 atf_process_status_exited(const atf_process_status_t
*s
)
209 int mutable_status
= s
->m_status
;
210 return WIFEXITED(mutable_status
);
214 atf_process_status_exitstatus(const atf_process_status_t
*s
)
216 PRE(atf_process_status_exited(s
));
217 int mutable_status
= s
->m_status
;
218 return WEXITSTATUS(mutable_status
);
222 atf_process_status_signaled(const atf_process_status_t
*s
)
224 int mutable_status
= s
->m_status
;
225 return WIFSIGNALED(mutable_status
);
229 atf_process_status_termsig(const atf_process_status_t
*s
)
231 PRE(atf_process_status_signaled(s
));
232 int mutable_status
= s
->m_status
;
233 return WTERMSIG(mutable_status
);
237 atf_process_status_coredump(const atf_process_status_t
*s
)
239 PRE(atf_process_status_signaled(s
));
240 #if defined(WCOREDUMP)
241 int mutable_status
= s
->m_status
;
242 return WCOREDUMP(mutable_status
);
248 /* ---------------------------------------------------------------------
249 * The "atf_process_child" type.
250 * --------------------------------------------------------------------- */
254 atf_process_child_init(atf_process_child_t
*c
)
260 return atf_no_error();
265 atf_process_child_fini(atf_process_child_t
*c
)
267 if (c
->m_stdout
!= -1)
269 if (c
->m_stderr
!= -1)
274 atf_process_child_wait(atf_process_child_t
*c
, atf_process_status_t
*s
)
279 if (waitpid(c
->m_pid
, &status
, 0) == -1)
280 err
= atf_libc_error(errno
, "Failed waiting for process %d",
283 atf_process_child_fini(c
);
284 err
= atf_process_status_init(s
, status
);
291 atf_process_child_pid(const atf_process_child_t
*c
)
297 atf_process_child_stdout(atf_process_child_t
*c
)
299 PRE(c
->m_stdout
!= -1);
304 atf_process_child_stderr(atf_process_child_t
*c
)
306 PRE(c
->m_stderr
!= -1);
310 /* ---------------------------------------------------------------------
312 * --------------------------------------------------------------------- */
316 safe_dup(const int oldfd
, const int newfd
)
320 if (oldfd
!= newfd
) {
321 if (dup2(oldfd
, newfd
) == -1) {
322 err
= atf_libc_error(errno
, "Could not allocate file descriptor");
325 err
= atf_no_error();
328 err
= atf_no_error();
335 child_connect(const stream_prepare_t
*sp
, int procfd
)
338 const int type
= atf_process_stream_type(sp
->m_sb
);
340 if (type
== atf_process_stream_type_capture
) {
341 close(sp
->m_pipefds
[0]);
342 err
= safe_dup(sp
->m_pipefds
[1], procfd
);
343 } else if (type
== atf_process_stream_type_connect
) {
344 if (dup2(sp
->m_sb
->m_tgt_fd
, sp
->m_sb
->m_src_fd
) == -1)
345 err
= atf_libc_error(errno
, "Cannot connect descriptor %d to %d",
346 sp
->m_sb
->m_tgt_fd
, sp
->m_sb
->m_src_fd
);
348 err
= atf_no_error();
349 } else if (type
== atf_process_stream_type_inherit
) {
350 err
= atf_no_error();
351 } else if (type
== atf_process_stream_type_redirect_fd
) {
352 err
= safe_dup(sp
->m_sb
->m_fd
, procfd
);
353 } else if (type
== atf_process_stream_type_redirect_path
) {
354 int aux
= open(atf_fs_path_cstring(sp
->m_sb
->m_path
),
355 O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
357 err
= atf_libc_error(errno
, "Could not create %s",
358 atf_fs_path_cstring(sp
->m_sb
->m_path
));
360 err
= safe_dup(aux
, procfd
);
361 if (atf_is_error(err
))
366 err
= atf_no_error();
374 parent_connect(const stream_prepare_t
*sp
, int *fd
)
376 const int type
= atf_process_stream_type(sp
->m_sb
);
378 if (type
== atf_process_stream_type_capture
) {
379 close(sp
->m_pipefds
[1]);
380 *fd
= sp
->m_pipefds
[0];
381 } else if (type
== atf_process_stream_type_connect
) {
383 } else if (type
== atf_process_stream_type_inherit
) {
385 } else if (type
== atf_process_stream_type_redirect_fd
) {
387 } else if (type
== atf_process_stream_type_redirect_path
) {
396 do_parent(atf_process_child_t
*c
,
398 const stream_prepare_t
*outsp
,
399 const stream_prepare_t
*errsp
)
403 err
= atf_process_child_init(c
);
404 if (atf_is_error(err
))
409 parent_connect(outsp
, &c
->m_stdout
);
410 parent_connect(errsp
, &c
->m_stderr
);
418 do_child(void (*)(void *),
420 const stream_prepare_t
*,
421 const stream_prepare_t
*) ATF_DEFS_ATTRIBUTE_NORETURN
;
425 do_child(void (*start
)(void *),
427 const stream_prepare_t
*outsp
,
428 const stream_prepare_t
*errsp
)
432 err
= child_connect(outsp
, STDOUT_FILENO
);
433 if (atf_is_error(err
))
436 err
= child_connect(errsp
, STDERR_FILENO
);
437 if (atf_is_error(err
))
444 if (atf_is_error(err
)) {
447 atf_error_format(err
, buf
, sizeof(buf
));
448 fprintf(stderr
, "Unhandled error: %s\n", buf
);
458 fork_with_streams(atf_process_child_t
*c
,
459 void (*start
)(void *),
460 const atf_process_stream_t
*outsb
,
461 const atf_process_stream_t
*errsb
,
465 stream_prepare_t outsp
;
466 stream_prepare_t errsp
;
469 err
= stream_prepare_init(&outsp
, outsb
);
470 if (atf_is_error(err
))
473 err
= stream_prepare_init(&errsp
, errsb
);
474 if (atf_is_error(err
))
479 err
= atf_libc_error(errno
, "Failed to fork");
484 do_child(start
, v
, &outsp
, &errsp
);
487 err
= atf_no_error();
489 err
= do_parent(c
, pid
, &outsp
, &errsp
);
490 if (atf_is_error(err
))
497 stream_prepare_fini(&errsp
);
499 stream_prepare_fini(&outsp
);
507 init_stream_w_default(const atf_process_stream_t
*usersb
,
508 atf_process_stream_t
*inheritsb
,
509 const atf_process_stream_t
**realsb
)
513 if (usersb
== NULL
) {
514 err
= atf_process_stream_init_inherit(inheritsb
);
515 if (!atf_is_error(err
))
518 err
= atf_no_error();
526 atf_process_fork(atf_process_child_t
*c
,
527 void (*start
)(void *),
528 const atf_process_stream_t
*outsb
,
529 const atf_process_stream_t
*errsb
,
533 atf_process_stream_t inherit_outsb
, inherit_errsb
;
534 const atf_process_stream_t
*real_outsb
, *real_errsb
;
536 real_outsb
= NULL
; /* Shut up GCC warning. */
537 err
= init_stream_w_default(outsb
, &inherit_outsb
, &real_outsb
);
538 if (atf_is_error(err
))
541 real_errsb
= NULL
; /* Shut up GCC warning. */
542 err
= init_stream_w_default(errsb
, &inherit_errsb
, &real_errsb
);
543 if (atf_is_error(err
))
546 err
= fork_with_streams(c
, start
, real_outsb
, real_errsb
, v
);
549 atf_process_stream_fini(&inherit_errsb
);
552 atf_process_stream_fini(&inherit_outsb
);
559 const_execvp(const char *file
, const char *const *argv
)
561 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
562 return execvp(file
, UNCONST(argv
));
568 list_to_array(const atf_list_t
*l
, const char ***ap
)
573 a
= (const char **)malloc((atf_list_size(l
) + 1) * sizeof(const char *));
575 err
= atf_no_memory_error();
578 atf_list_citer_t liter
;
581 atf_list_for_each_c(liter
, l
) {
582 *aiter
= (const char *)atf_list_citer_data(liter
);
587 err
= atf_no_error();
595 const atf_fs_path_t
*m_prog
;
596 const char *const *m_argv
;
597 void (*m_prehook
)(void);
604 struct exec_args
*ea
= v
;
606 if (ea
->m_prehook
!= NULL
)
609 #if defined(__minix) && !defined(NDEBUG)
611 #endif /* defined(__minix) && !defined(NDEBUG) */
612 const_execvp(atf_fs_path_cstring(ea
->m_prog
), ea
->m_argv
);
613 const int errnocopy
= errno
;
615 fprintf(stderr
, "exec(%s) failed: %s\n",
616 atf_fs_path_cstring(ea
->m_prog
), strerror(errnocopy
));
621 atf_process_exec_array(atf_process_status_t
*s
,
622 const atf_fs_path_t
*prog
,
623 const char *const *argv
,
624 const atf_process_stream_t
*outsb
,
625 const atf_process_stream_t
*errsb
,
626 void (*prehook
)(void))
629 atf_process_child_t c
= { .m_pid
= 0, .m_stdout
= 1, .m_stderr
= 2 }; /* MINIX: Complain in -O3 */
630 struct exec_args ea
= { prog
, argv
, prehook
};
633 atf_process_stream_type(outsb
) != atf_process_stream_type_capture
);
635 atf_process_stream_type(errsb
) != atf_process_stream_type_capture
);
637 err
= atf_process_fork(&c
, do_exec
, outsb
, errsb
, &ea
);
638 if (atf_is_error(err
))
642 err
= atf_process_child_wait(&c
, s
);
643 if (atf_is_error(err
)) {
644 INV(atf_error_is(err
, "libc") && atf_libc_error_code(err
) == EINTR
);
654 atf_process_exec_list(atf_process_status_t
*s
,
655 const atf_fs_path_t
*prog
,
656 const atf_list_t
*argv
,
657 const atf_process_stream_t
*outsb
,
658 const atf_process_stream_t
*errsb
,
659 void (*prehook
)(void))
665 atf_process_stream_type(outsb
) != atf_process_stream_type_capture
);
667 atf_process_stream_type(errsb
) != atf_process_stream_type_capture
);
669 argv2
= NULL
; /* Silence GCC warning. */
670 err
= list_to_array(argv
, &argv2
);
671 if (atf_is_error(err
))
674 err
= atf_process_exec_array(s
, prog
, argv2
, outsb
, errsb
, prehook
);