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