tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / atf / dist / atf-c / detail / process.c
bloba16d0204037a57cf3941623e8defc5fe19689a9b
1 /*
2 * Automated Testing Framework (atf)
4 * Copyright (c) 2007 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"
43 #include "process.h"
44 #include "sanity.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;
57 bool m_pipefds_ok;
58 int m_pipefds[2];
60 typedef struct stream_prepare stream_prepare_t;
62 static
63 atf_error_t
64 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
66 atf_error_t err;
68 const int type = atf_process_stream_type(sb);
70 sp->m_sb = 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");
76 else {
77 err = atf_no_error();
78 sp->m_pipefds_ok = true;
80 } else
81 err = atf_no_error();
83 return err;
86 static
87 void
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)
107 static
108 bool
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) */
119 atf_error_t
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();
128 atf_error_t
129 atf_process_stream_init_connect(atf_process_stream_t *sb,
130 const int src_fd, const int tgt_fd)
132 PRE(src_fd >= 0);
133 PRE(tgt_fd >= 0);
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();
144 atf_error_t
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();
153 atf_error_t
154 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
155 const int fd)
157 sb->m_type = atf_process_stream_type_redirect_fd;
158 sb->m_fd = fd;
160 POST(stream_is_valid(sb));
161 return atf_no_error();
164 atf_error_t
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;
169 sb->m_path = path;
171 POST(stream_is_valid(sb));
172 return atf_no_error();
175 void
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));
186 return sb->m_type;
189 /* ---------------------------------------------------------------------
190 * The "atf_process_status" type.
191 * --------------------------------------------------------------------- */
193 atf_error_t
194 atf_process_status_init(atf_process_status_t *s, int status)
196 s->m_status = status;
198 return atf_no_error();
201 void
202 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
206 bool
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);
221 bool
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);
236 bool
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);
243 #else
244 return false;
245 #endif
248 /* ---------------------------------------------------------------------
249 * The "atf_process_child" type.
250 * --------------------------------------------------------------------- */
252 static
253 atf_error_t
254 atf_process_child_init(atf_process_child_t *c)
256 c->m_pid = 0;
257 c->m_stdout = -1;
258 c->m_stderr = -1;
260 return atf_no_error();
263 static
264 void
265 atf_process_child_fini(atf_process_child_t *c)
267 if (c->m_stdout != -1)
268 close(c->m_stdout);
269 if (c->m_stderr != -1)
270 close(c->m_stderr);
273 atf_error_t
274 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
276 atf_error_t err;
277 int status;
279 if (waitpid(c->m_pid, &status, 0) == -1)
280 err = atf_libc_error(errno, "Failed waiting for process %d",
281 c->m_pid);
282 else {
283 atf_process_child_fini(c);
284 err = atf_process_status_init(s, status);
287 return err;
290 pid_t
291 atf_process_child_pid(const atf_process_child_t *c)
293 return c->m_pid;
297 atf_process_child_stdout(atf_process_child_t *c)
299 PRE(c->m_stdout != -1);
300 return c->m_stdout;
304 atf_process_child_stderr(atf_process_child_t *c)
306 PRE(c->m_stderr != -1);
307 return c->m_stderr;
310 /* ---------------------------------------------------------------------
311 * Free functions.
312 * --------------------------------------------------------------------- */
314 static
315 atf_error_t
316 safe_dup(const int oldfd, const int newfd)
318 atf_error_t err;
320 if (oldfd != newfd) {
321 if (dup2(oldfd, newfd) == -1) {
322 err = atf_libc_error(errno, "Could not allocate file descriptor");
323 } else {
324 close(oldfd);
325 err = atf_no_error();
327 } else
328 err = atf_no_error();
330 return err;
333 static
334 atf_error_t
335 child_connect(const stream_prepare_t *sp, int procfd)
337 atf_error_t err;
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);
347 else
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);
356 if (aux == -1)
357 err = atf_libc_error(errno, "Could not create %s",
358 atf_fs_path_cstring(sp->m_sb->m_path));
359 else {
360 err = safe_dup(aux, procfd);
361 if (atf_is_error(err))
362 close(aux);
364 } else {
365 UNREACHABLE;
366 err = atf_no_error();
369 return err;
372 static
373 void
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) {
382 /* Do nothing. */
383 } else if (type == atf_process_stream_type_inherit) {
384 /* Do nothing. */
385 } else if (type == atf_process_stream_type_redirect_fd) {
386 /* Do nothing. */
387 } else if (type == atf_process_stream_type_redirect_path) {
388 /* Do nothing. */
389 } else {
390 UNREACHABLE;
394 static
395 atf_error_t
396 do_parent(atf_process_child_t *c,
397 const pid_t pid,
398 const stream_prepare_t *outsp,
399 const stream_prepare_t *errsp)
401 atf_error_t err;
403 err = atf_process_child_init(c);
404 if (atf_is_error(err))
405 goto out;
407 c->m_pid = pid;
409 parent_connect(outsp, &c->m_stdout);
410 parent_connect(errsp, &c->m_stderr);
412 out:
413 return err;
416 static
417 void
418 do_child(void (*)(void *),
419 void *,
420 const stream_prepare_t *,
421 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
423 static
424 void
425 do_child(void (*start)(void *),
426 void *v,
427 const stream_prepare_t *outsp,
428 const stream_prepare_t *errsp)
430 atf_error_t err;
432 err = child_connect(outsp, STDOUT_FILENO);
433 if (atf_is_error(err))
434 goto out;
436 err = child_connect(errsp, STDERR_FILENO);
437 if (atf_is_error(err))
438 goto out;
440 start(v);
441 UNREACHABLE;
443 out:
444 if (atf_is_error(err)) {
445 char buf[1024];
447 atf_error_format(err, buf, sizeof(buf));
448 fprintf(stderr, "Unhandled error: %s\n", buf);
449 atf_error_free(err);
451 exit(EXIT_FAILURE);
452 } else
453 exit(EXIT_SUCCESS);
456 static
457 atf_error_t
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,
462 void *v)
464 atf_error_t err;
465 stream_prepare_t outsp;
466 stream_prepare_t errsp;
467 pid_t pid;
469 err = stream_prepare_init(&outsp, outsb);
470 if (atf_is_error(err))
471 goto out;
473 err = stream_prepare_init(&errsp, errsb);
474 if (atf_is_error(err))
475 goto err_outpipe;
477 pid = fork();
478 if (pid == -1) {
479 err = atf_libc_error(errno, "Failed to fork");
480 goto err_errpipe;
483 if (pid == 0) {
484 do_child(start, v, &outsp, &errsp);
485 UNREACHABLE;
486 abort();
487 err = atf_no_error();
488 } else {
489 err = do_parent(c, pid, &outsp, &errsp);
490 if (atf_is_error(err))
491 goto err_errpipe;
494 goto out;
496 err_errpipe:
497 stream_prepare_fini(&errsp);
498 err_outpipe:
499 stream_prepare_fini(&outsp);
501 out:
502 return err;
505 static
506 atf_error_t
507 init_stream_w_default(const atf_process_stream_t *usersb,
508 atf_process_stream_t *inheritsb,
509 const atf_process_stream_t **realsb)
511 atf_error_t err;
513 if (usersb == NULL) {
514 err = atf_process_stream_init_inherit(inheritsb);
515 if (!atf_is_error(err))
516 *realsb = inheritsb;
517 } else {
518 err = atf_no_error();
519 *realsb = usersb;
522 return err;
525 atf_error_t
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,
530 void *v)
532 atf_error_t err;
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))
539 goto out;
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))
544 goto out_out;
546 err = fork_with_streams(c, start, real_outsb, real_errsb, v);
548 if (errsb == NULL)
549 atf_process_stream_fini(&inherit_errsb);
550 out_out:
551 if (outsb == NULL)
552 atf_process_stream_fini(&inherit_outsb);
553 out:
554 return err;
557 static
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));
563 #undef UNCONST
566 static
567 atf_error_t
568 list_to_array(const atf_list_t *l, const char ***ap)
570 atf_error_t err;
571 const char **a;
573 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
574 if (a == NULL)
575 err = atf_no_memory_error();
576 else {
577 const char **aiter;
578 atf_list_citer_t liter;
580 aiter = a;
581 atf_list_for_each_c(liter, l) {
582 *aiter = (const char *)atf_list_citer_data(liter);
583 aiter++;
585 *aiter = NULL;
587 err = atf_no_error();
588 *ap = a;
591 return err;
594 struct exec_args {
595 const atf_fs_path_t *m_prog;
596 const char *const *m_argv;
597 void (*m_prehook)(void);
600 static
601 void
602 do_exec(void *v)
604 struct exec_args *ea = v;
606 if (ea->m_prehook != NULL)
607 ea->m_prehook();
609 #if defined(__minix) && !defined(NDEBUG)
610 const int ret =
611 #endif /* defined(__minix) && !defined(NDEBUG) */
612 const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
613 const int errnocopy = errno;
614 INV(ret == -1);
615 fprintf(stderr, "exec(%s) failed: %s\n",
616 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
617 exit(EXIT_FAILURE);
620 atf_error_t
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))
628 atf_error_t err;
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 };
632 PRE(outsb == NULL ||
633 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
634 PRE(errsb == NULL ||
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))
639 goto out;
641 again:
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);
645 atf_error_free(err);
646 goto again;
649 out:
650 return err;
653 atf_error_t
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))
661 atf_error_t err;
662 const char **argv2;
664 PRE(outsb == NULL ||
665 atf_process_stream_type(outsb) != atf_process_stream_type_capture);
666 PRE(errsb == NULL ||
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))
672 goto out;
674 err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
676 free(argv2);
677 out:
678 return err;