No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / atf / dist / atf-c / process.c
blob009e5492423fbcd0b4db8686acafdee47223a30f
1 /*
2 * Automated Testing Framework (atf)
4 * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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>
31 #include <sys/wait.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.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;
56 bool m_pipefds_ok;
57 int m_pipefds[2];
59 typedef struct stream_prepare stream_prepare_t;
61 static
62 atf_error_t
63 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
65 atf_error_t err;
67 const int type = atf_process_stream_type(sb);
69 sp->m_sb = 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");
75 else {
76 err = atf_no_error();
77 sp->m_pipefds_ok = true;
79 } else
80 err = atf_no_error();
82 return err;
85 static
86 void
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;
105 static
106 bool
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);
116 atf_error_t
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();
127 atf_error_t
128 atf_process_stream_init_connect(atf_process_stream_t *sb,
129 const int src_fd, const int tgt_fd)
131 PRE(src_fd >= 0);
132 PRE(tgt_fd >= 0);
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();
145 atf_error_t
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();
156 atf_error_t
157 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
158 const int fd)
160 atf_object_init(&sb->m_object);
162 sb->m_type = atf_process_stream_type_redirect_fd;
163 sb->m_fd = fd;
165 POST(stream_is_valid(sb));
166 return atf_no_error();
169 atf_error_t
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;
176 sb->m_path = path;
178 POST(stream_is_valid(sb));
179 return atf_no_error();
182 void
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));
195 return sb->m_type;
198 /* ---------------------------------------------------------------------
199 * The "atf_process_status" type.
200 * --------------------------------------------------------------------- */
202 atf_error_t
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();
212 void
213 atf_process_status_fini(atf_process_status_t *s)
215 atf_object_fini(&s->m_object);
218 bool
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);
233 bool
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);
248 bool
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);
255 #else
256 return false;
257 #endif
260 /* ---------------------------------------------------------------------
261 * The "atf_process_child" type.
262 * --------------------------------------------------------------------- */
264 static
265 atf_error_t
266 atf_process_child_init(atf_process_child_t *c)
268 atf_object_init(&c->m_object);
270 c->m_pid = 0;
271 c->m_stdout = -1;
272 c->m_stderr = -1;
274 return atf_no_error();
277 static
278 void
279 atf_process_child_fini(atf_process_child_t *c)
281 atf_object_fini(&c->m_object);
284 atf_error_t
285 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
287 atf_error_t err;
288 int status;
290 if (waitpid(c->m_pid, &status, 0) == -1)
291 err = atf_libc_error(errno, "Failed waiting for process %d",
292 c->m_pid);
293 else {
294 atf_process_child_fini(c);
295 err = atf_process_status_init(s, status);
298 return err;
301 pid_t
302 atf_process_child_pid(const atf_process_child_t *c)
304 return c->m_pid;
308 atf_process_child_stdout(atf_process_child_t *c)
310 PRE(c->m_stdout != -1);
311 return c->m_stdout;
315 atf_process_child_stderr(atf_process_child_t *c)
317 PRE(c->m_stderr != -1);
318 return c->m_stderr;
321 /* ---------------------------------------------------------------------
322 * Free functions.
323 * --------------------------------------------------------------------- */
325 static
326 atf_error_t
327 safe_dup(const int oldfd, const int newfd)
329 atf_error_t err;
331 if (oldfd != newfd) {
332 if (dup2(oldfd, newfd) == -1) {
333 err = atf_libc_error(errno, "Could not allocate file descriptor");
334 } else {
335 close(oldfd);
336 err = atf_no_error();
338 } else
339 err = atf_no_error();
341 return err;
344 static
345 atf_error_t
346 child_connect(const stream_prepare_t *sp, int procfd)
348 atf_error_t err;
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);
358 else
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);
367 if (aux == -1)
368 err = atf_libc_error(errno, "Could not create %s",
369 atf_fs_path_cstring(sp->m_sb->m_path));
370 else {
371 err = safe_dup(aux, procfd);
372 if (atf_is_error(err))
373 close(aux);
375 } else {
376 UNREACHABLE;
377 err = atf_no_error();
380 return err;
383 static
384 void
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) {
393 /* Do nothing. */
394 } else if (type == atf_process_stream_type_inherit) {
395 /* Do nothing. */
396 } else if (type == atf_process_stream_type_redirect_fd) {
397 /* Do nothing. */
398 } else if (type == atf_process_stream_type_redirect_path) {
399 /* Do nothing. */
400 } else {
401 UNREACHABLE;
405 static
406 atf_error_t
407 do_parent(atf_process_child_t *c,
408 const pid_t pid,
409 const stream_prepare_t *outsp,
410 const stream_prepare_t *errsp)
412 atf_error_t err;
414 err = atf_process_child_init(c);
415 if (atf_is_error(err))
416 goto out;
418 c->m_pid = pid;
420 parent_connect(outsp, &c->m_stdout);
421 parent_connect(errsp, &c->m_stderr);
423 out:
424 return err;
427 static
428 void
429 do_child(void (*)(void *),
430 void *,
431 const stream_prepare_t *,
432 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
434 static
435 void
436 do_child(void (*start)(void *),
437 void *v,
438 const stream_prepare_t *outsp,
439 const stream_prepare_t *errsp)
441 atf_error_t err;
443 atf_reset_exit_checks();
444 err = child_connect(outsp, STDOUT_FILENO);
445 if (atf_is_error(err))
446 goto out;
448 err = child_connect(errsp, STDERR_FILENO);
449 if (atf_is_error(err))
450 goto out;
452 start(v);
453 UNREACHABLE;
455 out:
456 if (atf_is_error(err)) {
457 char buf[1024];
459 atf_error_format(err, buf, sizeof(buf));
460 fprintf(stderr, "Unhandled error: %s\n", buf);
461 atf_error_free(err);
463 exit(EXIT_FAILURE);
464 } else
465 exit(EXIT_SUCCESS);
468 static
469 atf_error_t
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,
474 void *v)
476 atf_error_t err;
477 stream_prepare_t outsp;
478 stream_prepare_t errsp;
479 pid_t pid;
481 err = stream_prepare_init(&outsp, outsb);
482 if (atf_is_error(err))
483 goto out;
485 err = stream_prepare_init(&errsp, errsb);
486 if (atf_is_error(err))
487 goto err_outpipe;
489 pid = fork();
490 if (pid == -1) {
491 err = atf_libc_error(errno, "Failed to fork");
492 goto err_errpipe;
495 if (pid == 0) {
496 do_child(start, v, &outsp, &errsp);
497 UNREACHABLE;
498 abort();
499 err = atf_no_error();
500 } else {
501 err = do_parent(c, pid, &outsp, &errsp);
502 if (atf_is_error(err))
503 goto err_errpipe;
506 goto out;
508 err_errpipe:
509 stream_prepare_fini(&errsp);
510 err_outpipe:
511 stream_prepare_fini(&outsp);
513 out:
514 return err;
517 static
518 atf_error_t
519 init_stream_w_default(const atf_process_stream_t *usersb,
520 atf_process_stream_t *inheritsb,
521 const atf_process_stream_t **realsb)
523 atf_error_t err;
525 if (usersb == NULL) {
526 err = atf_process_stream_init_inherit(inheritsb);
527 if (!atf_is_error(err))
528 *realsb = inheritsb;
529 } else {
530 err = atf_no_error();
531 *realsb = usersb;
534 return err;
537 atf_error_t
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,
542 void *v)
544 atf_error_t err;
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))
550 goto out;
552 err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
553 if (atf_is_error(err))
554 goto out_out;
556 err = fork_with_streams(c, start, real_outsb, real_errsb, v);
558 if (errsb == NULL)
559 atf_process_stream_fini(&inherit_errsb);
560 out_out:
561 if (outsb == NULL)
562 atf_process_stream_fini(&inherit_outsb);
563 out:
564 return err;
567 static
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));
573 #undef UNCONST
576 static
577 atf_error_t
578 list_to_array(const atf_list_t *l, const char ***ap)
580 atf_error_t err;
581 const char **a;
583 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
584 if (a == NULL)
585 err = atf_no_memory_error();
586 else {
587 const char **aiter;
588 atf_list_citer_t liter;
590 aiter = a;
591 atf_list_for_each_c(liter, l) {
592 *aiter = (const char *)atf_list_citer_data(liter);
593 aiter++;
595 *aiter = NULL;
597 err = atf_no_error();
598 *ap = a;
601 return err;
604 struct exec_args {
605 const atf_fs_path_t *m_prog;
606 const char *const *m_argv;
609 static
610 void
611 do_exec(void *v)
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;
618 INV(ret == -1);
619 fprintf(stderr, "exec(%s) failed: %s\n",
620 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
621 exit(EXIT_FAILURE);
624 atf_error_t
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)
631 atf_error_t err;
632 atf_process_child_t c;
633 struct exec_args ea = { prog, argv };
635 PRE(outsb == NULL ||
636 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
637 PRE(errsb == NULL ||
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))
642 goto out;
644 again:
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);
648 atf_error_free(err);
649 goto again;
652 out:
653 return err;
656 atf_error_t
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)
663 atf_error_t err;
664 const char **argv2;
666 PRE(outsb == NULL ||
667 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
668 PRE(errsb == NULL ||
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))
674 goto out;
676 err = atf_process_exec_array(s, prog, argv2, outsb, errsb);
678 free(argv2);
679 out:
680 return err;