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