1157019Sdes/* Copyright (c) 2008 The NetBSD Foundation, Inc.
299051Sdes * All rights reserved.
357429Smarkm *
498684Sdes * Redistribution and use in source and binary forms, with or without
598684Sdes * modification, are permitted provided that the following conditions
676262Sgreen * are met:
798941Sdes * 1. Redistributions of source code must retain the above copyright
898941Sdes *    notice, this list of conditions and the following disclaimer.
992559Sdes * 2. Redistributions in binary form must reproduce the above copyright
1092559Sdes *    notice, this list of conditions and the following disclaimer in the
1192559Sdes *    documentation and/or other materials provided with the distribution.
1292559Sdes *
1392559Sdes * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
1499051Sdes * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1599051Sdes * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1699051Sdes * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17157019Sdes * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
1899051Sdes * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1992559Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20126271Sdes * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21147005Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2257429Smarkm * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2357429Smarkm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2469591Sgreen * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
2592559Sdes
2692559Sdes#include "atf-c/tc.h"
2792559Sdes
2892559Sdes#include <sys/types.h>
2957429Smarkm#include <sys/stat.h>
3092559Sdes#include <sys/uio.h>
31124211Sdes
3292559Sdes#include <errno.h>
3392559Sdes#include <fcntl.h>
3457429Smarkm#include <stdarg.h>
35149753Sdes#include <stdbool.h>
3692559Sdes#include <stdint.h>
3792559Sdes#include <stdio.h>
3857429Smarkm#include <stdlib.h>
3992559Sdes#include <string.h>
4092559Sdes#include <unistd.h>
41124211Sdes
4299051Sdes#include "atf-c/defs.h"
4392559Sdes#include "atf-c/detail/env.h"
44137019Sdes#include "atf-c/detail/fs.h"
4592559Sdes#include "atf-c/detail/map.h"
4692559Sdes#include "atf-c/detail/sanity.h"
4792559Sdes#include "atf-c/detail/text.h"
4892559Sdes#include "atf-c/error.h"
4992559Sdes
5092559Sdes/* ---------------------------------------------------------------------
5192559Sdes * Auxiliary functions.
5276262Sgreen * --------------------------------------------------------------------- */
5392559Sdes
5492559Sdesenum expect_type {
5592559Sdes    EXPECT_PASS,
5692559Sdes    EXPECT_FAIL,
57124211Sdes    EXPECT_EXIT,
58124211Sdes    EXPECT_SIGNAL,
5957429Smarkm    EXPECT_DEATH,
60126009Sdes    EXPECT_TIMEOUT,
61126009Sdes};
6292559Sdes
6376262Sgreenstruct context {
6499315Sdes    const atf_tc_t *tc;
6595456Sdes    const char *resfile;
6657429Smarkm    int resfilefd;
6792559Sdes    size_t fail_count;
6898684Sdes
6957429Smarkm    enum expect_type expect;
7092559Sdes    atf_dynstr_t expect_reason;
71126277Sdes    size_t expect_previous_fail_count;
7257429Smarkm    size_t expect_fail_count;
73124211Sdes    int expect_exitcode;
74124211Sdes    int expect_signo;
75126277Sdes};
7657429Smarkm
77137019Sdesstatic void context_init(struct context *, const atf_tc_t *, const char *);
78137019Sdesstatic void context_set_resfile(struct context *, const char *);
79137019Sdesstatic void context_close_resfile(struct context *);
80137019Sdesstatic void check_fatal_error(atf_error_t);
81137019Sdesstatic void report_fatal_error(const char *, ...)
82137019Sdes    ATF_DEFS_ATTRIBUTE_NORETURN;
83137019Sdesstatic atf_error_t write_resfile(const int, const char *, const int,
84137019Sdes                                 const atf_dynstr_t *);
85127033Sdesstatic void create_resfile(struct context *, const char *, const int,
8692559Sdes                           atf_dynstr_t *);
87124211Sdesstatic void error_in_expect(struct context *, const char *, ...)
88124211Sdes    ATF_DEFS_ATTRIBUTE_NORETURN;
8999051Sdesstatic void validate_expect(struct context *);
9092559Sdesstatic void expected_failure(struct context *, atf_dynstr_t *)
9192559Sdes    ATF_DEFS_ATTRIBUTE_NORETURN;
9292559Sdesstatic void fail_requirement(struct context *, atf_dynstr_t *)
9392559Sdes    ATF_DEFS_ATTRIBUTE_NORETURN;
94126277Sdesstatic void fail_check(struct context *, atf_dynstr_t *);
9557429Smarkmstatic void pass(struct context *)
9698941Sdes    ATF_DEFS_ATTRIBUTE_NORETURN;
97106130Sdesstatic void skip(struct context *, atf_dynstr_t *)
98149753Sdes    ATF_DEFS_ATTRIBUTE_NORETURN;
99124211Sdesstatic void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
100124211Sdes                             const char *, va_list);
101124211Sdesstatic void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
102124211Sdes                              const char *, ...);
103124211Sdesstatic void errno_test(struct context *, const char *, const size_t,
104157019Sdes                       const int, const char *, const bool,
10565674Skris                       void (*)(struct context *, atf_dynstr_t *));
10692559Sdesstatic atf_error_t check_prog_in_dir(const char *, void *);
10792559Sdesstatic atf_error_t check_prog(struct context *, const char *);
10876262Sgreen
10992559Sdes/* No prototype in header for this one, it's a little sketchy (internal). */
11076262Sgreenvoid 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    create_resfile(ctx, "skipped", -1, reason);
385    context_close_resfile(ctx);
386    exit(EXIT_SUCCESS);
387}
388
389/** Formats a failure/skip reason message.
390 *
391 * The formatted reason is stored in out_reason.  out_reason is initialized
392 * in this function and is supposed to be released by the caller.  In general,
393 * the reason will eventually be fed to create_resfile, which will release
394 * it.
395 *
396 * Errors in this function are fatal.  Rationale being: reasons are used to
397 * create results files; if we can't format the reason correctly, the result
398 * of the test program will be bogus.  So it's better to just exit with a
399 * fatal error.
400 */
401static void
402format_reason_ap(atf_dynstr_t *out_reason,
403                 const char *source_file, const size_t source_line,
404                 const char *reason, va_list ap)
405{
406    atf_error_t err;
407
408    if (source_file != NULL) {
409        err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
410                                  source_line);
411    } else {
412        PRE(source_line == 0);
413        err = atf_dynstr_init(out_reason);
414    }
415
416    if (!atf_is_error(err)) {
417        va_list ap2;
418        va_copy(ap2, ap);
419        err = atf_dynstr_append_ap(out_reason, reason, ap2);
420        va_end(ap2);
421    }
422
423    check_fatal_error(err);
424}
425
426static void
427format_reason_fmt(atf_dynstr_t *out_reason,
428                  const char *source_file, const size_t source_line,
429                  const char *reason, ...)
430{
431    va_list ap;
432
433    va_start(ap, reason);
434    format_reason_ap(out_reason, source_file, source_line, reason, ap);
435    va_end(ap);
436}
437
438static void
439errno_test(struct context *ctx, const char *file, const size_t line,
440           const int exp_errno, const char *expr_str,
441           const bool expr_result,
442           void (*fail_func)(struct context *, atf_dynstr_t *))
443{
444    const int actual_errno = errno;
445
446    if (expr_result) {
447        if (exp_errno != actual_errno) {
448            atf_dynstr_t reason;
449
450            format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
451                "in %s", exp_errno, actual_errno, expr_str);
452            fail_func(ctx, &reason);
453        }
454    } else {
455        atf_dynstr_t reason;
456
457        format_reason_fmt(&reason, file, line, "Expected true value in %s",
458            expr_str);
459        fail_func(ctx, &reason);
460    }
461}
462
463struct prog_found_pair {
464    const char *prog;
465    bool found;
466};
467
468static atf_error_t
469check_prog_in_dir(const char *dir, void *data)
470{
471    struct prog_found_pair *pf = data;
472    atf_error_t err;
473
474    if (pf->found)
475        err = atf_no_error();
476    else {
477        atf_fs_path_t p;
478
479        err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
480        if (atf_is_error(err))
481            goto out_p;
482
483        err = atf_fs_eaccess(&p, atf_fs_access_x);
484        if (!atf_is_error(err))
485            pf->found = true;
486        else {
487            atf_error_free(err);
488            INV(!pf->found);
489            err = atf_no_error();
490        }
491
492out_p:
493        atf_fs_path_fini(&p);
494    }
495
496    return err;
497}
498
499static atf_error_t
500check_prog(struct context *ctx, const char *prog)
501{
502    atf_error_t err;
503    atf_fs_path_t p;
504
505    err = atf_fs_path_init_fmt(&p, "%s", prog);
506    if (atf_is_error(err))
507        goto out;
508
509    if (atf_fs_path_is_absolute(&p)) {
510        err = atf_fs_eaccess(&p, atf_fs_access_x);
511        if (atf_is_error(err)) {
512            atf_dynstr_t reason;
513
514            atf_error_free(err);
515            atf_fs_path_fini(&p);
516            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
517                "not be found", prog);
518            skip(ctx, &reason);
519        }
520    } else {
521        const char *path = atf_env_get("PATH");
522        struct prog_found_pair pf;
523        atf_fs_path_t bp;
524
525        err = atf_fs_path_branch_path(&p, &bp);
526        if (atf_is_error(err))
527            goto out_p;
528
529        if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
530            atf_fs_path_fini(&bp);
531            atf_fs_path_fini(&p);
532
533            report_fatal_error("Relative paths are not allowed when searching "
534                "for a program (%s)", prog);
535            UNREACHABLE;
536        }
537
538        pf.prog = prog;
539        pf.found = false;
540        err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
541        if (atf_is_error(err))
542            goto out_bp;
543
544        if (!pf.found) {
545            atf_dynstr_t reason;
546
547            atf_fs_path_fini(&bp);
548            atf_fs_path_fini(&p);
549            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
550                "not be found in the PATH", prog);
551            fail_requirement(ctx, &reason);
552        }
553
554out_bp:
555        atf_fs_path_fini(&bp);
556    }
557
558out_p:
559    atf_fs_path_fini(&p);
560out:
561    return err;
562}
563
564/* ---------------------------------------------------------------------
565 * The "atf_tc" type.
566 * --------------------------------------------------------------------- */
567
568struct atf_tc_impl {
569    const char *m_ident;
570
571    atf_map_t m_vars;
572    atf_map_t m_config;
573
574    atf_tc_head_t m_head;
575    atf_tc_body_t m_body;
576    atf_tc_cleanup_t m_cleanup;
577};
578
579/*
580 * Constructors/destructors.
581 */
582
583atf_error_t
584atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
585            atf_tc_body_t body, atf_tc_cleanup_t cleanup,
586            const char *const *config)
587{
588    atf_error_t err;
589
590    tc->pimpl = malloc(sizeof(struct atf_tc_impl));
591    if (tc->pimpl == NULL) {
592        err = atf_no_memory_error();
593        goto err;
594    }
595
596    tc->pimpl->m_ident = ident;
597    tc->pimpl->m_head = head;
598    tc->pimpl->m_body = body;
599    tc->pimpl->m_cleanup = cleanup;
600
601    err = atf_map_init_charpp(&tc->pimpl->m_config, config);
602    if (atf_is_error(err))
603        goto err;
604
605    err = atf_map_init(&tc->pimpl->m_vars);
606    if (atf_is_error(err))
607        goto err_vars;
608
609    err = atf_tc_set_md_var(tc, "ident", ident);
610    if (atf_is_error(err))
611        goto err_map;
612
613    if (cleanup != NULL) {
614        err = atf_tc_set_md_var(tc, "has.cleanup", "true");
615        if (atf_is_error(err))
616            goto err_map;
617    }
618
619    /* XXX Should the head be able to return error codes? */
620    if (tc->pimpl->m_head != NULL)
621        tc->pimpl->m_head(tc);
622
623    if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
624        report_fatal_error("Test case head modified the read-only 'ident' "
625            "property");
626        UNREACHABLE;
627    }
628
629    INV(!atf_is_error(err));
630    return err;
631
632err_map:
633    atf_map_fini(&tc->pimpl->m_vars);
634err_vars:
635    atf_map_fini(&tc->pimpl->m_config);
636err:
637    return err;
638}
639
640atf_error_t
641atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
642                 const char *const *config)
643{
644    return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
645                       pack->m_cleanup, config);
646}
647
648void
649atf_tc_fini(atf_tc_t *tc)
650{
651    atf_map_fini(&tc->pimpl->m_vars);
652    free(tc->pimpl);
653}
654
655/*
656 * Getters.
657 */
658
659const char *
660atf_tc_get_ident(const atf_tc_t *tc)
661{
662    return tc->pimpl->m_ident;
663}
664
665const char *
666atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
667{
668    const char *val;
669    atf_map_citer_t iter;
670
671    PRE(atf_tc_has_config_var(tc, name));
672    iter = atf_map_find_c(&tc->pimpl->m_config, name);
673    val = atf_map_citer_data(iter);
674    INV(val != NULL);
675
676    return val;
677}
678
679const char *
680atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
681                         const char *defval)
682{
683    const char *val;
684
685    if (!atf_tc_has_config_var(tc, name))
686        val = defval;
687    else
688        val = atf_tc_get_config_var(tc, name);
689
690    return val;
691}
692
693bool
694atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
695{
696    bool val;
697    const char *strval;
698    atf_error_t err;
699
700    strval = atf_tc_get_config_var(tc, name);
701    err = atf_text_to_bool(strval, &val);
702    if (atf_is_error(err)) {
703        atf_error_free(err);
704        atf_tc_fail("Configuration variable %s does not have a valid "
705                    "boolean value; found %s", name, strval);
706    }
707
708    return val;
709}
710
711bool
712atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
713                                 const bool defval)
714{
715    bool val;
716
717    if (!atf_tc_has_config_var(tc, name))
718        val = defval;
719    else
720        val = atf_tc_get_config_var_as_bool(tc, name);
721
722    return val;
723}
724
725long
726atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
727{
728    long val;
729    const char *strval;
730    atf_error_t err;
731
732    strval = atf_tc_get_config_var(tc, name);
733    err = atf_text_to_long(strval, &val);
734    if (atf_is_error(err)) {
735        atf_error_free(err);
736        atf_tc_fail("Configuration variable %s does not have a valid "
737                    "long value; found %s", name, strval);
738    }
739
740    return val;
741}
742
743long
744atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
745                                 const long defval)
746{
747    long val;
748
749    if (!atf_tc_has_config_var(tc, name))
750        val = defval;
751    else
752        val = atf_tc_get_config_var_as_long(tc, name);
753
754    return val;
755}
756
757const char *
758atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
759{
760    const char *val;
761    atf_map_citer_t iter;
762
763    PRE(atf_tc_has_md_var(tc, name));
764    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
765    val = atf_map_citer_data(iter);
766    INV(val != NULL);
767
768    return val;
769}
770
771char **
772atf_tc_get_md_vars(const atf_tc_t *tc)
773{
774    return atf_map_to_charpp(&tc->pimpl->m_vars);
775}
776
777bool
778atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
779{
780    atf_map_citer_t end, iter;
781
782    iter = atf_map_find_c(&tc->pimpl->m_config, name);
783    end = atf_map_end_c(&tc->pimpl->m_config);
784    return !atf_equal_map_citer_map_citer(iter, end);
785}
786
787bool
788atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
789{
790    atf_map_citer_t end, iter;
791
792    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
793    end = atf_map_end_c(&tc->pimpl->m_vars);
794    return !atf_equal_map_citer_map_citer(iter, end);
795}
796
797/*
798 * Modifiers.
799 */
800
801atf_error_t
802atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
803{
804    atf_error_t err;
805    char *value;
806    va_list ap;
807
808    va_start(ap, fmt);
809    err = atf_text_format_ap(&value, fmt, ap);
810    va_end(ap);
811
812    if (!atf_is_error(err))
813        err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
814    else
815        free(value);
816
817    return err;
818}
819
820/* ---------------------------------------------------------------------
821 * Free functions, as they should be publicly but they can't.
822 * --------------------------------------------------------------------- */
823
824static void _atf_tc_fail(struct context *, const char *, va_list)
825    ATF_DEFS_ATTRIBUTE_NORETURN;
826static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
827static void _atf_tc_fail_check(struct context *, const char *, const size_t,
828    const char *, va_list);
829static void _atf_tc_fail_requirement(struct context *, const char *,
830    const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
831static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
832static void _atf_tc_require_prog(struct context *, const char *);
833static void _atf_tc_skip(struct context *, const char *, va_list)
834    ATF_DEFS_ATTRIBUTE_NORETURN;
835static void _atf_tc_check_errno(struct context *, const char *, const size_t,
836    const int, const char *, const bool);
837static void _atf_tc_require_errno(struct context *, const char *, const size_t,
838    const int, const char *, const bool);
839static void _atf_tc_expect_pass(struct context *);
840static void _atf_tc_expect_fail(struct context *, const char *, va_list);
841static void _atf_tc_expect_exit(struct context *, const int, const char *,
842    va_list);
843static void _atf_tc_expect_signal(struct context *, const int, const char *,
844    va_list);
845static void _atf_tc_expect_death(struct context *, const char *,
846    va_list);
847
848static void
849_atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
850{
851    va_list ap2;
852    atf_dynstr_t reason;
853
854    va_copy(ap2, ap);
855    format_reason_ap(&reason, NULL, 0, fmt, ap2);
856    va_end(ap2);
857
858    fail_requirement(ctx, &reason);
859    UNREACHABLE;
860}
861
862static void
863_atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
864{
865    va_list ap2;
866    atf_dynstr_t reason;
867
868    va_copy(ap2, ap);
869    format_reason_ap(&reason, NULL, 0, fmt, ap2);
870    va_end(ap2);
871
872    fail_check(ctx, &reason);
873}
874
875static void
876_atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
877                   const char *fmt, va_list ap)
878{
879    va_list ap2;
880    atf_dynstr_t reason;
881
882    va_copy(ap2, ap);
883    format_reason_ap(&reason, file, line, fmt, ap2);
884    va_end(ap2);
885
886    fail_check(ctx, &reason);
887}
888
889static void
890_atf_tc_fail_requirement(struct context *ctx, const char *file,
891                         const size_t line, const char *fmt, va_list ap)
892{
893    va_list ap2;
894    atf_dynstr_t reason;
895
896    va_copy(ap2, ap);
897    format_reason_ap(&reason, file, line, fmt, ap2);
898    va_end(ap2);
899
900    fail_requirement(ctx, &reason);
901    UNREACHABLE;
902}
903
904static void
905_atf_tc_pass(struct context *ctx)
906{
907    pass(ctx);
908    UNREACHABLE;
909}
910
911static void
912_atf_tc_require_prog(struct context *ctx, const char *prog)
913{
914    check_fatal_error(check_prog(ctx, prog));
915}
916
917static void
918_atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
919{
920    atf_dynstr_t reason;
921    va_list ap2;
922
923    va_copy(ap2, ap);
924    format_reason_ap(&reason, NULL, 0, fmt, ap2);
925    va_end(ap2);
926
927    skip(ctx, &reason);
928}
929
930static void
931_atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
932                    const int exp_errno, const char *expr_str,
933                    const bool expr_result)
934{
935    errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
936}
937
938static void
939_atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
940                      const int exp_errno, const char *expr_str,
941                      const bool expr_result)
942{
943    errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
944        fail_requirement);
945}
946
947static void
948_atf_tc_expect_pass(struct context *ctx)
949{
950    validate_expect(ctx);
951
952    ctx->expect = EXPECT_PASS;
953}
954
955static void
956_atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
957{
958    va_list ap2;
959
960    validate_expect(ctx);
961
962    ctx->expect = EXPECT_FAIL;
963    atf_dynstr_fini(&ctx->expect_reason);
964    va_copy(ap2, ap);
965    check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
966    va_end(ap2);
967    ctx->expect_previous_fail_count = ctx->expect_fail_count;
968}
969
970static void
971_atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
972                    va_list ap)
973{
974    va_list ap2;
975    atf_dynstr_t formatted;
976
977    validate_expect(ctx);
978
979    ctx->expect = EXPECT_EXIT;
980    va_copy(ap2, ap);
981    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
982    va_end(ap2);
983
984    create_resfile(ctx, "expected_exit", exitcode, &formatted);
985}
986
987static void
988_atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
989                      va_list ap)
990{
991    va_list ap2;
992    atf_dynstr_t formatted;
993
994    validate_expect(ctx);
995
996    ctx->expect = EXPECT_SIGNAL;
997    va_copy(ap2, ap);
998    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
999    va_end(ap2);
1000
1001    create_resfile(ctx, "expected_signal", signo, &formatted);
1002}
1003
1004static void
1005_atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
1006{
1007    va_list ap2;
1008    atf_dynstr_t formatted;
1009
1010    validate_expect(ctx);
1011
1012    ctx->expect = EXPECT_DEATH;
1013    va_copy(ap2, ap);
1014    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
1015    va_end(ap2);
1016
1017    create_resfile(ctx, "expected_death", -1, &formatted);
1018}
1019
1020static void
1021_atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
1022{
1023    va_list ap2;
1024    atf_dynstr_t formatted;
1025
1026    validate_expect(ctx);
1027
1028    ctx->expect = EXPECT_TIMEOUT;
1029    va_copy(ap2, ap);
1030    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
1031    va_end(ap2);
1032
1033    create_resfile(ctx, "expected_timeout", -1, &formatted);
1034}
1035
1036static void
1037_atf_tc_set_resultsfile(struct context *ctx, const char *file)
1038{
1039
1040    context_set_resfile(ctx, file);
1041}
1042
1043/* ---------------------------------------------------------------------
1044 * Free functions.
1045 * --------------------------------------------------------------------- */
1046
1047static struct context Current;
1048
1049atf_error_t
1050atf_tc_run(const atf_tc_t *tc, const char *resfile)
1051{
1052    context_init(&Current, tc, resfile);
1053
1054    tc->pimpl->m_body(tc);
1055
1056    validate_expect(&Current);
1057
1058    if (Current.fail_count > 0) {
1059        atf_dynstr_t reason;
1060
1061        format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for "
1062            "more details", Current.fail_count);
1063        fail_requirement(&Current, &reason);
1064    } else if (Current.expect_fail_count > 0) {
1065        atf_dynstr_t reason;
1066
1067        format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; "
1068            "see output for more details", Current.expect_fail_count);
1069        expected_failure(&Current, &reason);
1070    } else {
1071        pass(&Current);
1072    }
1073    UNREACHABLE;
1074    return atf_no_error();
1075}
1076
1077atf_error_t
1078atf_tc_cleanup(const atf_tc_t *tc)
1079{
1080    if (tc->pimpl->m_cleanup != NULL)
1081        tc->pimpl->m_cleanup(tc);
1082    return atf_no_error(); /* XXX */
1083}
1084
1085/* ---------------------------------------------------------------------
1086 * Free functions that depend on Current.
1087 * --------------------------------------------------------------------- */
1088
1089/*
1090 * All the functions below provide delegates to other internal functions
1091 * (prefixed by _) that take the current test case as an argument to
1092 * prevent them from accessing global state.  This is to keep the side-
1093 * effects of the internal functions clearer and easier to understand.
1094 *
1095 * The public API should never have hid the fact that it needs access to
1096 * the current test case (other than maybe in the macros), but changing it
1097 * is hard.  TODO: Revisit in the future.
1098 */
1099
1100void
1101atf_tc_fail(const char *fmt, ...)
1102{
1103    va_list ap;
1104
1105    PRE(Current.tc != NULL);
1106
1107    va_start(ap, fmt);
1108    _atf_tc_fail(&Current, fmt, ap);
1109    va_end(ap);
1110}
1111
1112void
1113atf_tc_fail_nonfatal(const char *fmt, ...)
1114{
1115    va_list ap;
1116
1117    PRE(Current.tc != NULL);
1118
1119    va_start(ap, fmt);
1120    _atf_tc_fail_nonfatal(&Current, fmt, ap);
1121    va_end(ap);
1122}
1123
1124void
1125atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
1126{
1127    va_list ap;
1128
1129    PRE(Current.tc != NULL);
1130
1131    va_start(ap, fmt);
1132    _atf_tc_fail_check(&Current, file, line, fmt, ap);
1133    va_end(ap);
1134}
1135
1136void
1137atf_tc_fail_requirement(const char *file, const size_t line,
1138                        const char *fmt, ...)
1139{
1140    va_list ap;
1141
1142    PRE(Current.tc != NULL);
1143
1144    va_start(ap, fmt);
1145    _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
1146    va_end(ap);
1147}
1148
1149void
1150atf_tc_pass(void)
1151{
1152    PRE(Current.tc != NULL);
1153
1154    _atf_tc_pass(&Current);
1155}
1156
1157void
1158atf_tc_require_prog(const char *prog)
1159{
1160    PRE(Current.tc != NULL);
1161
1162    _atf_tc_require_prog(&Current, prog);
1163}
1164
1165void
1166atf_tc_skip(const char *fmt, ...)
1167{
1168    va_list ap;
1169
1170    PRE(Current.tc != NULL);
1171
1172    va_start(ap, fmt);
1173    _atf_tc_skip(&Current, fmt, ap);
1174    va_end(ap);
1175}
1176
1177void
1178atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
1179                   const char *expr_str, const bool expr_result)
1180{
1181    PRE(Current.tc != NULL);
1182
1183    _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
1184                        expr_result);
1185}
1186
1187void
1188atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
1189                     const char *expr_str, const bool expr_result)
1190{
1191    PRE(Current.tc != NULL);
1192
1193    _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
1194                          expr_result);
1195}
1196
1197void
1198atf_tc_expect_pass(void)
1199{
1200    PRE(Current.tc != NULL);
1201
1202    _atf_tc_expect_pass(&Current);
1203}
1204
1205void
1206atf_tc_expect_fail(const char *reason, ...)
1207{
1208    va_list ap;
1209
1210    PRE(Current.tc != NULL);
1211
1212    va_start(ap, reason);
1213    _atf_tc_expect_fail(&Current, reason, ap);
1214    va_end(ap);
1215}
1216
1217void
1218atf_tc_expect_exit(const int exitcode, const char *reason, ...)
1219{
1220    va_list ap;
1221
1222    PRE(Current.tc != NULL);
1223
1224    va_start(ap, reason);
1225    _atf_tc_expect_exit(&Current, exitcode, reason, ap);
1226    va_end(ap);
1227}
1228
1229void
1230atf_tc_expect_signal(const int signo, const char *reason, ...)
1231{
1232    va_list ap;
1233
1234    PRE(Current.tc != NULL);
1235
1236    va_start(ap, reason);
1237    _atf_tc_expect_signal(&Current, signo, reason, ap);
1238    va_end(ap);
1239}
1240
1241void
1242atf_tc_expect_death(const char *reason, ...)
1243{
1244    va_list ap;
1245
1246    PRE(Current.tc != NULL);
1247
1248    va_start(ap, reason);
1249    _atf_tc_expect_death(&Current, reason, ap);
1250    va_end(ap);
1251}
1252
1253void
1254atf_tc_expect_timeout(const char *reason, ...)
1255{
1256    va_list ap;
1257
1258    PRE(Current.tc != NULL);
1259
1260    va_start(ap, reason);
1261    _atf_tc_expect_timeout(&Current, reason, ap);
1262    va_end(ap);
1263}
1264
1265/* Internal! */
1266void
1267atf_tc_set_resultsfile(const char *file)
1268{
1269
1270    PRE(Current.tc != NULL);
1271
1272    _atf_tc_set_resultsfile(&Current, file);
1273}
1274