2 * Automated Testing Framework (atf)
4 * Copyright (c) 2007, 2008, 2009 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"
42 #include "atf-c/process.h"
43 #include "atf-c/sanity.h"
45 /* This prototype is not in the header file because this is a private
46 * function; however, we need to access it during testing. */
47 atf_error_t
atf_process_status_init(atf_process_status_t
*, int);
49 /* ---------------------------------------------------------------------
50 * The "stream_prepare" auxiliary type.
51 * --------------------------------------------------------------------- */
53 struct stream_prepare
{
54 const atf_process_stream_t
*m_sb
;
59 typedef struct stream_prepare stream_prepare_t
;
63 stream_prepare_init(stream_prepare_t
*sp
, const atf_process_stream_t
*sb
)
67 const int type
= atf_process_stream_type(sb
);
70 sp
->m_pipefds_ok
= false;
72 if (type
== atf_process_stream_type_capture
) {
73 if (pipe(sp
->m_pipefds
) == -1)
74 err
= atf_libc_error(errno
, "Failed to create pipe");
77 sp
->m_pipefds_ok
= true;
87 stream_prepare_fini(stream_prepare_t
*sp
)
89 if (sp
->m_pipefds_ok
) {
90 close(sp
->m_pipefds
[0]);
91 close(sp
->m_pipefds
[1]);
95 /* ---------------------------------------------------------------------
96 * The "atf_process_stream" type.
97 * --------------------------------------------------------------------- */
99 const int atf_process_stream_type_capture
= 1;
100 const int atf_process_stream_type_connect
= 2;
101 const int atf_process_stream_type_inherit
= 3;
102 const int atf_process_stream_type_redirect_fd
= 4;
103 const int atf_process_stream_type_redirect_path
= 5;
107 stream_is_valid(const atf_process_stream_t
*sb
)
109 return (sb
->m_type
== atf_process_stream_type_capture
) ||
110 (sb
->m_type
== atf_process_stream_type_connect
) ||
111 (sb
->m_type
== atf_process_stream_type_inherit
) ||
112 (sb
->m_type
== atf_process_stream_type_redirect_fd
) ||
113 (sb
->m_type
== atf_process_stream_type_redirect_path
);
117 atf_process_stream_init_capture(atf_process_stream_t
*sb
)
119 atf_object_init(&sb
->m_object
);
121 sb
->m_type
= atf_process_stream_type_capture
;
123 POST(stream_is_valid(sb
));
124 return atf_no_error();
128 atf_process_stream_init_connect(atf_process_stream_t
*sb
,
129 const int src_fd
, const int tgt_fd
)
133 PRE(src_fd
!= tgt_fd
);
135 atf_object_init(&sb
->m_object
);
137 sb
->m_type
= atf_process_stream_type_connect
;
138 sb
->m_src_fd
= src_fd
;
139 sb
->m_tgt_fd
= tgt_fd
;
141 POST(stream_is_valid(sb
));
142 return atf_no_error();
146 atf_process_stream_init_inherit(atf_process_stream_t
*sb
)
148 atf_object_init(&sb
->m_object
);
150 sb
->m_type
= atf_process_stream_type_inherit
;
152 POST(stream_is_valid(sb
));
153 return atf_no_error();
157 atf_process_stream_init_redirect_fd(atf_process_stream_t
*sb
,
160 atf_object_init(&sb
->m_object
);
162 sb
->m_type
= atf_process_stream_type_redirect_fd
;
165 POST(stream_is_valid(sb
));
166 return atf_no_error();
170 atf_process_stream_init_redirect_path(atf_process_stream_t
*sb
,
171 const atf_fs_path_t
*path
)
173 atf_object_init(&sb
->m_object
);
175 sb
->m_type
= atf_process_stream_type_redirect_path
;
178 POST(stream_is_valid(sb
));
179 return atf_no_error();
183 atf_process_stream_fini(atf_process_stream_t
*sb
)
185 PRE(stream_is_valid(sb
));
187 atf_object_fini(&sb
->m_object
);
191 atf_process_stream_type(const atf_process_stream_t
*sb
)
193 PRE(stream_is_valid(sb
));
198 /* ---------------------------------------------------------------------
199 * The "atf_process_status" type.
200 * --------------------------------------------------------------------- */
203 atf_process_status_init(atf_process_status_t
*s
, int status
)
205 atf_object_init(&s
->m_object
);
207 s
->m_status
= status
;
209 return atf_no_error();
213 atf_process_status_fini(atf_process_status_t
*s
)
215 atf_object_fini(&s
->m_object
);
219 atf_process_status_exited(const atf_process_status_t
*s
)
221 int mutable_status
= s
->m_status
;
222 return WIFEXITED(mutable_status
);
226 atf_process_status_exitstatus(const atf_process_status_t
*s
)
228 PRE(atf_process_status_exited(s
));
229 int mutable_status
= s
->m_status
;
230 return WEXITSTATUS(mutable_status
);
234 atf_process_status_signaled(const atf_process_status_t
*s
)
236 int mutable_status
= s
->m_status
;
237 return WIFSIGNALED(mutable_status
);
241 atf_process_status_termsig(const atf_process_status_t
*s
)
243 PRE(atf_process_status_signaled(s
));
244 int mutable_status
= s
->m_status
;
245 return WTERMSIG(mutable_status
);
249 atf_process_status_coredump(const atf_process_status_t
*s
)
251 PRE(atf_process_status_signaled(s
));
252 #if defined(WCOREDUMP)
253 int mutable_status
= s
->m_status
;
254 return WCOREDUMP(mutable_status
);
260 /* ---------------------------------------------------------------------
261 * The "atf_process_child" type.
262 * --------------------------------------------------------------------- */
266 atf_process_child_init(atf_process_child_t
*c
)
268 atf_object_init(&c
->m_object
);
274 return atf_no_error();
279 atf_process_child_fini(atf_process_child_t
*c
)
281 atf_object_fini(&c
->m_object
);
285 atf_process_child_wait(atf_process_child_t
*c
, atf_process_status_t
*s
)
290 if (waitpid(c
->m_pid
, &status
, 0) == -1)
291 err
= atf_libc_error(errno
, "Failed waiting for process %d",
294 atf_process_child_fini(c
);
295 err
= atf_process_status_init(s
, status
);
302 atf_process_child_pid(const atf_process_child_t
*c
)
308 atf_process_child_stdout(atf_process_child_t
*c
)
310 PRE(c
->m_stdout
!= -1);
315 atf_process_child_stderr(atf_process_child_t
*c
)
317 PRE(c
->m_stderr
!= -1);
321 /* ---------------------------------------------------------------------
323 * --------------------------------------------------------------------- */
327 safe_dup(const int oldfd
, const int newfd
)
331 if (oldfd
!= newfd
) {
332 if (dup2(oldfd
, newfd
) == -1) {
333 err
= atf_libc_error(errno
, "Could not allocate file descriptor");
336 err
= atf_no_error();
339 err
= atf_no_error();
346 child_connect(const stream_prepare_t
*sp
, int procfd
)
349 const int type
= atf_process_stream_type(sp
->m_sb
);
351 if (type
== atf_process_stream_type_capture
) {
352 close(sp
->m_pipefds
[0]);
353 err
= safe_dup(sp
->m_pipefds
[1], procfd
);
354 } else if (type
== atf_process_stream_type_connect
) {
355 if (dup2(sp
->m_sb
->m_tgt_fd
, sp
->m_sb
->m_src_fd
) == -1)
356 err
= atf_libc_error(errno
, "Cannot connect descriptor %d to %d",
357 sp
->m_sb
->m_tgt_fd
, sp
->m_sb
->m_src_fd
);
359 err
= atf_no_error();
360 } else if (type
== atf_process_stream_type_inherit
) {
361 err
= atf_no_error();
362 } else if (type
== atf_process_stream_type_redirect_fd
) {
363 err
= safe_dup(sp
->m_sb
->m_fd
, procfd
);
364 } else if (type
== atf_process_stream_type_redirect_path
) {
365 int aux
= open(atf_fs_path_cstring(sp
->m_sb
->m_path
),
366 O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
368 err
= atf_libc_error(errno
, "Could not create %s",
369 atf_fs_path_cstring(sp
->m_sb
->m_path
));
371 err
= safe_dup(aux
, procfd
);
372 if (atf_is_error(err
))
377 err
= atf_no_error();
385 parent_connect(const stream_prepare_t
*sp
, int *fd
)
387 const int type
= atf_process_stream_type(sp
->m_sb
);
389 if (type
== atf_process_stream_type_capture
) {
390 close(sp
->m_pipefds
[1]);
391 *fd
= sp
->m_pipefds
[0];
392 } else if (type
== atf_process_stream_type_connect
) {
394 } else if (type
== atf_process_stream_type_inherit
) {
396 } else if (type
== atf_process_stream_type_redirect_fd
) {
398 } else if (type
== atf_process_stream_type_redirect_path
) {
407 do_parent(atf_process_child_t
*c
,
409 const stream_prepare_t
*outsp
,
410 const stream_prepare_t
*errsp
)
414 err
= atf_process_child_init(c
);
415 if (atf_is_error(err
))
420 parent_connect(outsp
, &c
->m_stdout
);
421 parent_connect(errsp
, &c
->m_stderr
);
429 do_child(void (*)(void *),
431 const stream_prepare_t
*,
432 const stream_prepare_t
*) ATF_DEFS_ATTRIBUTE_NORETURN
;
436 do_child(void (*start
)(void *),
438 const stream_prepare_t
*outsp
,
439 const stream_prepare_t
*errsp
)
443 atf_reset_exit_checks();
444 err
= child_connect(outsp
, STDOUT_FILENO
);
445 if (atf_is_error(err
))
448 err
= child_connect(errsp
, STDERR_FILENO
);
449 if (atf_is_error(err
))
456 if (atf_is_error(err
)) {
459 atf_error_format(err
, buf
, sizeof(buf
));
460 fprintf(stderr
, "Unhandled error: %s\n", buf
);
470 fork_with_streams(atf_process_child_t
*c
,
471 void (*start
)(void *),
472 const atf_process_stream_t
*outsb
,
473 const atf_process_stream_t
*errsb
,
477 stream_prepare_t outsp
;
478 stream_prepare_t errsp
;
481 err
= stream_prepare_init(&outsp
, outsb
);
482 if (atf_is_error(err
))
485 err
= stream_prepare_init(&errsp
, errsb
);
486 if (atf_is_error(err
))
491 err
= atf_libc_error(errno
, "Failed to fork");
496 do_child(start
, v
, &outsp
, &errsp
);
499 err
= atf_no_error();
501 err
= do_parent(c
, pid
, &outsp
, &errsp
);
502 if (atf_is_error(err
))
509 stream_prepare_fini(&errsp
);
511 stream_prepare_fini(&outsp
);
519 init_stream_w_default(const atf_process_stream_t
*usersb
,
520 atf_process_stream_t
*inheritsb
,
521 const atf_process_stream_t
**realsb
)
525 if (usersb
== NULL
) {
526 err
= atf_process_stream_init_inherit(inheritsb
);
527 if (!atf_is_error(err
))
530 err
= atf_no_error();
538 atf_process_fork(atf_process_child_t
*c
,
539 void (*start
)(void *),
540 const atf_process_stream_t
*outsb
,
541 const atf_process_stream_t
*errsb
,
545 atf_process_stream_t inherit_outsb
, inherit_errsb
;
546 const atf_process_stream_t
*real_outsb
, *real_errsb
;
548 err
= init_stream_w_default(outsb
, &inherit_outsb
, &real_outsb
);
549 if (atf_is_error(err
))
552 err
= init_stream_w_default(errsb
, &inherit_errsb
, &real_errsb
);
553 if (atf_is_error(err
))
556 err
= fork_with_streams(c
, start
, real_outsb
, real_errsb
, v
);
559 atf_process_stream_fini(&inherit_errsb
);
562 atf_process_stream_fini(&inherit_outsb
);
569 const_execvp(const char *file
, const char *const *argv
)
571 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
572 return execvp(file
, UNCONST(argv
));
578 list_to_array(const atf_list_t
*l
, const char ***ap
)
583 a
= (const char **)malloc((atf_list_size(l
) + 1) * sizeof(const char *));
585 err
= atf_no_memory_error();
588 atf_list_citer_t liter
;
591 atf_list_for_each_c(liter
, l
) {
592 *aiter
= (const char *)atf_list_citer_data(liter
);
597 err
= atf_no_error();
605 const atf_fs_path_t
*m_prog
;
606 const char *const *m_argv
;
613 struct exec_args
*ea
= v
;
615 atf_reset_exit_checks();
616 const int ret
= const_execvp(atf_fs_path_cstring(ea
->m_prog
), ea
->m_argv
);
617 const int errnocopy
= errno
;
619 fprintf(stderr
, "exec(%s) failed: %s\n",
620 atf_fs_path_cstring(ea
->m_prog
), strerror(errnocopy
));
625 atf_process_exec_array(atf_process_status_t
*s
,
626 const atf_fs_path_t
*prog
,
627 const char *const *argv
,
628 const atf_process_stream_t
*outsb
,
629 const atf_process_stream_t
*errsb
)
632 atf_process_child_t c
;
633 struct exec_args ea
= { prog
, argv
};
636 atf_process_stream_type(outsb
) != atf_process_stream_type_capture
);
638 atf_process_stream_type(errsb
) != atf_process_stream_type_capture
);
640 err
= atf_process_fork(&c
, do_exec
, outsb
, errsb
, &ea
);
641 if (atf_is_error(err
))
645 err
= atf_process_child_wait(&c
, s
);
646 if (atf_is_error(err
)) {
647 INV(atf_error_is(err
, "libc") && atf_libc_error_code(err
) == EINTR
);
657 atf_process_exec_list(atf_process_status_t
*s
,
658 const atf_fs_path_t
*prog
,
659 const atf_list_t
*argv
,
660 const atf_process_stream_t
*outsb
,
661 const atf_process_stream_t
*errsb
)
667 atf_process_stream_type(outsb
) != atf_process_stream_type_capture
);
669 atf_process_stream_type(errsb
) != atf_process_stream_type_capture
);
671 argv2
= NULL
; /* Silence GCC warning. */
672 err
= list_to_array(argv
, &argv2
);
673 if (atf_is_error(err
))
676 err
= atf_process_exec_array(s
, prog
, argv2
, outsb
, errsb
);