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