Home | History | Annotate | Line # | Download | only in atf-c
      1 /*
      2  * Automated Testing Framework (atf)
      3  *
      4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      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.
     15  *
     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.
     28  */
     29 
     30 #include <sys/types.h>
     31 #include <sys/stat.h>
     32 #include <sys/uio.h>
     33 
     34 #include <errno.h>
     35 #include <fcntl.h>
     36 #include <stdarg.h>
     37 #include <stdbool.h>
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <string.h>
     41 #include <unistd.h>
     42 
     43 #include "atf-c/defs.h"
     44 #include "atf-c/error.h"
     45 #include "atf-c/tc.h"
     46 
     47 #include "detail/env.h"
     48 #include "detail/fs.h"
     49 #include "detail/map.h"
     50 #include "detail/sanity.h"
     51 #include "detail/text.h"
     52 
     53 /* ---------------------------------------------------------------------
     54  * Auxiliary functions.
     55  * --------------------------------------------------------------------- */
     56 
     57 enum expect_type {
     58     EXPECT_PASS,
     59     EXPECT_FAIL,
     60     EXPECT_EXIT,
     61     EXPECT_SIGNAL,
     62     EXPECT_DEATH,
     63     EXPECT_TIMEOUT,
     64 };
     65 
     66 struct context {
     67     const atf_tc_t *tc;
     68     const char *resfile;
     69     size_t fail_count;
     70 
     71     enum expect_type expect;
     72     atf_dynstr_t expect_reason;
     73     size_t expect_previous_fail_count;
     74     size_t expect_fail_count;
     75     int expect_exitcode;
     76     int expect_signo;
     77 };
     78 
     79 static void context_init(struct context *, const atf_tc_t *, const char *);
     80 static void check_fatal_error(atf_error_t);
     81 static void report_fatal_error(const char *, ...)
     82     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2)
     83     ATF_DEFS_ATTRIBUTE_NORETURN;
     84 static atf_error_t write_resfile(const int, const char *, const int,
     85                                  const atf_dynstr_t *);
     86 static void create_resfile(const char *, const char *, const int,
     87                            atf_dynstr_t *);
     88 static void error_in_expect(struct context *, const char *, ...)
     89     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 3)
     90     ATF_DEFS_ATTRIBUTE_NORETURN;
     91 static void validate_expect(struct context *);
     92 static void expected_failure(struct context *, atf_dynstr_t *)
     93     ATF_DEFS_ATTRIBUTE_NORETURN;
     94 static void fail_requirement(struct context *, atf_dynstr_t *)
     95     ATF_DEFS_ATTRIBUTE_NORETURN;
     96 static void fail_check(struct context *, atf_dynstr_t *);
     97 static void pass(struct context *)
     98     ATF_DEFS_ATTRIBUTE_NORETURN;
     99 static void skip(struct context *, atf_dynstr_t *)
    100     ATF_DEFS_ATTRIBUTE_NORETURN;
    101 static void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
    102                              const char *, va_list)
    103     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 0);
    104 static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
    105                               const char *, ...)
    106     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 5);
    107 static void errno_test(struct context *, const char *, const size_t,
    108                        const int, const char *, const bool,
    109                        void (*)(struct context *, atf_dynstr_t *));
    110 static atf_error_t check_prog_in_dir(const char *, void *);
    111 static atf_error_t check_prog(struct context *, const char *);
    112 
    113 static void
    114 context_init(struct context *ctx, const atf_tc_t *tc, const char *resfile)
    115 {
    116     ctx->tc = tc;
    117     ctx->resfile = resfile;
    118     ctx->fail_count = 0;
    119     ctx->expect = EXPECT_PASS;
    120     check_fatal_error(atf_dynstr_init(&ctx->expect_reason));
    121     ctx->expect_previous_fail_count = 0;
    122     ctx->expect_fail_count = 0;
    123     ctx->expect_exitcode = 0;
    124     ctx->expect_signo = 0;
    125 }
    126 
    127 static void
    128 check_fatal_error(atf_error_t err)
    129 {
    130     if (atf_is_error(err)) {
    131         char buf[1024];
    132         atf_error_format(err, buf, sizeof(buf));
    133         fprintf(stderr, "FATAL ERROR: %s\n", buf);
    134         atf_error_free(err);
    135         abort();
    136     }
    137 }
    138 
    139 static void
    140 report_fatal_error(const char *msg, ...)
    141 {
    142     va_list ap;
    143     fprintf(stderr, "FATAL ERROR: ");
    144 
    145     va_start(ap, msg);
    146     vfprintf(stderr, msg, ap);
    147     va_end(ap);
    148 
    149     fprintf(stderr, "\n");
    150     abort();
    151 }
    152 
    153 /** Writes to a results file.
    154  *
    155  * The results file is supposed to be already open.
    156  *
    157  * This function returns an error code instead of exiting in case of error
    158  * because the caller needs to clean up the reason object before terminating.
    159  */
    160 static atf_error_t
    161 write_resfile(const int fd, const char *result, const int arg,
    162               const atf_dynstr_t *reason)
    163 {
    164     static char NL[] = "\n", CS[] = ": ";
    165     char buf[64];
    166     const char *r;
    167     struct iovec iov[5];
    168     ssize_t ret;
    169     int count = 0;
    170 
    171     INV(arg == -1 || reason != NULL);
    172 
    173 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
    174     iov[count].iov_base = UNCONST(result);
    175     iov[count++].iov_len = strlen(result);
    176 
    177     if (reason != NULL) {
    178         if (arg != -1) {
    179             iov[count].iov_base = buf;
    180             iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg);
    181         }
    182 
    183         iov[count].iov_base = CS;
    184         iov[count++].iov_len = sizeof(CS) - 1;
    185 
    186         r = atf_dynstr_cstring(reason);
    187         iov[count].iov_base = UNCONST(r);
    188         iov[count++].iov_len = strlen(r);
    189     }
    190 #undef UNCONST
    191 
    192     iov[count].iov_base = NL;
    193     iov[count++].iov_len = sizeof(NL) - 1;
    194 
    195     while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR)
    196         continue; /* Retry. */
    197     if (ret != -1)
    198         return atf_no_error();
    199 
    200     return atf_libc_error(
    201         errno, "Failed to write results file; result %s, reason %s", result,
    202         reason == NULL ? "null" : atf_dynstr_cstring(reason));
    203 }
    204 
    205 /** Creates a results file.
    206  *
    207  * The input reason is released in all cases.
    208  *
    209  * An error in this function is considered to be fatal, hence why it does
    210  * not return any error code.
    211  */
    212 static void
    213 create_resfile(const char *resfile, const char *result, const int arg,
    214                atf_dynstr_t *reason)
    215 {
    216     atf_error_t err;
    217 
    218     if (strcmp("/dev/stdout", resfile) == 0) {
    219         err = write_resfile(STDOUT_FILENO, result, arg, reason);
    220     } else if (strcmp("/dev/stderr", resfile) == 0) {
    221         err = write_resfile(STDERR_FILENO, result, arg, reason);
    222     } else {
    223         const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC,
    224             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    225         if (fd == -1) {
    226             err = atf_libc_error(errno, "Cannot create results file '%s'",
    227                                  resfile);
    228         } else {
    229             err = write_resfile(fd, result, arg, reason);
    230             close(fd);
    231         }
    232     }
    233 
    234     if (reason != NULL)
    235         atf_dynstr_fini(reason);
    236 
    237     check_fatal_error(err);
    238 }
    239 
    240 /** Fails a test case if validate_expect fails. */
    241 static void
    242 error_in_expect(struct context *ctx, const char *fmt, ...)
    243 {
    244     atf_dynstr_t reason;
    245     va_list ap;
    246 
    247     va_start(ap, fmt);
    248     format_reason_ap(&reason, NULL, 0, fmt, ap);
    249     va_end(ap);
    250 
    251     ctx->expect = EXPECT_PASS;  /* Ensure fail_requirement really fails. */
    252     fail_requirement(ctx, &reason);
    253 }
    254 
    255 /** Ensures that the "expect" state is correct.
    256  *
    257  * Call this function before modifying the current value of expect.
    258  */
    259 static void
    260 validate_expect(struct context *ctx)
    261 {
    262     if (ctx->expect == EXPECT_DEATH) {
    263         error_in_expect(ctx, "Test case was expected to terminate abruptly "
    264             "but it continued execution");
    265     } else if (ctx->expect == EXPECT_EXIT) {
    266         error_in_expect(ctx, "Test case was expected to exit cleanly but it "
    267             "continued execution");
    268     } else if (ctx->expect == EXPECT_FAIL) {
    269         if (ctx->expect_fail_count == ctx->expect_previous_fail_count)
    270             error_in_expect(ctx, "Test case was expecting a failure but none "
    271                 "were raised");
    272         else
    273             INV(ctx->expect_fail_count > ctx->expect_previous_fail_count);
    274     } else if (ctx->expect == EXPECT_PASS) {
    275         /* Nothing to validate. */
    276     } else if (ctx->expect == EXPECT_SIGNAL) {
    277         error_in_expect(ctx, "Test case was expected to receive a termination "
    278             "signal but it continued execution");
    279     } else if (ctx->expect == EXPECT_TIMEOUT) {
    280         error_in_expect(ctx, "Test case was expected to hang but it continued "
    281             "execution");
    282     } else
    283         UNREACHABLE;
    284 }
    285 
    286 static void
    287 expected_failure(struct context *ctx, atf_dynstr_t *reason)
    288 {
    289     check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ",
    290         atf_dynstr_cstring(&ctx->expect_reason)));
    291     create_resfile(ctx->resfile, "expected_failure", -1, reason);
    292     exit(EXIT_SUCCESS);
    293 }
    294 
    295 static void
    296 fail_requirement(struct context *ctx, atf_dynstr_t *reason)
    297 {
    298     if (ctx->expect == EXPECT_FAIL) {
    299         expected_failure(ctx, reason);
    300     } else if (ctx->expect == EXPECT_PASS) {
    301         create_resfile(ctx->resfile, "failed", -1, reason);
    302         exit(EXIT_FAILURE);
    303     } else {
    304         error_in_expect(ctx, "Test case raised a failure but was not "
    305             "expecting one; reason was %s", atf_dynstr_cstring(reason));
    306     }
    307     UNREACHABLE;
    308 }
    309 
    310 static void
    311 fail_check(struct context *ctx, atf_dynstr_t *reason)
    312 {
    313     if (ctx->expect == EXPECT_FAIL) {
    314         fprintf(stderr, "*** Expected check failure: %s: %s\n",
    315             atf_dynstr_cstring(&ctx->expect_reason),
    316             atf_dynstr_cstring(reason));
    317         ctx->expect_fail_count++;
    318     } else if (ctx->expect == EXPECT_PASS) {
    319         fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason));
    320         ctx->fail_count++;
    321     } else {
    322         error_in_expect(ctx, "Test case raised a failure but was not "
    323             "expecting one; reason was %s", atf_dynstr_cstring(reason));
    324     }
    325 
    326     atf_dynstr_fini(reason);
    327 }
    328 
    329 static void
    330 pass(struct context *ctx)
    331 {
    332     if (ctx->expect == EXPECT_FAIL) {
    333         error_in_expect(ctx, "Test case was expecting a failure but got "
    334             "a pass instead");
    335     } else if (ctx->expect == EXPECT_PASS) {
    336         create_resfile(ctx->resfile, "passed", -1, NULL);
    337         exit(EXIT_SUCCESS);
    338     } else {
    339         error_in_expect(ctx, "Test case asked to explicitly pass but was "
    340             "not expecting such condition");
    341     }
    342     UNREACHABLE;
    343 }
    344 
    345 static void
    346 skip(struct context *ctx, atf_dynstr_t *reason)
    347 {
    348     if (ctx->expect == EXPECT_PASS) {
    349         create_resfile(ctx->resfile, "skipped", -1, reason);
    350         exit(EXIT_SUCCESS);
    351     } else {
    352         error_in_expect(ctx, "Can only skip a test case when running in "
    353             "expect pass mode");
    354     }
    355     UNREACHABLE;
    356 }
    357 
    358 /** Formats a failure/skip reason message.
    359  *
    360  * The formatted reason is stored in out_reason.  out_reason is initialized
    361  * in this function and is supposed to be released by the caller.  In general,
    362  * the reason will eventually be fed to create_resfile, which will release
    363  * it.
    364  *
    365  * Errors in this function are fatal.  Rationale being: reasons are used to
    366  * create results files; if we can't format the reason correctly, the result
    367  * of the test program will be bogus.  So it's better to just exit with a
    368  * fatal error.
    369  */
    370 static void
    371 format_reason_ap(atf_dynstr_t *out_reason,
    372                  const char *source_file, const size_t source_line,
    373                  const char *reason, va_list ap)
    374 {
    375     atf_error_t err;
    376 
    377     if (source_file != NULL) {
    378         err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
    379                                   source_line);
    380     } else {
    381         PRE(source_line == 0);
    382         err = atf_dynstr_init(out_reason);
    383     }
    384 
    385     if (!atf_is_error(err)) {
    386         va_list ap2;
    387         va_copy(ap2, ap);
    388         err = atf_dynstr_append_ap(out_reason, reason, ap2);
    389         va_end(ap2);
    390     }
    391 
    392     check_fatal_error(err);
    393 }
    394 
    395 static void
    396 format_reason_fmt(atf_dynstr_t *out_reason,
    397                   const char *source_file, const size_t source_line,
    398                   const char *reason, ...)
    399 {
    400     va_list ap;
    401 
    402     va_start(ap, reason);
    403     format_reason_ap(out_reason, source_file, source_line, reason, ap);
    404     va_end(ap);
    405 }
    406 
    407 static void
    408 errno_test(struct context *ctx, const char *file, const size_t line,
    409            const int exp_errno, const char *expr_str,
    410            const bool expr_result,
    411            void (*fail_func)(struct context *, atf_dynstr_t *))
    412 {
    413     const int actual_errno = errno;
    414 
    415     if (expr_result) {
    416         if (exp_errno != actual_errno) {
    417             atf_dynstr_t reason;
    418 
    419             format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
    420                 "in %s", exp_errno, actual_errno, expr_str);
    421             fail_func(ctx, &reason);
    422         }
    423     } else {
    424         atf_dynstr_t reason;
    425 
    426         format_reason_fmt(&reason, file, line, "Expected true value in %s",
    427             expr_str);
    428         fail_func(ctx, &reason);
    429     }
    430 }
    431 
    432 struct prog_found_pair {
    433     const char *prog;
    434     bool found;
    435 };
    436 
    437 static atf_error_t
    438 check_prog_in_dir(const char *dir, void *data)
    439 {
    440     struct prog_found_pair *pf = data;
    441     atf_error_t err;
    442 
    443     if (pf->found)
    444         err = atf_no_error();
    445     else {
    446         atf_fs_path_t p;
    447 
    448         err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
    449         if (atf_is_error(err))
    450             goto out_p;
    451 
    452         err = atf_fs_eaccess(&p, atf_fs_access_x);
    453         if (!atf_is_error(err))
    454             pf->found = true;
    455         else {
    456             atf_error_free(err);
    457             INV(!pf->found);
    458             err = atf_no_error();
    459         }
    460 
    461 out_p:
    462         atf_fs_path_fini(&p);
    463     }
    464 
    465     return err;
    466 }
    467 
    468 static atf_error_t
    469 check_prog(struct context *ctx, const char *prog)
    470 {
    471     atf_error_t err;
    472     atf_fs_path_t p;
    473 
    474     err = atf_fs_path_init_fmt(&p, "%s", prog);
    475     if (atf_is_error(err))
    476         goto out;
    477 
    478     if (atf_fs_path_is_absolute(&p)) {
    479         err = atf_fs_eaccess(&p, atf_fs_access_x);
    480         if (atf_is_error(err)) {
    481             atf_dynstr_t reason;
    482 
    483             atf_error_free(err);
    484             atf_fs_path_fini(&p);
    485             format_reason_fmt(&reason, NULL, 0, "The required program %s could "
    486                 "not be found", prog);
    487             skip(ctx, &reason);
    488         }
    489     } else {
    490         const char *path = atf_env_get("PATH");
    491         struct prog_found_pair pf;
    492         atf_fs_path_t bp;
    493 
    494         err = atf_fs_path_branch_path(&p, &bp);
    495         if (atf_is_error(err))
    496             goto out_p;
    497 
    498         if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
    499             atf_fs_path_fini(&bp);
    500             atf_fs_path_fini(&p);
    501 
    502             report_fatal_error("Relative paths are not allowed when searching "
    503                 "for a program (%s)", prog);
    504             UNREACHABLE;
    505         }
    506 
    507         pf.prog = prog;
    508         pf.found = false;
    509         err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
    510         if (atf_is_error(err))
    511             goto out_bp;
    512 
    513         if (!pf.found) {
    514             atf_dynstr_t reason;
    515 
    516             atf_fs_path_fini(&bp);
    517             atf_fs_path_fini(&p);
    518             format_reason_fmt(&reason, NULL, 0, "The required program %s could "
    519                 "not be found in the PATH", prog);
    520             fail_requirement(ctx, &reason);
    521         }
    522 
    523 out_bp:
    524         atf_fs_path_fini(&bp);
    525     }
    526 
    527 out_p:
    528     atf_fs_path_fini(&p);
    529 out:
    530     return err;
    531 }
    532 
    533 /* ---------------------------------------------------------------------
    534  * The "atf_tc" type.
    535  * --------------------------------------------------------------------- */
    536 
    537 struct atf_tc_impl {
    538     const char *m_ident;
    539 
    540     atf_map_t m_vars;
    541     atf_map_t m_config;
    542 
    543     atf_tc_head_t m_head;
    544     atf_tc_body_t m_body;
    545     atf_tc_cleanup_t m_cleanup;
    546 };
    547 
    548 /*
    549  * Constructors/destructors.
    550  */
    551 
    552 atf_error_t
    553 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
    554             atf_tc_body_t body, atf_tc_cleanup_t cleanup,
    555             const char *const *config)
    556 {
    557     atf_error_t err;
    558 
    559     tc->pimpl = malloc(sizeof(struct atf_tc_impl));
    560     if (tc->pimpl == NULL) {
    561         err = atf_no_memory_error();
    562         goto err;
    563     }
    564 
    565     tc->pimpl->m_ident = ident;
    566     tc->pimpl->m_head = head;
    567     tc->pimpl->m_body = body;
    568     tc->pimpl->m_cleanup = cleanup;
    569 
    570     err = atf_map_init_charpp(&tc->pimpl->m_config, config);
    571     if (atf_is_error(err))
    572         goto err;
    573 
    574     err = atf_map_init(&tc->pimpl->m_vars);
    575     if (atf_is_error(err))
    576         goto err_vars;
    577 
    578     err = atf_tc_set_md_var(tc, "ident", "%s", ident);
    579     if (atf_is_error(err))
    580         goto err_map;
    581 
    582     if (cleanup != NULL) {
    583         err = atf_tc_set_md_var(tc, "has.cleanup", "true");
    584         if (atf_is_error(err))
    585             goto err_map;
    586     }
    587 
    588     /* XXX Should the head be able to return error codes? */
    589     if (tc->pimpl->m_head != NULL)
    590         tc->pimpl->m_head(tc);
    591 
    592     if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
    593         report_fatal_error("Test case head modified the read-only 'ident' "
    594             "property");
    595         UNREACHABLE;
    596     }
    597 
    598     INV(!atf_is_error(err));
    599     return err;
    600 
    601 err_map:
    602     atf_map_fini(&tc->pimpl->m_vars);
    603 err_vars:
    604     atf_map_fini(&tc->pimpl->m_config);
    605 err:
    606     return err;
    607 }
    608 
    609 atf_error_t
    610 atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
    611                  const char *const *config)
    612 {
    613     return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
    614                        pack->m_cleanup, config);
    615 }
    616 
    617 void
    618 atf_tc_fini(atf_tc_t *tc)
    619 {
    620     atf_map_fini(&tc->pimpl->m_vars);
    621     free(tc->pimpl);
    622 }
    623 
    624 /*
    625  * Getters.
    626  */
    627 
    628 const char *
    629 atf_tc_get_ident(const atf_tc_t *tc)
    630 {
    631     return tc->pimpl->m_ident;
    632 }
    633 
    634 const char *
    635 atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
    636 {
    637     const char *val;
    638     atf_map_citer_t iter;
    639 
    640     PRE(atf_tc_has_config_var(tc, name));
    641     iter = atf_map_find_c(&tc->pimpl->m_config, name);
    642     val = atf_map_citer_data(iter);
    643     INV(val != NULL);
    644 
    645     return val;
    646 }
    647 
    648 const char *
    649 atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
    650                          const char *defval)
    651 {
    652     const char *val;
    653 
    654     if (!atf_tc_has_config_var(tc, name))
    655         val = defval;
    656     else
    657         val = atf_tc_get_config_var(tc, name);
    658 
    659     return val;
    660 }
    661 
    662 bool
    663 atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
    664 {
    665     bool val;
    666     const char *strval;
    667     atf_error_t err;
    668 
    669     strval = atf_tc_get_config_var(tc, name);
    670     err = atf_text_to_bool(strval, &val);
    671     if (atf_is_error(err)) {
    672         atf_error_free(err);
    673         atf_tc_fail("Configuration variable %s does not have a valid "
    674                     "boolean value; found %s", name, strval);
    675     }
    676 
    677     return val;
    678 }
    679 
    680 bool
    681 atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
    682                                  const bool defval)
    683 {
    684     bool val;
    685 
    686     if (!atf_tc_has_config_var(tc, name))
    687         val = defval;
    688     else
    689         val = atf_tc_get_config_var_as_bool(tc, name);
    690 
    691     return val;
    692 }
    693 
    694 long
    695 atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
    696 {
    697     long val;
    698     const char *strval;
    699     atf_error_t err;
    700 
    701     strval = atf_tc_get_config_var(tc, name);
    702     err = atf_text_to_long(strval, &val);
    703     if (atf_is_error(err)) {
    704         atf_error_free(err);
    705         atf_tc_fail("Configuration variable %s does not have a valid "
    706                     "long value; found %s", name, strval);
    707     }
    708 
    709     return val;
    710 }
    711 
    712 long
    713 atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
    714                                  const long defval)
    715 {
    716     long val;
    717 
    718     if (!atf_tc_has_config_var(tc, name))
    719         val = defval;
    720     else
    721         val = atf_tc_get_config_var_as_long(tc, name);
    722 
    723     return val;
    724 }
    725 
    726 const char *
    727 atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
    728 {
    729     const char *val;
    730     atf_map_citer_t iter;
    731 
    732     PRE(atf_tc_has_md_var(tc, name));
    733     iter = atf_map_find_c(&tc->pimpl->m_vars, name);
    734     val = atf_map_citer_data(iter);
    735     INV(val != NULL);
    736 
    737     return val;
    738 }
    739 
    740 char **
    741 atf_tc_get_md_vars(const atf_tc_t *tc)
    742 {
    743     return atf_map_to_charpp(&tc->pimpl->m_vars);
    744 }
    745 
    746 bool
    747 atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
    748 {
    749     atf_map_citer_t end, iter;
    750 
    751     iter = atf_map_find_c(&tc->pimpl->m_config, name);
    752     end = atf_map_end_c(&tc->pimpl->m_config);
    753     return !atf_equal_map_citer_map_citer(iter, end);
    754 }
    755 
    756 bool
    757 atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
    758 {
    759     atf_map_citer_t end, iter;
    760 
    761     iter = atf_map_find_c(&tc->pimpl->m_vars, name);
    762     end = atf_map_end_c(&tc->pimpl->m_vars);
    763     return !atf_equal_map_citer_map_citer(iter, end);
    764 }
    765 
    766 /*
    767  * Modifiers.
    768  */
    769 
    770 atf_error_t
    771 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
    772 {
    773     atf_error_t err;
    774     char *value;
    775     va_list ap;
    776 
    777     va_start(ap, fmt);
    778     err = atf_text_format_ap(&value, fmt, ap);
    779     va_end(ap);
    780 
    781     if (!atf_is_error(err))
    782         err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
    783     else
    784         free(value);
    785 
    786     return err;
    787 }
    788 
    789 /* ---------------------------------------------------------------------
    790  * Free functions, as they should be publicly but they can't.
    791  * --------------------------------------------------------------------- */
    792 
    793 static void _atf_tc_fail(struct context *, const char *, va_list)
    794     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0)
    795     ATF_DEFS_ATTRIBUTE_NORETURN;
    796 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list)
    797     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
    798 static void _atf_tc_fail_check(struct context *, const char *, const size_t,
    799     const char *, va_list)
    800     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 0);
    801 static void _atf_tc_fail_requirement(struct context *, const char *,
    802     const size_t, const char *, va_list)
    803     ATF_DEFS_ATTRIBUTE_NORETURN
    804     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 0);
    805 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
    806 static void _atf_tc_require_prog(struct context *, const char *);
    807 static void _atf_tc_skip(struct context *, const char *, va_list)
    808     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0)
    809     ATF_DEFS_ATTRIBUTE_NORETURN;
    810 static void _atf_tc_check_errno(struct context *, const char *, const size_t,
    811     const int, const char *, const bool);
    812 static void _atf_tc_require_errno(struct context *, const char *, const size_t,
    813     const int, const char *, const bool);
    814 static void _atf_tc_expect_pass(struct context *);
    815 static void _atf_tc_expect_fail(struct context *, const char *, va_list)
    816     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
    817 static void _atf_tc_expect_exit(struct context *, const int, const char *,
    818     va_list) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(3, 0);
    819 static void _atf_tc_expect_signal(struct context *, const int, const char *,
    820     va_list) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(3, 0);
    821 static void _atf_tc_expect_death(struct context *, const char *,
    822     va_list) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
    823 
    824 static void
    825 _atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
    826 {
    827     va_list ap2;
    828     atf_dynstr_t reason;
    829 
    830     va_copy(ap2, ap);
    831     format_reason_ap(&reason, NULL, 0, fmt, ap2);
    832     va_end(ap2);
    833 
    834     fail_requirement(ctx, &reason);
    835     UNREACHABLE;
    836 }
    837 
    838 static void
    839 _atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
    840 {
    841     va_list ap2;
    842     atf_dynstr_t reason;
    843 
    844     va_copy(ap2, ap);
    845     format_reason_ap(&reason, NULL, 0, fmt, ap2);
    846     va_end(ap2);
    847 
    848     fail_check(ctx, &reason);
    849 }
    850 
    851 static void
    852 _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
    853                    const char *fmt, va_list ap)
    854 {
    855     va_list ap2;
    856     atf_dynstr_t reason;
    857 
    858     va_copy(ap2, ap);
    859     format_reason_ap(&reason, file, line, fmt, ap2);
    860     va_end(ap2);
    861 
    862     fail_check(ctx, &reason);
    863 }
    864 
    865 static void
    866 _atf_tc_fail_requirement(struct context *ctx, const char *file,
    867                          const size_t line, const char *fmt, va_list ap)
    868 {
    869     va_list ap2;
    870     atf_dynstr_t reason;
    871 
    872     va_copy(ap2, ap);
    873     format_reason_ap(&reason, file, line, fmt, ap2);
    874     va_end(ap2);
    875 
    876     fail_requirement(ctx, &reason);
    877     UNREACHABLE;
    878 }
    879 
    880 static void
    881 _atf_tc_pass(struct context *ctx)
    882 {
    883     pass(ctx);
    884     UNREACHABLE;
    885 }
    886 
    887 static void
    888 _atf_tc_require_prog(struct context *ctx, const char *prog)
    889 {
    890     check_fatal_error(check_prog(ctx, prog));
    891 }
    892 
    893 static void
    894 _atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
    895 {
    896     atf_dynstr_t reason;
    897     va_list ap2;
    898 
    899     va_copy(ap2, ap);
    900     format_reason_ap(&reason, NULL, 0, fmt, ap2);
    901     va_end(ap2);
    902 
    903     skip(ctx, &reason);
    904 }
    905 
    906 static void
    907 _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
    908                     const int exp_errno, const char *expr_str,
    909                     const bool expr_result)
    910 {
    911     errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
    912 }
    913 
    914 static void
    915 _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
    916                       const int exp_errno, const char *expr_str,
    917                       const bool expr_result)
    918 {
    919     errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
    920         fail_requirement);
    921 }
    922 
    923 static void
    924 _atf_tc_expect_pass(struct context *ctx)
    925 {
    926     validate_expect(ctx);
    927 
    928     ctx->expect = EXPECT_PASS;
    929 }
    930 
    931 static void
    932 _atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
    933 {
    934     va_list ap2;
    935 
    936     validate_expect(ctx);
    937 
    938     ctx->expect = EXPECT_FAIL;
    939     atf_dynstr_fini(&ctx->expect_reason);
    940     va_copy(ap2, ap);
    941     check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
    942     va_end(ap2);
    943     ctx->expect_previous_fail_count = ctx->expect_fail_count;
    944 }
    945 
    946 static void
    947 _atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
    948                     va_list ap)
    949 {
    950     va_list ap2;
    951     atf_dynstr_t formatted;
    952 
    953     validate_expect(ctx);
    954 
    955     ctx->expect = EXPECT_EXIT;
    956     va_copy(ap2, ap);
    957     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
    958     va_end(ap2);
    959 
    960     create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
    961 }
    962 
    963 static void
    964 _atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
    965                       va_list ap)
    966 {
    967     va_list ap2;
    968     atf_dynstr_t formatted;
    969 
    970     validate_expect(ctx);
    971 
    972     ctx->expect = EXPECT_SIGNAL;
    973     va_copy(ap2, ap);
    974     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
    975     va_end(ap2);
    976 
    977     create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
    978 }
    979 
    980 static void
    981 _atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
    982 {
    983     va_list ap2;
    984     atf_dynstr_t formatted;
    985 
    986     validate_expect(ctx);
    987 
    988     ctx->expect = EXPECT_DEATH;
    989     va_copy(ap2, ap);
    990     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
    991     va_end(ap2);
    992 
    993     create_resfile(ctx->resfile, "expected_death", -1, &formatted);
    994 }
    995 
    996 ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0)
    997 static void
    998 _atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
    999 {
   1000     va_list ap2;
   1001     atf_dynstr_t formatted;
   1002 
   1003     validate_expect(ctx);
   1004 
   1005     ctx->expect = EXPECT_TIMEOUT;
   1006     va_copy(ap2, ap);
   1007     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
   1008     va_end(ap2);
   1009 
   1010     create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
   1011 }
   1012 
   1013 /* ---------------------------------------------------------------------
   1014  * Free functions.
   1015  * --------------------------------------------------------------------- */
   1016 
   1017 static struct context Current;
   1018 
   1019 atf_error_t
   1020 atf_tc_run(const atf_tc_t *tc, const char *resfile)
   1021 {
   1022     context_init(&Current, tc, resfile);
   1023 
   1024     tc->pimpl->m_body(tc);
   1025 
   1026     validate_expect(&Current);
   1027 
   1028     if (Current.fail_count > 0) {
   1029         atf_dynstr_t reason;
   1030 
   1031         format_reason_fmt(&reason, NULL, 0, "%zu checks failed; see output for "
   1032             "more details", Current.fail_count);
   1033         fail_requirement(&Current, &reason);
   1034     } else if (Current.expect_fail_count > 0) {
   1035         atf_dynstr_t reason;
   1036 
   1037         format_reason_fmt(&reason, NULL, 0, "%zu checks failed as expected; "
   1038             "see output for more details", Current.expect_fail_count);
   1039         expected_failure(&Current, &reason);
   1040     } else {
   1041         pass(&Current);
   1042     }
   1043     UNREACHABLE;
   1044     return atf_no_error();
   1045 }
   1046 
   1047 atf_error_t
   1048 atf_tc_cleanup(const atf_tc_t *tc)
   1049 {
   1050     if (tc->pimpl->m_cleanup != NULL)
   1051         tc->pimpl->m_cleanup(tc);
   1052     return atf_no_error(); /* XXX */
   1053 }
   1054 
   1055 /* ---------------------------------------------------------------------
   1056  * Free functions that depend on Current.
   1057  * --------------------------------------------------------------------- */
   1058 
   1059 /*
   1060  * All the functions below provide delegates to other internal functions
   1061  * (prefixed by _) that take the current test case as an argument to
   1062  * prevent them from accessing global state.  This is to keep the side-
   1063  * effects of the internal functions clearer and easier to understand.
   1064  *
   1065  * The public API should never have hid the fact that it needs access to
   1066  * the current test case (other than maybe in the macros), but changing it
   1067  * is hard.  TODO: Revisit in the future.
   1068  */
   1069 
   1070 void
   1071 atf_tc_fail(const char *fmt, ...)
   1072 {
   1073     va_list ap;
   1074 
   1075     PRE(Current.tc != NULL);
   1076 
   1077     va_start(ap, fmt);
   1078     _atf_tc_fail(&Current, fmt, ap);
   1079     va_end(ap);
   1080 }
   1081 
   1082 void
   1083 atf_tc_fail_nonfatal(const char *fmt, ...)
   1084 {
   1085     va_list ap;
   1086 
   1087     PRE(Current.tc != NULL);
   1088 
   1089     va_start(ap, fmt);
   1090     _atf_tc_fail_nonfatal(&Current, fmt, ap);
   1091     va_end(ap);
   1092 }
   1093 
   1094 void
   1095 atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
   1096 {
   1097     va_list ap;
   1098 
   1099     PRE(Current.tc != NULL);
   1100 
   1101     va_start(ap, fmt);
   1102     _atf_tc_fail_check(&Current, file, line, fmt, ap);
   1103     va_end(ap);
   1104 }
   1105 
   1106 void
   1107 atf_tc_fail_requirement(const char *file, const size_t line,
   1108                         const char *fmt, ...)
   1109 {
   1110     va_list ap;
   1111 
   1112     PRE(Current.tc != NULL);
   1113 
   1114     va_start(ap, fmt);
   1115     _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
   1116     va_end(ap);
   1117 }
   1118 
   1119 void
   1120 atf_tc_pass(void)
   1121 {
   1122     PRE(Current.tc != NULL);
   1123 
   1124     _atf_tc_pass(&Current);
   1125 }
   1126 
   1127 void
   1128 atf_tc_require_prog(const char *prog)
   1129 {
   1130     PRE(Current.tc != NULL);
   1131 
   1132     _atf_tc_require_prog(&Current, prog);
   1133 }
   1134 
   1135 void
   1136 atf_tc_skip(const char *fmt, ...)
   1137 {
   1138     va_list ap;
   1139 
   1140     PRE(Current.tc != NULL);
   1141 
   1142     va_start(ap, fmt);
   1143     _atf_tc_skip(&Current, fmt, ap);
   1144     va_end(ap);
   1145 }
   1146 
   1147 void
   1148 atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
   1149                    const char *expr_str, const bool expr_result)
   1150 {
   1151     PRE(Current.tc != NULL);
   1152 
   1153     _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
   1154                         expr_result);
   1155 }
   1156 
   1157 void
   1158 atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
   1159                      const char *expr_str, const bool expr_result)
   1160 {
   1161     PRE(Current.tc != NULL);
   1162 
   1163     _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
   1164                           expr_result);
   1165 }
   1166 
   1167 void
   1168 atf_tc_expect_pass(void)
   1169 {
   1170     PRE(Current.tc != NULL);
   1171 
   1172     _atf_tc_expect_pass(&Current);
   1173 }
   1174 
   1175 void
   1176 atf_tc_expect_fail(const char *reason, ...)
   1177 {
   1178     va_list ap;
   1179 
   1180     PRE(Current.tc != NULL);
   1181 
   1182     va_start(ap, reason);
   1183     _atf_tc_expect_fail(&Current, reason, ap);
   1184     va_end(ap);
   1185 }
   1186 
   1187 void
   1188 atf_tc_expect_exit(const int exitcode, const char *reason, ...)
   1189 {
   1190     va_list ap;
   1191 
   1192     PRE(Current.tc != NULL);
   1193 
   1194     va_start(ap, reason);
   1195     _atf_tc_expect_exit(&Current, exitcode, reason, ap);
   1196     va_end(ap);
   1197 }
   1198 
   1199 void
   1200 atf_tc_expect_signal(const int signo, const char *reason, ...)
   1201 {
   1202     va_list ap;
   1203 
   1204     PRE(Current.tc != NULL);
   1205 
   1206     va_start(ap, reason);
   1207     _atf_tc_expect_signal(&Current, signo, reason, ap);
   1208     va_end(ap);
   1209 }
   1210 
   1211 void
   1212 atf_tc_expect_death(const char *reason, ...)
   1213 {
   1214     va_list ap;
   1215 
   1216     PRE(Current.tc != NULL);
   1217 
   1218     va_start(ap, reason);
   1219     _atf_tc_expect_death(&Current, reason, ap);
   1220     va_end(ap);
   1221 }
   1222 
   1223 void
   1224 atf_tc_expect_timeout(const char *reason, ...)
   1225 {
   1226     va_list ap;
   1227 
   1228     PRE(Current.tc != NULL);
   1229 
   1230     va_start(ap, reason);
   1231     _atf_tc_expect_timeout(&Current, reason, ap);
   1232     va_end(ap);
   1233 }
   1234