Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / atf / dist / atf-c / tc.c
blob397fd45e583a05a3de08fde99723d8712e8b08ad
1 /*
2 * Automated Testing Framework (atf)
4 * Copyright (c) 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/time.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <limits.h>
38 #include <stdarg.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
45 #include "atf-c/config.h"
46 #include "atf-c/defs.h"
47 #include "atf-c/env.h"
48 #include "atf-c/error.h"
49 #include "atf-c/fs.h"
50 #include "atf-c/process.h"
51 #include "atf-c/sanity.h"
52 #include "atf-c/signals.h"
53 #include "atf-c/tc.h"
54 #include "atf-c/tcr.h"
55 #include "atf-c/text.h"
56 #include "atf-c/user.h"
58 /* ---------------------------------------------------------------------
59 * Auxiliary types and functions.
60 * --------------------------------------------------------------------- */
62 struct child_data {
63 const atf_tc_t *tc;
64 const atf_fs_path_t *workdir;
67 /* Parent-only stuff. */
68 struct timeout_data;
69 static atf_error_t body_parent(const atf_tc_t *, const atf_fs_path_t *,
70 atf_process_child_t *, atf_tcr_t *);
71 static atf_error_t cleanup_parent(const atf_tc_t *, atf_process_child_t *);
72 static atf_error_t fork_body(const atf_tc_t *, int, int,
73 const atf_fs_path_t *, atf_tcr_t *);
74 static atf_error_t fork_cleanup(const atf_tc_t *, int, int,
75 const atf_fs_path_t *);
76 static atf_error_t get_tc_result(const atf_fs_path_t *, atf_tcr_t *);
77 static atf_error_t program_timeout(const atf_process_child_t *,
78 const atf_tc_t *, struct timeout_data *);
79 static void unprogram_timeout(struct timeout_data *);
80 static void sigalrm_handler(int);
82 /* Child-only stuff. */
83 static void body_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
84 static atf_error_t check_arch(const char *, void *);
85 static atf_error_t check_config(const char *, void *);
86 static atf_error_t check_machine(const char *, void *);
87 static atf_error_t check_prog(const char *, void *);
88 static atf_error_t check_prog_in_dir(const char *, void *);
89 static atf_error_t check_requirements(const atf_tc_t *);
90 static void cleanup_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
91 static void fail_internal(const char *, int, const char *, const char *,
92 const char *, va_list,
93 void (*)(atf_dynstr_t *),
94 void (*)(const char *, ...));
95 static void fatal_atf_error(const char *, atf_error_t)
96 ATF_DEFS_ATTRIBUTE_NORETURN;
97 static void fatal_libc_error(const char *, int)
98 ATF_DEFS_ATTRIBUTE_NORETURN;
99 static atf_error_t prepare_child(const struct child_data *);
100 static void tc_fail(atf_dynstr_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
101 static void tc_fail_nonfatal(atf_dynstr_t *);
102 static void write_tcr(const atf_tcr_t *);
104 /* ---------------------------------------------------------------------
105 * The "atf_tc" type.
106 * --------------------------------------------------------------------- */
109 * Constructors/destructors.
112 atf_error_t
113 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
114 atf_tc_body_t body, atf_tc_cleanup_t cleanup,
115 const atf_map_t *config)
117 atf_error_t err;
119 atf_object_init(&tc->m_object);
121 tc->m_ident = ident;
122 tc->m_head = head;
123 tc->m_body = body;
124 tc->m_cleanup = cleanup;
125 tc->m_config = config;
127 err = atf_map_init(&tc->m_vars);
128 if (atf_is_error(err))
129 goto err_object;
131 err = atf_tc_set_md_var(tc, "ident", ident);
132 if (atf_is_error(err))
133 goto err_map;
135 err = atf_tc_set_md_var(tc, "timeout", "300");
136 if (atf_is_error(err))
137 goto err_map;
139 /* XXX Should the head be able to return error codes? */
140 tc->m_head(tc);
142 if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0)
143 atf_tc_fail("Test case head modified the read-only 'ident' "
144 "property");
146 INV(!atf_is_error(err));
147 return err;
149 err_map:
150 atf_map_fini(&tc->m_vars);
151 err_object:
152 atf_object_fini(&tc->m_object);
154 return err;
157 atf_error_t
158 atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
159 const atf_map_t *config)
161 return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
162 pack->m_cleanup, config);
165 void
166 atf_tc_fini(atf_tc_t *tc)
168 atf_map_fini(&tc->m_vars);
170 atf_object_fini(&tc->m_object);
174 * Getters.
177 const char *
178 atf_tc_get_ident(const atf_tc_t *tc)
180 return tc->m_ident;
183 const char *
184 atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
186 const char *val;
187 atf_map_citer_t iter;
189 PRE(atf_tc_has_config_var(tc, name));
190 iter = atf_map_find_c(tc->m_config, name);
191 val = atf_map_citer_data(iter);
192 INV(val != NULL);
194 return val;
197 const char *
198 atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
199 const char *defval)
201 const char *val;
203 if (!atf_tc_has_config_var(tc, name))
204 val = defval;
205 else
206 val = atf_tc_get_config_var(tc, name);
208 return val;
211 const char *
212 atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
214 const char *val;
215 atf_map_citer_t iter;
217 PRE(atf_tc_has_md_var(tc, name));
218 iter = atf_map_find_c(&tc->m_vars, name);
219 val = atf_map_citer_data(iter);
220 INV(val != NULL);
222 return val;
225 bool
226 atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
228 bool found;
229 atf_map_citer_t end, iter;
231 if (tc->m_config == NULL)
232 found = false;
233 else {
234 iter = atf_map_find_c(tc->m_config, name);
235 end = atf_map_end_c(tc->m_config);
236 found = !atf_equal_map_citer_map_citer(iter, end);
239 return found;
242 bool
243 atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
245 atf_map_citer_t end, iter;
247 iter = atf_map_find_c(&tc->m_vars, name);
248 end = atf_map_end_c(&tc->m_vars);
249 return !atf_equal_map_citer_map_citer(iter, end);
253 * Modifiers.
256 atf_error_t
257 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
259 atf_error_t err;
260 char *value;
261 va_list ap;
263 va_start(ap, fmt);
264 err = atf_text_format_ap(&value, fmt, ap);
265 va_end(ap);
267 if (!atf_is_error(err))
268 err = atf_map_insert(&tc->m_vars, name, value, true);
269 else
270 free(value);
272 return err;
275 /* ---------------------------------------------------------------------
276 * Free functions.
277 * --------------------------------------------------------------------- */
279 atf_error_t
280 atf_tc_run(const atf_tc_t *tc, atf_tcr_t *tcr, int fdout, int fderr,
281 const atf_fs_path_t *workdirbase)
283 atf_error_t err, cleanuperr;
284 atf_fs_path_t workdir;
286 err = atf_fs_path_copy(&workdir, workdirbase);
287 if (atf_is_error(err))
288 goto out;
290 err = atf_fs_path_append_fmt(&workdir, "atf.XXXXXX");
291 if (atf_is_error(err))
292 goto out_workdir;
294 err = atf_fs_mkdtemp(&workdir);
295 if (atf_is_error(err))
296 goto out_workdir;
298 err = fork_body(tc, fdout, fderr, &workdir, tcr);
299 cleanuperr = fork_cleanup(tc, fdout, fderr, &workdir);
300 if (!atf_is_error(cleanuperr))
301 (void)atf_fs_cleanup(&workdir);
302 if (!atf_is_error(err))
303 err = cleanuperr;
304 else if (atf_is_error(cleanuperr))
305 atf_error_free(cleanuperr);
307 out_workdir:
308 atf_fs_path_fini(&workdir);
309 out:
310 return err;
314 * Parent-only stuff.
317 static bool sigalrm_killed = false;
318 static pid_t sigalrm_pid = -1;
320 static
321 void
322 sigalrm_handler(int signo)
324 INV(signo == SIGALRM);
326 if (sigalrm_pid != -1) {
327 killpg(sigalrm_pid, SIGTERM);
328 sigalrm_killed = true;
332 struct timeout_data {
333 bool m_programmed;
334 atf_signal_programmer_t m_sigalrm;
337 static
338 atf_error_t
339 program_timeout(const atf_process_child_t *child, const atf_tc_t *tc,
340 struct timeout_data *td)
342 atf_error_t err;
343 long timeout;
345 err = atf_text_to_long(atf_tc_get_md_var(tc, "timeout"), &timeout);
346 if (atf_is_error(err))
347 goto out;
349 if (timeout != 0) {
350 sigalrm_pid = atf_process_child_pid(child);
351 sigalrm_killed = false;
353 err = atf_signal_programmer_init(&td->m_sigalrm, SIGALRM,
354 sigalrm_handler);
355 if (atf_is_error(err))
356 goto out;
358 struct itimerval itv;
359 timerclear(&itv.it_interval);
360 timerclear(&itv.it_value);
361 itv.it_value.tv_sec = timeout;
362 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
363 atf_signal_programmer_fini(&td->m_sigalrm);
364 err = atf_libc_error(errno, "Failed to program timeout "
365 "with %ld seconds", timeout);
368 td->m_programmed = !atf_is_error(err);
369 } else
370 td->m_programmed = false;
372 out:
373 return err;
376 static
377 void
378 unprogram_timeout(struct timeout_data *td)
380 if (td->m_programmed) {
381 atf_signal_programmer_fini(&td->m_sigalrm);
382 sigalrm_pid = -1;
383 sigalrm_killed = false;
387 static
388 atf_error_t
389 body_parent(const atf_tc_t *tc, const atf_fs_path_t *workdir,
390 atf_process_child_t *child, atf_tcr_t *tcr)
392 atf_error_t err;
393 atf_process_status_t status;
394 struct timeout_data td;
396 err = program_timeout(child, tc, &td);
397 if (atf_is_error(err)) {
398 char buf[4096];
400 atf_error_format(err, buf, sizeof(buf));
401 fprintf(stderr, "Error programming test case's timeout: %s", buf);
402 atf_error_free(err);
403 killpg(atf_process_child_pid(child), SIGKILL);
406 again:
407 err = atf_process_child_wait(child, &status);
408 if (atf_is_error(err)) {
409 if (atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR) {
410 atf_error_free(err);
411 goto again;
412 } else {
413 /* Propagate err */
415 } else {
416 if (sigalrm_killed)
417 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
418 "Test case timed out after %s "
419 "seconds",
420 atf_tc_get_md_var(tc, "timeout"));
421 else {
422 if (atf_process_status_exited(&status)) {
423 const int exitstatus = atf_process_status_exitstatus(&status);
424 if (exitstatus == EXIT_SUCCESS)
425 err = get_tc_result(workdir, tcr);
426 else
427 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
428 "Test case exited with "
429 "status %d", exitstatus);
430 } else if (atf_process_status_signaled(&status)) {
431 const int sig = atf_process_status_termsig(&status);
432 const bool wcore = atf_process_status_coredump(&status);
433 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
434 "Test case was signaled by "
435 "signal %d%s", sig,
436 wcore ? " (core dumped)" : "");
437 } else {
438 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
439 "Test case exited due to an "
440 "unexpected condition");
444 atf_process_status_fini(&status);
447 unprogram_timeout(&td);
449 return err;
452 static
453 atf_error_t
454 cleanup_parent(const atf_tc_t *tc, atf_process_child_t *child)
456 atf_error_t err;
457 atf_process_status_t status;
459 err = atf_process_child_wait(child, &status);
460 if (atf_is_error(err))
461 goto out;
463 if (!atf_process_status_exited(&status) ||
464 atf_process_status_exitstatus(&status) != EXIT_SUCCESS) {
465 /* XXX Not really a libc error. */
466 err = atf_libc_error(EINVAL, "Child process did not exit cleanly");
467 } else
468 err = atf_no_error();
470 atf_process_status_fini(&status);
471 out:
472 return err;
475 static
476 atf_error_t
477 fork_body(const atf_tc_t *tc, int fdout, int fderr,
478 const atf_fs_path_t *workdir, atf_tcr_t *tcr)
480 atf_error_t err;
481 atf_process_stream_t outsb, errsb;
482 atf_process_child_t child;
483 struct child_data data = {
485 workdir,
488 err = atf_process_stream_init_redirect_fd(&outsb, fdout);
489 if (atf_is_error(err))
490 goto out;
492 err = atf_process_stream_init_redirect_fd(&errsb, fderr);
493 if (atf_is_error(err))
494 goto out_outsb;
496 err = atf_process_fork(&child, body_child, &outsb, &errsb, &data);
497 if (atf_is_error(err))
498 goto out_errsb;
500 err = body_parent(tc, workdir, &child, tcr);
502 out_errsb:
503 atf_process_stream_fini(&errsb);
504 out_outsb:
505 atf_process_stream_fini(&outsb);
506 out:
507 return err;
510 static
511 atf_error_t
512 fork_cleanup(const atf_tc_t *tc, int fdout, int fderr,
513 const atf_fs_path_t *workdir)
515 atf_error_t err;
517 if (tc->m_cleanup == NULL)
518 err = atf_no_error();
519 else {
520 atf_process_stream_t outsb, errsb;
521 atf_process_child_t child;
522 struct child_data data = {
524 workdir,
527 err = atf_process_stream_init_redirect_fd(&outsb, fdout);
528 if (atf_is_error(err))
529 goto out;
531 err = atf_process_stream_init_redirect_fd(&errsb, fderr);
532 if (atf_is_error(err))
533 goto out_outsb;
535 err = atf_process_fork(&child, cleanup_child, &outsb, &errsb, &data);
536 if (atf_is_error(err))
537 goto out_errsb;
539 err = cleanup_parent(tc, &child);
541 out_errsb:
542 atf_process_stream_fini(&errsb);
543 out_outsb:
544 atf_process_stream_fini(&outsb);
547 out:
548 return err;
551 static
552 atf_error_t
553 get_tc_result(const atf_fs_path_t *workdir, atf_tcr_t *tcr)
555 atf_error_t err;
556 int fd;
557 atf_fs_path_t tcrfile;
559 err = atf_fs_path_copy(&tcrfile, workdir);
560 if (atf_is_error(err))
561 goto out;
563 err = atf_fs_path_append_fmt(&tcrfile, "tc-result");
564 if (atf_is_error(err))
565 goto out_tcrfile;
567 fd = open(atf_fs_path_cstring(&tcrfile), O_RDONLY);
568 if (fd == -1) {
569 err = atf_libc_error(errno, "Cannot retrieve test case result");
570 goto out_tcrfile;
573 err = atf_tcr_deserialize(tcr, fd);
575 close(fd);
576 out_tcrfile:
577 atf_fs_path_fini(&tcrfile);
578 out:
579 return err;
583 * Child-only stuff.
586 static const atf_tc_t *current_tc = NULL;
587 static const atf_fs_path_t *current_workdir = NULL;
588 static size_t current_tc_fail_count = 0;
590 static
591 atf_error_t
592 prepare_child(const struct child_data *cd)
594 atf_error_t err;
595 int i, ret;
597 current_tc = cd->tc;
598 current_workdir = cd->workdir;
599 current_tc_fail_count = 0;
601 ret = setpgid(getpid(), 0);
602 INV(ret != -1);
604 umask(S_IWGRP | S_IWOTH);
606 for (i = 1; i <= atf_signals_last_signo; i++)
607 atf_signal_reset(i);
609 err = atf_env_set("HOME", atf_fs_path_cstring(cd->workdir));
610 if (atf_is_error(err))
611 goto out;
613 err = atf_env_unset("LANG");
614 if (atf_is_error(err))
615 goto out;
617 err = atf_env_unset("LC_ALL");
618 if (atf_is_error(err))
619 goto out;
621 err = atf_env_unset("LC_COLLATE");
622 if (atf_is_error(err))
623 goto out;
625 err = atf_env_unset("LC_CTYPE");
626 if (atf_is_error(err))
627 goto out;
629 err = atf_env_unset("LC_MESSAGES");
630 if (atf_is_error(err))
631 goto out;
633 err = atf_env_unset("LC_MONETARY");
634 if (atf_is_error(err))
635 goto out;
637 err = atf_env_unset("LC_NUMERIC");
638 if (atf_is_error(err))
639 goto out;
641 err = atf_env_unset("LC_TIME");
642 if (atf_is_error(err))
643 goto out;
645 err = atf_env_unset("TZ");
646 if (atf_is_error(err))
647 goto out;
649 if (chdir(atf_fs_path_cstring(cd->workdir)) == -1) {
650 err = atf_libc_error(errno, "Cannot enter work directory '%s'",
651 atf_fs_path_cstring(cd->workdir));
652 goto out;
655 err = atf_no_error();
657 out:
658 return err;
661 static
662 void
663 body_child(void *v)
665 const struct child_data *cd = v;
666 atf_error_t err;
668 atf_reset_exit_checks();
670 err = prepare_child(cd);
671 if (atf_is_error(err))
672 goto print_err;
673 err = check_requirements(cd->tc);
674 if (atf_is_error(err))
675 goto print_err;
677 cd->tc->m_body(cd->tc);
679 if (current_tc_fail_count == 0)
680 atf_tc_pass();
681 else
682 atf_tc_fail("%d checks failed; see output for more details",
683 current_tc_fail_count);
685 UNREACHABLE;
687 print_err:
688 INV(atf_is_error(err));
690 char buf[4096];
692 atf_error_format(err, buf, sizeof(buf));
693 atf_error_free(err);
695 atf_tc_fail("Error while preparing child process: %s", buf);
698 UNREACHABLE;
701 static
702 atf_error_t
703 check_arch(const char *arch, void *data)
705 bool *found = data;
707 if (strcmp(arch, atf_config_get("atf_arch")) == 0)
708 *found = true;
710 return atf_no_error();
713 static
714 atf_error_t
715 check_config(const char *var, void *data)
717 if (!atf_tc_has_config_var(current_tc, var))
718 atf_tc_skip("Required configuration variable %s not defined", var);
720 return atf_no_error();
723 static
724 atf_error_t
725 check_machine(const char *machine, void *data)
727 bool *found = data;
729 if (strcmp(machine, atf_config_get("atf_machine")) == 0)
730 *found = true;
732 return atf_no_error();
735 struct prog_found_pair {
736 const char *prog;
737 bool found;
740 static
741 atf_error_t
742 check_prog(const char *prog, void *data)
744 atf_error_t err;
745 atf_fs_path_t p;
747 err = atf_fs_path_init_fmt(&p, "%s", prog);
748 if (atf_is_error(err))
749 goto out;
751 if (atf_fs_path_is_absolute(&p)) {
752 err = atf_fs_eaccess(&p, atf_fs_access_x);
753 if (atf_is_error(err)) {
754 atf_error_free(err);
755 atf_fs_path_fini(&p);
756 atf_tc_skip("The required program %s could not be found", prog);
758 } else {
759 const char *path = atf_env_get("PATH");
760 struct prog_found_pair pf;
761 atf_fs_path_t bp;
763 err = atf_fs_path_branch_path(&p, &bp);
764 if (atf_is_error(err))
765 goto out_p;
767 if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
768 atf_fs_path_fini(&bp);
769 atf_fs_path_fini(&p);
770 atf_tc_fail("Relative paths are not allowed when searching for "
771 "a program (%s)", prog);
774 pf.prog = prog;
775 pf.found = false;
776 err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
777 if (atf_is_error(err))
778 goto out_bp;
780 if (!pf.found) {
781 atf_fs_path_fini(&bp);
782 atf_fs_path_fini(&p);
783 atf_tc_skip("The required program %s could not be found in "
784 "the PATH", prog);
787 out_bp:
788 atf_fs_path_fini(&bp);
791 out_p:
792 atf_fs_path_fini(&p);
793 out:
794 return err;
797 static
798 atf_error_t
799 check_prog_in_dir(const char *dir, void *data)
801 struct prog_found_pair *pf = data;
802 atf_error_t err;
804 if (pf->found)
805 err = atf_no_error();
806 else {
807 atf_fs_path_t p;
809 err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
810 if (atf_is_error(err))
811 goto out_p;
813 err = atf_fs_eaccess(&p, atf_fs_access_x);
814 if (!atf_is_error(err))
815 pf->found = true;
816 else {
817 atf_error_free(err);
818 INV(!pf->found);
819 err = atf_no_error();
822 out_p:
823 atf_fs_path_fini(&p);
826 return err;
829 static
830 atf_error_t
831 check_requirements(const atf_tc_t *tc)
833 atf_error_t err;
835 err = atf_no_error();
837 if (atf_tc_has_md_var(tc, "require.arch")) {
838 const char *arches = atf_tc_get_md_var(tc, "require.arch");
839 bool found = false;
841 if (strlen(arches) == 0)
842 atf_tc_fail("Invalid value in the require.arch property");
843 else {
844 err = atf_text_for_each_word(arches, " ", check_arch, &found);
845 if (atf_is_error(err))
846 goto out;
848 if (!found)
849 atf_tc_skip("Requires one of the '%s' architectures",
850 arches);
854 if (atf_tc_has_md_var(tc, "require.config")) {
855 const char *vars = atf_tc_get_md_var(tc, "require.config");
857 if (strlen(vars) == 0)
858 atf_tc_fail("Invalid value in the require.config property");
859 else {
860 err = atf_text_for_each_word(vars, " ", check_config, NULL);
861 if (atf_is_error(err))
862 goto out;
866 if (atf_tc_has_md_var(tc, "require.machine")) {
867 const char *machines = atf_tc_get_md_var(tc, "require.machine");
868 bool found = false;
870 if (strlen(machines) == 0)
871 atf_tc_fail("Invalid value in the require.machine property");
872 else {
873 err = atf_text_for_each_word(machines, " ", check_machine,
874 &found);
875 if (atf_is_error(err))
876 goto out;
878 if (!found)
879 atf_tc_skip("Requires one of the '%s' machine types",
880 machines);
884 if (atf_tc_has_md_var(tc, "require.progs")) {
885 const char *progs = atf_tc_get_md_var(tc, "require.progs");
887 if (strlen(progs) == 0)
888 atf_tc_fail("Invalid value in the require.progs property");
889 else {
890 err = atf_text_for_each_word(progs, " ", check_prog, NULL);
891 if (atf_is_error(err))
892 goto out;
896 if (atf_tc_has_md_var(tc, "require.user")) {
897 const char *u = atf_tc_get_md_var(tc, "require.user");
899 if (strcmp(u, "root") == 0) {
900 if (!atf_user_is_root())
901 atf_tc_skip("Requires root privileges");
902 } else if (strcmp(u, "unprivileged") == 0) {
903 if (atf_user_is_root())
904 atf_tc_skip("Requires an unprivileged user");
905 } else
906 atf_tc_fail("Invalid value in the require.user property");
909 INV(!atf_is_error(err));
910 out:
911 return err;
914 static
915 void
916 cleanup_child(void *v)
918 const struct child_data *cd = v;
919 atf_error_t err;
921 err = prepare_child(cd);
922 if (atf_is_error(err)) {
923 atf_reset_exit_checks();
924 exit(EXIT_FAILURE);
925 } else {
926 atf_reset_exit_checks();
927 cd->tc->m_cleanup(cd->tc);
928 exit(EXIT_SUCCESS);
931 UNREACHABLE;
934 static
935 void
936 fatal_atf_error(const char *prefix, atf_error_t err)
938 char buf[1024];
940 INV(atf_is_error(err));
942 atf_error_format(err, buf, sizeof(buf));
943 atf_error_free(err);
945 fprintf(stderr, "%s: %s", prefix, buf);
947 abort();
950 static
951 void
952 fatal_libc_error(const char *prefix, int err)
954 fprintf(stderr, "%s: %s", prefix, strerror(err));
956 abort();
959 static
960 void
961 write_tcr(const atf_tcr_t *tcr)
963 atf_error_t err;
964 int fd;
965 atf_fs_path_t tcrfile;
967 err = atf_fs_path_copy(&tcrfile, current_workdir);
968 if (atf_is_error(err))
969 fatal_atf_error("Cannot write test case results", err);
971 err = atf_fs_path_append_fmt(&tcrfile, "tc-result");
972 if (atf_is_error(err))
973 fatal_atf_error("Cannot write test case results", err);
975 fd = open(atf_fs_path_cstring(&tcrfile),
976 O_WRONLY | O_CREAT | O_TRUNC, 0755);
977 if (fd == -1)
978 fatal_libc_error("Cannot write test case results", errno);
980 err = atf_tcr_serialize(tcr, fd);
981 if (atf_is_error(err))
982 fatal_atf_error("Cannot write test case results", err);
984 close(fd);
985 atf_fs_path_fini(&tcrfile);
988 static
989 void
990 tc_fail(atf_dynstr_t *msg)
992 atf_tcr_t tcr;
993 atf_error_t err;
995 PRE(current_tc != NULL);
997 err = atf_tcr_init_reason_fmt(&tcr, atf_tcr_failed_state, "%s",
998 atf_dynstr_cstring(msg));
999 if (atf_is_error(err))
1000 abort();
1002 write_tcr(&tcr);
1004 atf_tcr_fini(&tcr);
1005 atf_dynstr_fini(msg);
1007 exit(EXIT_SUCCESS);
1010 static
1011 void
1012 tc_fail_nonfatal(atf_dynstr_t *msg)
1014 fprintf(stderr, "%s\n", atf_dynstr_cstring(msg));
1015 atf_dynstr_fini(msg);
1017 current_tc_fail_count++;
1020 void
1021 atf_tc_fail(const char *fmt, ...)
1023 va_list ap;
1024 atf_tcr_t tcr;
1025 atf_error_t err;
1027 PRE(current_tc != NULL);
1029 va_start(ap, fmt);
1030 err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap);
1031 va_end(ap);
1032 if (atf_is_error(err))
1033 abort();
1035 write_tcr(&tcr);
1037 atf_tcr_fini(&tcr);
1039 exit(EXIT_SUCCESS);
1042 void
1043 atf_tc_fail_nonfatal(const char *fmt, ...)
1045 va_list ap;
1047 va_start(ap, fmt);
1048 vfprintf(stderr, fmt, ap);
1049 va_end(ap);
1050 fprintf(stderr, "\n");
1052 current_tc_fail_count++;
1055 void
1056 atf_tc_fail_check(const char *file, int line, const char *fmt, ...)
1058 va_list ap;
1060 va_start(ap, fmt);
1061 fail_internal(file, line, "Check failed", "*** ", fmt, ap,
1062 tc_fail_nonfatal, atf_tc_fail_nonfatal);
1063 va_end(ap);
1066 void
1067 atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...)
1069 va_list ap;
1071 atf_reset_exit_checks();
1073 va_start(ap, fmt);
1074 fail_internal(file, line, "Requirement failed", "", fmt, ap,
1075 tc_fail, atf_tc_fail);
1076 va_end(ap);
1078 UNREACHABLE;
1079 abort();
1082 static
1083 void
1084 fail_internal(const char *file, int line, const char *reason,
1085 const char *prefix, const char *fmt, va_list ap,
1086 void (*failfunc)(atf_dynstr_t *),
1087 void (*backupfunc)(const char *, ...))
1089 va_list ap2;
1090 atf_error_t err;
1091 atf_dynstr_t msg;
1093 err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line,
1094 reason);
1095 if (atf_is_error(err))
1096 goto backup;
1098 va_copy(ap2, ap);
1099 err = atf_dynstr_append_ap(&msg, fmt, ap2);
1100 va_end(ap2);
1101 if (atf_is_error(err)) {
1102 atf_dynstr_fini(&msg);
1103 goto backup;
1106 va_copy(ap2, ap);
1107 failfunc(&msg);
1108 return;
1110 backup:
1111 atf_error_free(err);
1112 va_copy(ap2, ap);
1113 backupfunc(fmt, ap2);
1114 va_end(ap2);
1117 void
1118 atf_tc_pass(void)
1120 atf_tcr_t tcr;
1121 atf_error_t err;
1123 PRE(current_tc != NULL);
1125 err = atf_tcr_init(&tcr, atf_tcr_passed_state);
1126 if (atf_is_error(err))
1127 abort();
1129 write_tcr(&tcr);
1131 atf_tcr_fini(&tcr);
1133 exit(EXIT_SUCCESS);
1136 void
1137 atf_tc_require_prog(const char *prog)
1139 atf_error_t err;
1141 err = check_prog(prog, NULL);
1142 if (atf_is_error(err)) {
1143 atf_error_free(err);
1144 atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */
1148 void
1149 atf_tc_skip(const char *fmt, ...)
1151 va_list ap;
1152 atf_tcr_t tcr;
1153 atf_error_t err;
1155 PRE(current_tc != NULL);
1157 va_start(ap, fmt);
1158 err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap);
1159 va_end(ap);
1160 if (atf_is_error(err))
1161 abort();
1163 write_tcr(&tcr);
1165 atf_tcr_fini(&tcr);
1167 exit(EXIT_SUCCESS);