2 * Automated Testing Framework (atf)
4 * Copyright (c) 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>
45 #include "atf-c/config.h"
46 #include "atf-c/defs.h"
47 #include "atf-c/env.h"
48 #include "atf-c/error.h"
50 #include "atf-c/process.h"
51 #include "atf-c/sanity.h"
52 #include "atf-c/signals.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 * --------------------------------------------------------------------- */
64 const atf_fs_path_t
*workdir
;
67 /* Parent-only stuff. */
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 /* ---------------------------------------------------------------------
106 * --------------------------------------------------------------------- */
109 * Constructors/destructors.
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
)
119 atf_object_init(&tc
->m_object
);
124 tc
->m_cleanup
= cleanup
;
125 tc
->m_config
= config
;
127 err
= atf_map_init(&tc
->m_vars
);
128 if (atf_is_error(err
))
131 err
= atf_tc_set_md_var(tc
, "ident", ident
);
132 if (atf_is_error(err
))
135 err
= atf_tc_set_md_var(tc
, "timeout", "300");
136 if (atf_is_error(err
))
139 /* XXX Should the head be able to return error codes? */
142 if (strcmp(atf_tc_get_md_var(tc
, "ident"), ident
) != 0)
143 atf_tc_fail("Test case head modified the read-only 'ident' "
146 INV(!atf_is_error(err
));
150 atf_map_fini(&tc
->m_vars
);
152 atf_object_fini(&tc
->m_object
);
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
);
166 atf_tc_fini(atf_tc_t
*tc
)
168 atf_map_fini(&tc
->m_vars
);
170 atf_object_fini(&tc
->m_object
);
178 atf_tc_get_ident(const atf_tc_t
*tc
)
184 atf_tc_get_config_var(const atf_tc_t
*tc
, const char *name
)
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
);
198 atf_tc_get_config_var_wd(const atf_tc_t
*tc
, const char *name
,
203 if (!atf_tc_has_config_var(tc
, name
))
206 val
= atf_tc_get_config_var(tc
, name
);
212 atf_tc_get_md_var(const atf_tc_t
*tc
, const char *name
)
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
);
226 atf_tc_has_config_var(const atf_tc_t
*tc
, const char *name
)
229 atf_map_citer_t end
, iter
;
231 if (tc
->m_config
== NULL
)
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
);
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
);
257 atf_tc_set_md_var(atf_tc_t
*tc
, const char *name
, const char *fmt
, ...)
264 err
= atf_text_format_ap(&value
, fmt
, ap
);
267 if (!atf_is_error(err
))
268 err
= atf_map_insert(&tc
->m_vars
, name
, value
, true);
275 /* ---------------------------------------------------------------------
277 * --------------------------------------------------------------------- */
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
))
290 err
= atf_fs_path_append_fmt(&workdir
, "atf.XXXXXX");
291 if (atf_is_error(err
))
294 err
= atf_fs_mkdtemp(&workdir
);
295 if (atf_is_error(err
))
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
))
304 else if (atf_is_error(cleanuperr
))
305 atf_error_free(cleanuperr
);
308 atf_fs_path_fini(&workdir
);
317 static bool sigalrm_killed
= false;
318 static pid_t sigalrm_pid
= -1;
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
{
334 atf_signal_programmer_t m_sigalrm
;
339 program_timeout(const atf_process_child_t
*child
, const atf_tc_t
*tc
,
340 struct timeout_data
*td
)
345 err
= atf_text_to_long(atf_tc_get_md_var(tc
, "timeout"), &timeout
);
346 if (atf_is_error(err
))
350 sigalrm_pid
= atf_process_child_pid(child
);
351 sigalrm_killed
= false;
353 err
= atf_signal_programmer_init(&td
->m_sigalrm
, SIGALRM
,
355 if (atf_is_error(err
))
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
);
370 td
->m_programmed
= false;
378 unprogram_timeout(struct timeout_data
*td
)
380 if (td
->m_programmed
) {
381 atf_signal_programmer_fini(&td
->m_sigalrm
);
383 sigalrm_killed
= false;
389 body_parent(const atf_tc_t
*tc
, const atf_fs_path_t
*workdir
,
390 atf_process_child_t
*child
, atf_tcr_t
*tcr
)
393 atf_process_status_t status
;
394 struct timeout_data td
;
396 err
= program_timeout(child
, tc
, &td
);
397 if (atf_is_error(err
)) {
400 atf_error_format(err
, buf
, sizeof(buf
));
401 fprintf(stderr
, "Error programming test case's timeout: %s", buf
);
403 killpg(atf_process_child_pid(child
), SIGKILL
);
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
) {
417 err
= atf_tcr_init_reason_fmt(tcr
, atf_tcr_failed_state
,
418 "Test case timed out after %s "
420 atf_tc_get_md_var(tc
, "timeout"));
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
);
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 "
436 wcore
? " (core dumped)" : "");
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
);
454 cleanup_parent(const atf_tc_t
*tc
, atf_process_child_t
*child
)
457 atf_process_status_t status
;
459 err
= atf_process_child_wait(child
, &status
);
460 if (atf_is_error(err
))
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");
468 err
= atf_no_error();
470 atf_process_status_fini(&status
);
477 fork_body(const atf_tc_t
*tc
, int fdout
, int fderr
,
478 const atf_fs_path_t
*workdir
, atf_tcr_t
*tcr
)
481 atf_process_stream_t outsb
, errsb
;
482 atf_process_child_t child
;
483 struct child_data data
= {
488 err
= atf_process_stream_init_redirect_fd(&outsb
, fdout
);
489 if (atf_is_error(err
))
492 err
= atf_process_stream_init_redirect_fd(&errsb
, fderr
);
493 if (atf_is_error(err
))
496 err
= atf_process_fork(&child
, body_child
, &outsb
, &errsb
, &data
);
497 if (atf_is_error(err
))
500 err
= body_parent(tc
, workdir
, &child
, tcr
);
503 atf_process_stream_fini(&errsb
);
505 atf_process_stream_fini(&outsb
);
512 fork_cleanup(const atf_tc_t
*tc
, int fdout
, int fderr
,
513 const atf_fs_path_t
*workdir
)
517 if (tc
->m_cleanup
== NULL
)
518 err
= atf_no_error();
520 atf_process_stream_t outsb
, errsb
;
521 atf_process_child_t child
;
522 struct child_data data
= {
527 err
= atf_process_stream_init_redirect_fd(&outsb
, fdout
);
528 if (atf_is_error(err
))
531 err
= atf_process_stream_init_redirect_fd(&errsb
, fderr
);
532 if (atf_is_error(err
))
535 err
= atf_process_fork(&child
, cleanup_child
, &outsb
, &errsb
, &data
);
536 if (atf_is_error(err
))
539 err
= cleanup_parent(tc
, &child
);
542 atf_process_stream_fini(&errsb
);
544 atf_process_stream_fini(&outsb
);
553 get_tc_result(const atf_fs_path_t
*workdir
, atf_tcr_t
*tcr
)
557 atf_fs_path_t tcrfile
;
559 err
= atf_fs_path_copy(&tcrfile
, workdir
);
560 if (atf_is_error(err
))
563 err
= atf_fs_path_append_fmt(&tcrfile
, "tc-result");
564 if (atf_is_error(err
))
567 fd
= open(atf_fs_path_cstring(&tcrfile
), O_RDONLY
);
569 err
= atf_libc_error(errno
, "Cannot retrieve test case result");
573 err
= atf_tcr_deserialize(tcr
, fd
);
577 atf_fs_path_fini(&tcrfile
);
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;
592 prepare_child(const struct child_data
*cd
)
598 current_workdir
= cd
->workdir
;
599 current_tc_fail_count
= 0;
601 ret
= setpgid(getpid(), 0);
604 umask(S_IWGRP
| S_IWOTH
);
606 for (i
= 1; i
<= atf_signals_last_signo
; i
++)
609 err
= atf_env_set("HOME", atf_fs_path_cstring(cd
->workdir
));
610 if (atf_is_error(err
))
613 err
= atf_env_unset("LANG");
614 if (atf_is_error(err
))
617 err
= atf_env_unset("LC_ALL");
618 if (atf_is_error(err
))
621 err
= atf_env_unset("LC_COLLATE");
622 if (atf_is_error(err
))
625 err
= atf_env_unset("LC_CTYPE");
626 if (atf_is_error(err
))
629 err
= atf_env_unset("LC_MESSAGES");
630 if (atf_is_error(err
))
633 err
= atf_env_unset("LC_MONETARY");
634 if (atf_is_error(err
))
637 err
= atf_env_unset("LC_NUMERIC");
638 if (atf_is_error(err
))
641 err
= atf_env_unset("LC_TIME");
642 if (atf_is_error(err
))
645 err
= atf_env_unset("TZ");
646 if (atf_is_error(err
))
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
));
655 err
= atf_no_error();
665 const struct child_data
*cd
= v
;
668 atf_reset_exit_checks();
670 err
= prepare_child(cd
);
671 if (atf_is_error(err
))
673 err
= check_requirements(cd
->tc
);
674 if (atf_is_error(err
))
677 cd
->tc
->m_body(cd
->tc
);
679 if (current_tc_fail_count
== 0)
682 atf_tc_fail("%d checks failed; see output for more details",
683 current_tc_fail_count
);
688 INV(atf_is_error(err
));
692 atf_error_format(err
, buf
, sizeof(buf
));
695 atf_tc_fail("Error while preparing child process: %s", buf
);
703 check_arch(const char *arch
, void *data
)
707 if (strcmp(arch
, atf_config_get("atf_arch")) == 0)
710 return atf_no_error();
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();
725 check_machine(const char *machine
, void *data
)
729 if (strcmp(machine
, atf_config_get("atf_machine")) == 0)
732 return atf_no_error();
735 struct prog_found_pair
{
742 check_prog(const char *prog
, void *data
)
747 err
= atf_fs_path_init_fmt(&p
, "%s", prog
);
748 if (atf_is_error(err
))
751 if (atf_fs_path_is_absolute(&p
)) {
752 err
= atf_fs_eaccess(&p
, atf_fs_access_x
);
753 if (atf_is_error(err
)) {
755 atf_fs_path_fini(&p
);
756 atf_tc_skip("The required program %s could not be found", prog
);
759 const char *path
= atf_env_get("PATH");
760 struct prog_found_pair pf
;
763 err
= atf_fs_path_branch_path(&p
, &bp
);
764 if (atf_is_error(err
))
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
);
776 err
= atf_text_for_each_word(path
, ":", check_prog_in_dir
, &pf
);
777 if (atf_is_error(err
))
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 "
788 atf_fs_path_fini(&bp
);
792 atf_fs_path_fini(&p
);
799 check_prog_in_dir(const char *dir
, void *data
)
801 struct prog_found_pair
*pf
= data
;
805 err
= atf_no_error();
809 err
= atf_fs_path_init_fmt(&p
, "%s/%s", dir
, pf
->prog
);
810 if (atf_is_error(err
))
813 err
= atf_fs_eaccess(&p
, atf_fs_access_x
);
814 if (!atf_is_error(err
))
819 err
= atf_no_error();
823 atf_fs_path_fini(&p
);
831 check_requirements(const atf_tc_t
*tc
)
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");
841 if (strlen(arches
) == 0)
842 atf_tc_fail("Invalid value in the require.arch property");
844 err
= atf_text_for_each_word(arches
, " ", check_arch
, &found
);
845 if (atf_is_error(err
))
849 atf_tc_skip("Requires one of the '%s' architectures",
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");
860 err
= atf_text_for_each_word(vars
, " ", check_config
, NULL
);
861 if (atf_is_error(err
))
866 if (atf_tc_has_md_var(tc
, "require.machine")) {
867 const char *machines
= atf_tc_get_md_var(tc
, "require.machine");
870 if (strlen(machines
) == 0)
871 atf_tc_fail("Invalid value in the require.machine property");
873 err
= atf_text_for_each_word(machines
, " ", check_machine
,
875 if (atf_is_error(err
))
879 atf_tc_skip("Requires one of the '%s' machine types",
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");
890 err
= atf_text_for_each_word(progs
, " ", check_prog
, NULL
);
891 if (atf_is_error(err
))
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");
906 atf_tc_fail("Invalid value in the require.user property");
909 INV(!atf_is_error(err
));
916 cleanup_child(void *v
)
918 const struct child_data
*cd
= v
;
921 err
= prepare_child(cd
);
922 if (atf_is_error(err
)) {
923 atf_reset_exit_checks();
926 atf_reset_exit_checks();
927 cd
->tc
->m_cleanup(cd
->tc
);
936 fatal_atf_error(const char *prefix
, atf_error_t err
)
940 INV(atf_is_error(err
));
942 atf_error_format(err
, buf
, sizeof(buf
));
945 fprintf(stderr
, "%s: %s", prefix
, buf
);
952 fatal_libc_error(const char *prefix
, int err
)
954 fprintf(stderr
, "%s: %s", prefix
, strerror(err
));
961 write_tcr(const atf_tcr_t
*tcr
)
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);
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
);
985 atf_fs_path_fini(&tcrfile
);
990 tc_fail(atf_dynstr_t
*msg
)
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
))
1005 atf_dynstr_fini(msg
);
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
++;
1021 atf_tc_fail(const char *fmt
, ...)
1027 PRE(current_tc
!= NULL
);
1030 err
= atf_tcr_init_reason_ap(&tcr
, atf_tcr_failed_state
, fmt
, ap
);
1032 if (atf_is_error(err
))
1043 atf_tc_fail_nonfatal(const char *fmt
, ...)
1048 vfprintf(stderr
, fmt
, ap
);
1050 fprintf(stderr
, "\n");
1052 current_tc_fail_count
++;
1056 atf_tc_fail_check(const char *file
, int line
, const char *fmt
, ...)
1061 fail_internal(file
, line
, "Check failed", "*** ", fmt
, ap
,
1062 tc_fail_nonfatal
, atf_tc_fail_nonfatal
);
1067 atf_tc_fail_requirement(const char *file
, int line
, const char *fmt
, ...)
1071 atf_reset_exit_checks();
1074 fail_internal(file
, line
, "Requirement failed", "", fmt
, ap
,
1075 tc_fail
, atf_tc_fail
);
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 *, ...))
1093 err
= atf_dynstr_init_fmt(&msg
, "%s%s:%d: %s: ", prefix
, file
, line
,
1095 if (atf_is_error(err
))
1099 err
= atf_dynstr_append_ap(&msg
, fmt
, ap2
);
1101 if (atf_is_error(err
)) {
1102 atf_dynstr_fini(&msg
);
1111 atf_error_free(err
);
1113 backupfunc(fmt
, ap2
);
1123 PRE(current_tc
!= NULL
);
1125 err
= atf_tcr_init(&tcr
, atf_tcr_passed_state
);
1126 if (atf_is_error(err
))
1137 atf_tc_require_prog(const char *prog
)
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? */
1149 atf_tc_skip(const char *fmt
, ...)
1155 PRE(current_tc
!= NULL
);
1158 err
= atf_tcr_init_reason_ap(&tcr
, atf_tcr_skipped_state
, fmt
, ap
);
1160 if (atf_is_error(err
))