Home | History | Annotate | Line # | Download | only in atf-c
tc.c revision 1.1.1.3
      1      1.1  jmmv /*
      2      1.1  jmmv  * Automated Testing Framework (atf)
      3      1.1  jmmv  *
      4  1.1.1.3  jmmv  * Copyright (c) 2008, 2009, 2010 The NetBSD Foundation, Inc.
      5      1.1  jmmv  * All rights reserved.
      6      1.1  jmmv  *
      7      1.1  jmmv  * Redistribution and use in source and binary forms, with or without
      8      1.1  jmmv  * modification, are permitted provided that the following conditions
      9      1.1  jmmv  * are met:
     10      1.1  jmmv  * 1. Redistributions of source code must retain the above copyright
     11      1.1  jmmv  *    notice, this list of conditions and the following disclaimer.
     12      1.1  jmmv  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1  jmmv  *    notice, this list of conditions and the following disclaimer in the
     14      1.1  jmmv  *    documentation and/or other materials provided with the distribution.
     15      1.1  jmmv  *
     16      1.1  jmmv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
     17      1.1  jmmv  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     18      1.1  jmmv  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19      1.1  jmmv  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20      1.1  jmmv  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
     21      1.1  jmmv  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22      1.1  jmmv  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     23      1.1  jmmv  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24      1.1  jmmv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
     25      1.1  jmmv  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     26      1.1  jmmv  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27      1.1  jmmv  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28      1.1  jmmv  */
     29      1.1  jmmv 
     30      1.1  jmmv #include <sys/types.h>
     31      1.1  jmmv #include <sys/time.h>
     32      1.1  jmmv #include <sys/stat.h>
     33      1.1  jmmv #include <sys/wait.h>
     34      1.1  jmmv 
     35      1.1  jmmv #include <errno.h>
     36      1.1  jmmv #include <fcntl.h>
     37      1.1  jmmv #include <limits.h>
     38      1.1  jmmv #include <stdarg.h>
     39      1.1  jmmv #include <stdbool.h>
     40      1.1  jmmv #include <stdio.h>
     41      1.1  jmmv #include <stdlib.h>
     42      1.1  jmmv #include <string.h>
     43      1.1  jmmv #include <unistd.h>
     44      1.1  jmmv 
     45      1.1  jmmv #include "atf-c/config.h"
     46  1.1.1.2  jmmv #include "atf-c/defs.h"
     47      1.1  jmmv #include "atf-c/env.h"
     48      1.1  jmmv #include "atf-c/error.h"
     49      1.1  jmmv #include "atf-c/fs.h"
     50      1.1  jmmv #include "atf-c/process.h"
     51      1.1  jmmv #include "atf-c/sanity.h"
     52      1.1  jmmv #include "atf-c/tc.h"
     53      1.1  jmmv #include "atf-c/tcr.h"
     54      1.1  jmmv #include "atf-c/text.h"
     55      1.1  jmmv #include "atf-c/user.h"
     56      1.1  jmmv 
     57      1.1  jmmv /* ---------------------------------------------------------------------
     58      1.1  jmmv  * Auxiliary types and functions.
     59      1.1  jmmv  * --------------------------------------------------------------------- */
     60      1.1  jmmv 
     61      1.1  jmmv static atf_error_t check_prog(const char *, void *);
     62      1.1  jmmv static atf_error_t check_prog_in_dir(const char *, void *);
     63      1.1  jmmv static void fail_internal(const char *, int, const char *, const char *,
     64      1.1  jmmv                           const char *, va_list,
     65  1.1.1.2  jmmv                           void (*)(atf_dynstr_t *),
     66      1.1  jmmv                           void (*)(const char *, ...));
     67  1.1.1.2  jmmv static void tc_fail(atf_dynstr_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
     68  1.1.1.2  jmmv static void tc_fail_nonfatal(atf_dynstr_t *);
     69      1.1  jmmv 
     70      1.1  jmmv /* ---------------------------------------------------------------------
     71      1.1  jmmv  * The "atf_tc" type.
     72      1.1  jmmv  * --------------------------------------------------------------------- */
     73      1.1  jmmv 
     74      1.1  jmmv /*
     75      1.1  jmmv  * Constructors/destructors.
     76      1.1  jmmv  */
     77      1.1  jmmv 
     78      1.1  jmmv atf_error_t
     79      1.1  jmmv atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
     80      1.1  jmmv             atf_tc_body_t body, atf_tc_cleanup_t cleanup,
     81      1.1  jmmv             const atf_map_t *config)
     82      1.1  jmmv {
     83      1.1  jmmv     atf_error_t err;
     84      1.1  jmmv 
     85      1.1  jmmv     atf_object_init(&tc->m_object);
     86      1.1  jmmv 
     87      1.1  jmmv     tc->m_ident = ident;
     88      1.1  jmmv     tc->m_head = head;
     89      1.1  jmmv     tc->m_body = body;
     90      1.1  jmmv     tc->m_cleanup = cleanup;
     91      1.1  jmmv     tc->m_config = config;
     92      1.1  jmmv 
     93      1.1  jmmv     err = atf_map_init(&tc->m_vars);
     94      1.1  jmmv     if (atf_is_error(err))
     95      1.1  jmmv         goto err_object;
     96      1.1  jmmv 
     97      1.1  jmmv     err = atf_tc_set_md_var(tc, "ident", ident);
     98      1.1  jmmv     if (atf_is_error(err))
     99      1.1  jmmv         goto err_map;
    100      1.1  jmmv 
    101      1.1  jmmv     /* XXX Should the head be able to return error codes? */
    102      1.1  jmmv     tc->m_head(tc);
    103      1.1  jmmv 
    104      1.1  jmmv     if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0)
    105      1.1  jmmv         atf_tc_fail("Test case head modified the read-only 'ident' "
    106      1.1  jmmv                     "property");
    107      1.1  jmmv 
    108      1.1  jmmv     INV(!atf_is_error(err));
    109      1.1  jmmv     return err;
    110      1.1  jmmv 
    111      1.1  jmmv err_map:
    112      1.1  jmmv     atf_map_fini(&tc->m_vars);
    113      1.1  jmmv err_object:
    114      1.1  jmmv     atf_object_fini(&tc->m_object);
    115      1.1  jmmv 
    116      1.1  jmmv     return err;
    117      1.1  jmmv }
    118      1.1  jmmv 
    119      1.1  jmmv atf_error_t
    120      1.1  jmmv atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
    121      1.1  jmmv                  const atf_map_t *config)
    122      1.1  jmmv {
    123      1.1  jmmv     return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
    124      1.1  jmmv                        pack->m_cleanup, config);
    125      1.1  jmmv }
    126      1.1  jmmv 
    127      1.1  jmmv void
    128      1.1  jmmv atf_tc_fini(atf_tc_t *tc)
    129      1.1  jmmv {
    130      1.1  jmmv     atf_map_fini(&tc->m_vars);
    131      1.1  jmmv 
    132      1.1  jmmv     atf_object_fini(&tc->m_object);
    133      1.1  jmmv }
    134      1.1  jmmv 
    135      1.1  jmmv /*
    136      1.1  jmmv  * Getters.
    137      1.1  jmmv  */
    138      1.1  jmmv 
    139      1.1  jmmv const char *
    140      1.1  jmmv atf_tc_get_ident(const atf_tc_t *tc)
    141      1.1  jmmv {
    142      1.1  jmmv     return tc->m_ident;
    143      1.1  jmmv }
    144      1.1  jmmv 
    145      1.1  jmmv const char *
    146      1.1  jmmv atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
    147      1.1  jmmv {
    148      1.1  jmmv     const char *val;
    149      1.1  jmmv     atf_map_citer_t iter;
    150      1.1  jmmv 
    151      1.1  jmmv     PRE(atf_tc_has_config_var(tc, name));
    152      1.1  jmmv     iter = atf_map_find_c(tc->m_config, name);
    153      1.1  jmmv     val = atf_map_citer_data(iter);
    154      1.1  jmmv     INV(val != NULL);
    155      1.1  jmmv 
    156      1.1  jmmv     return val;
    157      1.1  jmmv }
    158      1.1  jmmv 
    159      1.1  jmmv const char *
    160      1.1  jmmv atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
    161      1.1  jmmv                          const char *defval)
    162      1.1  jmmv {
    163      1.1  jmmv     const char *val;
    164      1.1  jmmv 
    165      1.1  jmmv     if (!atf_tc_has_config_var(tc, name))
    166      1.1  jmmv         val = defval;
    167      1.1  jmmv     else
    168      1.1  jmmv         val = atf_tc_get_config_var(tc, name);
    169      1.1  jmmv 
    170      1.1  jmmv     return val;
    171      1.1  jmmv }
    172      1.1  jmmv 
    173      1.1  jmmv const char *
    174      1.1  jmmv atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
    175      1.1  jmmv {
    176      1.1  jmmv     const char *val;
    177      1.1  jmmv     atf_map_citer_t iter;
    178      1.1  jmmv 
    179      1.1  jmmv     PRE(atf_tc_has_md_var(tc, name));
    180      1.1  jmmv     iter = atf_map_find_c(&tc->m_vars, name);
    181      1.1  jmmv     val = atf_map_citer_data(iter);
    182      1.1  jmmv     INV(val != NULL);
    183      1.1  jmmv 
    184      1.1  jmmv     return val;
    185      1.1  jmmv }
    186      1.1  jmmv 
    187  1.1.1.3  jmmv const atf_map_t *
    188  1.1.1.3  jmmv atf_tc_get_md_vars(const atf_tc_t *tc)
    189  1.1.1.3  jmmv {
    190  1.1.1.3  jmmv     return &tc->m_vars;
    191  1.1.1.3  jmmv }
    192  1.1.1.3  jmmv 
    193      1.1  jmmv bool
    194      1.1  jmmv atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
    195      1.1  jmmv {
    196      1.1  jmmv     bool found;
    197      1.1  jmmv     atf_map_citer_t end, iter;
    198      1.1  jmmv 
    199      1.1  jmmv     if (tc->m_config == NULL)
    200      1.1  jmmv         found = false;
    201      1.1  jmmv     else {
    202      1.1  jmmv         iter = atf_map_find_c(tc->m_config, name);
    203      1.1  jmmv         end = atf_map_end_c(tc->m_config);
    204      1.1  jmmv         found = !atf_equal_map_citer_map_citer(iter, end);
    205      1.1  jmmv     }
    206      1.1  jmmv 
    207      1.1  jmmv     return found;
    208      1.1  jmmv }
    209      1.1  jmmv 
    210      1.1  jmmv bool
    211      1.1  jmmv atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
    212      1.1  jmmv {
    213      1.1  jmmv     atf_map_citer_t end, iter;
    214      1.1  jmmv 
    215      1.1  jmmv     iter = atf_map_find_c(&tc->m_vars, name);
    216      1.1  jmmv     end = atf_map_end_c(&tc->m_vars);
    217      1.1  jmmv     return !atf_equal_map_citer_map_citer(iter, end);
    218      1.1  jmmv }
    219      1.1  jmmv 
    220      1.1  jmmv /*
    221      1.1  jmmv  * Modifiers.
    222      1.1  jmmv  */
    223      1.1  jmmv 
    224      1.1  jmmv atf_error_t
    225      1.1  jmmv atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
    226      1.1  jmmv {
    227      1.1  jmmv     atf_error_t err;
    228      1.1  jmmv     char *value;
    229      1.1  jmmv     va_list ap;
    230      1.1  jmmv 
    231      1.1  jmmv     va_start(ap, fmt);
    232      1.1  jmmv     err = atf_text_format_ap(&value, fmt, ap);
    233      1.1  jmmv     va_end(ap);
    234      1.1  jmmv 
    235      1.1  jmmv     if (!atf_is_error(err))
    236      1.1  jmmv         err = atf_map_insert(&tc->m_vars, name, value, true);
    237      1.1  jmmv     else
    238      1.1  jmmv         free(value);
    239      1.1  jmmv 
    240      1.1  jmmv     return err;
    241      1.1  jmmv }
    242      1.1  jmmv 
    243      1.1  jmmv /* ---------------------------------------------------------------------
    244      1.1  jmmv  * Free functions.
    245      1.1  jmmv  * --------------------------------------------------------------------- */
    246      1.1  jmmv 
    247      1.1  jmmv static const atf_tc_t *current_tc = NULL;
    248  1.1.1.3  jmmv static const atf_fs_path_t *current_resfile = NULL;
    249      1.1  jmmv static size_t current_tc_fail_count = 0;
    250      1.1  jmmv 
    251      1.1  jmmv atf_error_t
    252  1.1.1.3  jmmv atf_tc_run(const atf_tc_t *tc, const atf_fs_path_t *resfile)
    253      1.1  jmmv {
    254  1.1.1.3  jmmv     atf_reset_exit_checks(); /* XXX */
    255      1.1  jmmv 
    256  1.1.1.3  jmmv     current_tc = tc;
    257  1.1.1.3  jmmv     current_resfile = resfile;
    258      1.1  jmmv     current_tc_fail_count = 0;
    259      1.1  jmmv 
    260  1.1.1.3  jmmv     tc->m_body(tc);
    261      1.1  jmmv 
    262      1.1  jmmv     if (current_tc_fail_count == 0)
    263      1.1  jmmv         atf_tc_pass();
    264      1.1  jmmv     else
    265      1.1  jmmv         atf_tc_fail("%d checks failed; see output for more details",
    266      1.1  jmmv                     current_tc_fail_count);
    267      1.1  jmmv 
    268  1.1.1.3  jmmv     current_tc = NULL;
    269  1.1.1.3  jmmv     current_resfile = NULL;
    270  1.1.1.3  jmmv     current_tc_fail_count = 0;
    271      1.1  jmmv 
    272      1.1  jmmv     return atf_no_error();
    273      1.1  jmmv }
    274      1.1  jmmv 
    275      1.1  jmmv atf_error_t
    276  1.1.1.3  jmmv atf_tc_cleanup(const atf_tc_t *tc)
    277      1.1  jmmv {
    278  1.1.1.3  jmmv     if (tc->m_cleanup != NULL)
    279  1.1.1.3  jmmv         tc->m_cleanup(tc);
    280  1.1.1.3  jmmv     return atf_no_error(); /* XXX */
    281      1.1  jmmv }
    282      1.1  jmmv 
    283      1.1  jmmv struct prog_found_pair {
    284      1.1  jmmv     const char *prog;
    285      1.1  jmmv     bool found;
    286      1.1  jmmv };
    287      1.1  jmmv 
    288      1.1  jmmv static
    289      1.1  jmmv atf_error_t
    290      1.1  jmmv check_prog(const char *prog, void *data)
    291      1.1  jmmv {
    292      1.1  jmmv     atf_error_t err;
    293      1.1  jmmv     atf_fs_path_t p;
    294      1.1  jmmv 
    295      1.1  jmmv     err = atf_fs_path_init_fmt(&p, "%s", prog);
    296      1.1  jmmv     if (atf_is_error(err))
    297      1.1  jmmv         goto out;
    298      1.1  jmmv 
    299      1.1  jmmv     if (atf_fs_path_is_absolute(&p)) {
    300  1.1.1.2  jmmv         err = atf_fs_eaccess(&p, atf_fs_access_x);
    301  1.1.1.2  jmmv         if (atf_is_error(err)) {
    302  1.1.1.2  jmmv             atf_error_free(err);
    303  1.1.1.2  jmmv             atf_fs_path_fini(&p);
    304      1.1  jmmv             atf_tc_skip("The required program %s could not be found", prog);
    305  1.1.1.2  jmmv         }
    306      1.1  jmmv     } else {
    307      1.1  jmmv         const char *path = atf_env_get("PATH");
    308      1.1  jmmv         struct prog_found_pair pf;
    309      1.1  jmmv         atf_fs_path_t bp;
    310      1.1  jmmv 
    311      1.1  jmmv         err = atf_fs_path_branch_path(&p, &bp);
    312      1.1  jmmv         if (atf_is_error(err))
    313      1.1  jmmv             goto out_p;
    314      1.1  jmmv 
    315  1.1.1.2  jmmv         if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
    316  1.1.1.2  jmmv             atf_fs_path_fini(&bp);
    317  1.1.1.2  jmmv             atf_fs_path_fini(&p);
    318      1.1  jmmv             atf_tc_fail("Relative paths are not allowed when searching for "
    319      1.1  jmmv                         "a program (%s)", prog);
    320  1.1.1.2  jmmv         }
    321      1.1  jmmv 
    322      1.1  jmmv         pf.prog = prog;
    323      1.1  jmmv         pf.found = false;
    324      1.1  jmmv         err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
    325      1.1  jmmv         if (atf_is_error(err))
    326      1.1  jmmv             goto out_bp;
    327      1.1  jmmv 
    328  1.1.1.2  jmmv         if (!pf.found) {
    329  1.1.1.2  jmmv             atf_fs_path_fini(&bp);
    330  1.1.1.2  jmmv             atf_fs_path_fini(&p);
    331      1.1  jmmv             atf_tc_skip("The required program %s could not be found in "
    332      1.1  jmmv                         "the PATH", prog);
    333  1.1.1.2  jmmv         }
    334      1.1  jmmv 
    335      1.1  jmmv out_bp:
    336      1.1  jmmv         atf_fs_path_fini(&bp);
    337      1.1  jmmv     }
    338      1.1  jmmv 
    339      1.1  jmmv out_p:
    340      1.1  jmmv     atf_fs_path_fini(&p);
    341      1.1  jmmv out:
    342      1.1  jmmv     return err;
    343      1.1  jmmv }
    344      1.1  jmmv 
    345      1.1  jmmv static
    346      1.1  jmmv atf_error_t
    347      1.1  jmmv check_prog_in_dir(const char *dir, void *data)
    348      1.1  jmmv {
    349      1.1  jmmv     struct prog_found_pair *pf = data;
    350      1.1  jmmv     atf_error_t err;
    351      1.1  jmmv 
    352      1.1  jmmv     if (pf->found)
    353      1.1  jmmv         err = atf_no_error();
    354      1.1  jmmv     else {
    355      1.1  jmmv         atf_fs_path_t p;
    356      1.1  jmmv 
    357      1.1  jmmv         err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
    358      1.1  jmmv         if (atf_is_error(err))
    359      1.1  jmmv             goto out_p;
    360      1.1  jmmv 
    361  1.1.1.2  jmmv         err = atf_fs_eaccess(&p, atf_fs_access_x);
    362  1.1.1.2  jmmv         if (!atf_is_error(err))
    363      1.1  jmmv             pf->found = true;
    364  1.1.1.2  jmmv         else {
    365  1.1.1.2  jmmv             atf_error_free(err);
    366  1.1.1.2  jmmv             INV(!pf->found);
    367  1.1.1.2  jmmv             err = atf_no_error();
    368  1.1.1.2  jmmv         }
    369      1.1  jmmv 
    370      1.1  jmmv out_p:
    371      1.1  jmmv         atf_fs_path_fini(&p);
    372      1.1  jmmv     }
    373      1.1  jmmv 
    374      1.1  jmmv     return err;
    375      1.1  jmmv }
    376      1.1  jmmv 
    377      1.1  jmmv static
    378  1.1.1.2  jmmv void
    379  1.1.1.2  jmmv tc_fail(atf_dynstr_t *msg)
    380  1.1.1.2  jmmv {
    381  1.1.1.2  jmmv     atf_tcr_t tcr;
    382  1.1.1.2  jmmv     atf_error_t err;
    383  1.1.1.2  jmmv 
    384  1.1.1.2  jmmv     PRE(current_tc != NULL);
    385  1.1.1.2  jmmv 
    386  1.1.1.2  jmmv     err = atf_tcr_init_reason_fmt(&tcr, atf_tcr_failed_state, "%s",
    387  1.1.1.2  jmmv                                   atf_dynstr_cstring(msg));
    388  1.1.1.2  jmmv     if (atf_is_error(err))
    389  1.1.1.2  jmmv         abort();
    390  1.1.1.2  jmmv 
    391  1.1.1.3  jmmv     atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
    392  1.1.1.2  jmmv 
    393  1.1.1.2  jmmv     atf_tcr_fini(&tcr);
    394  1.1.1.2  jmmv     atf_dynstr_fini(msg);
    395  1.1.1.2  jmmv 
    396  1.1.1.3  jmmv     exit(EXIT_FAILURE);
    397  1.1.1.2  jmmv }
    398  1.1.1.2  jmmv 
    399  1.1.1.2  jmmv static
    400  1.1.1.2  jmmv void
    401  1.1.1.2  jmmv tc_fail_nonfatal(atf_dynstr_t *msg)
    402  1.1.1.2  jmmv {
    403  1.1.1.2  jmmv     fprintf(stderr, "%s\n", atf_dynstr_cstring(msg));
    404  1.1.1.2  jmmv     atf_dynstr_fini(msg);
    405  1.1.1.2  jmmv 
    406  1.1.1.2  jmmv     current_tc_fail_count++;
    407      1.1  jmmv }
    408      1.1  jmmv 
    409      1.1  jmmv void
    410      1.1  jmmv atf_tc_fail(const char *fmt, ...)
    411      1.1  jmmv {
    412      1.1  jmmv     va_list ap;
    413      1.1  jmmv     atf_tcr_t tcr;
    414      1.1  jmmv     atf_error_t err;
    415      1.1  jmmv 
    416      1.1  jmmv     PRE(current_tc != NULL);
    417      1.1  jmmv 
    418      1.1  jmmv     va_start(ap, fmt);
    419      1.1  jmmv     err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap);
    420      1.1  jmmv     va_end(ap);
    421      1.1  jmmv     if (atf_is_error(err))
    422      1.1  jmmv         abort();
    423      1.1  jmmv 
    424  1.1.1.3  jmmv     atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
    425      1.1  jmmv 
    426      1.1  jmmv     atf_tcr_fini(&tcr);
    427      1.1  jmmv 
    428  1.1.1.3  jmmv     exit(EXIT_FAILURE);
    429      1.1  jmmv }
    430      1.1  jmmv 
    431      1.1  jmmv void
    432      1.1  jmmv atf_tc_fail_nonfatal(const char *fmt, ...)
    433      1.1  jmmv {
    434      1.1  jmmv     va_list ap;
    435      1.1  jmmv 
    436      1.1  jmmv     va_start(ap, fmt);
    437      1.1  jmmv     vfprintf(stderr, fmt, ap);
    438      1.1  jmmv     va_end(ap);
    439      1.1  jmmv     fprintf(stderr, "\n");
    440      1.1  jmmv 
    441      1.1  jmmv     current_tc_fail_count++;
    442      1.1  jmmv }
    443      1.1  jmmv 
    444      1.1  jmmv void
    445      1.1  jmmv atf_tc_fail_check(const char *file, int line, const char *fmt, ...)
    446      1.1  jmmv {
    447      1.1  jmmv     va_list ap;
    448      1.1  jmmv 
    449      1.1  jmmv     va_start(ap, fmt);
    450      1.1  jmmv     fail_internal(file, line, "Check failed", "*** ", fmt, ap,
    451  1.1.1.2  jmmv                   tc_fail_nonfatal, atf_tc_fail_nonfatal);
    452      1.1  jmmv     va_end(ap);
    453      1.1  jmmv }
    454      1.1  jmmv 
    455      1.1  jmmv void
    456      1.1  jmmv atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...)
    457      1.1  jmmv {
    458      1.1  jmmv     va_list ap;
    459      1.1  jmmv 
    460  1.1.1.2  jmmv     atf_reset_exit_checks();
    461  1.1.1.2  jmmv 
    462      1.1  jmmv     va_start(ap, fmt);
    463      1.1  jmmv     fail_internal(file, line, "Requirement failed", "", fmt, ap,
    464  1.1.1.2  jmmv                   tc_fail, atf_tc_fail);
    465      1.1  jmmv     va_end(ap);
    466      1.1  jmmv 
    467      1.1  jmmv     UNREACHABLE;
    468      1.1  jmmv     abort();
    469      1.1  jmmv }
    470      1.1  jmmv 
    471      1.1  jmmv static
    472      1.1  jmmv void
    473      1.1  jmmv fail_internal(const char *file, int line, const char *reason,
    474      1.1  jmmv               const char *prefix, const char *fmt, va_list ap,
    475  1.1.1.2  jmmv               void (*failfunc)(atf_dynstr_t *),
    476  1.1.1.2  jmmv               void (*backupfunc)(const char *, ...))
    477      1.1  jmmv {
    478      1.1  jmmv     va_list ap2;
    479      1.1  jmmv     atf_error_t err;
    480      1.1  jmmv     atf_dynstr_t msg;
    481      1.1  jmmv 
    482      1.1  jmmv     err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line,
    483      1.1  jmmv                               reason);
    484      1.1  jmmv     if (atf_is_error(err))
    485      1.1  jmmv         goto backup;
    486      1.1  jmmv 
    487      1.1  jmmv     va_copy(ap2, ap);
    488      1.1  jmmv     err = atf_dynstr_append_ap(&msg, fmt, ap2);
    489      1.1  jmmv     va_end(ap2);
    490      1.1  jmmv     if (atf_is_error(err)) {
    491      1.1  jmmv         atf_dynstr_fini(&msg);
    492      1.1  jmmv         goto backup;
    493      1.1  jmmv     }
    494      1.1  jmmv 
    495      1.1  jmmv     va_copy(ap2, ap);
    496  1.1.1.2  jmmv     failfunc(&msg);
    497      1.1  jmmv     return;
    498      1.1  jmmv 
    499      1.1  jmmv backup:
    500  1.1.1.2  jmmv     atf_error_free(err);
    501      1.1  jmmv     va_copy(ap2, ap);
    502  1.1.1.2  jmmv     backupfunc(fmt, ap2);
    503      1.1  jmmv     va_end(ap2);
    504      1.1  jmmv }
    505      1.1  jmmv 
    506      1.1  jmmv void
    507      1.1  jmmv atf_tc_pass(void)
    508      1.1  jmmv {
    509      1.1  jmmv     atf_tcr_t tcr;
    510      1.1  jmmv     atf_error_t err;
    511      1.1  jmmv 
    512      1.1  jmmv     PRE(current_tc != NULL);
    513      1.1  jmmv 
    514      1.1  jmmv     err = atf_tcr_init(&tcr, atf_tcr_passed_state);
    515      1.1  jmmv     if (atf_is_error(err))
    516      1.1  jmmv         abort();
    517      1.1  jmmv 
    518  1.1.1.3  jmmv     atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
    519      1.1  jmmv 
    520      1.1  jmmv     atf_tcr_fini(&tcr);
    521      1.1  jmmv 
    522      1.1  jmmv     exit(EXIT_SUCCESS);
    523      1.1  jmmv }
    524      1.1  jmmv 
    525      1.1  jmmv void
    526      1.1  jmmv atf_tc_require_prog(const char *prog)
    527      1.1  jmmv {
    528      1.1  jmmv     atf_error_t err;
    529      1.1  jmmv 
    530      1.1  jmmv     err = check_prog(prog, NULL);
    531  1.1.1.2  jmmv     if (atf_is_error(err)) {
    532  1.1.1.2  jmmv         atf_error_free(err);
    533      1.1  jmmv         atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */
    534  1.1.1.2  jmmv     }
    535      1.1  jmmv }
    536      1.1  jmmv 
    537      1.1  jmmv void
    538      1.1  jmmv atf_tc_skip(const char *fmt, ...)
    539      1.1  jmmv {
    540      1.1  jmmv     va_list ap;
    541      1.1  jmmv     atf_tcr_t tcr;
    542      1.1  jmmv     atf_error_t err;
    543      1.1  jmmv 
    544      1.1  jmmv     PRE(current_tc != NULL);
    545      1.1  jmmv 
    546      1.1  jmmv     va_start(ap, fmt);
    547      1.1  jmmv     err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap);
    548      1.1  jmmv     va_end(ap);
    549      1.1  jmmv     if (atf_is_error(err))
    550      1.1  jmmv         abort();
    551      1.1  jmmv 
    552  1.1.1.3  jmmv     atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
    553      1.1  jmmv 
    554      1.1  jmmv     atf_tcr_fini(&tcr);
    555      1.1  jmmv 
    556      1.1  jmmv     exit(EXIT_SUCCESS);
    557      1.1  jmmv }
    558