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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 700 atf_tc_get_ident(const atf_tc_t *tc) 701 { 702 return tc->pimpl->m_ident; 703 } 704 705 const char * 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 * 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 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 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 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 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 * 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 ** 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 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 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 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 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 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 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 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 948 _atf_tc_pass(struct context *ctx) 949 { 950 pass(ctx); 951 UNREACHABLE; 952 } 953 954 #ifdef __FreeBSD__ 955 static void 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 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 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 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 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 999 _atf_tc_expect_pass(struct context *ctx) 1000 { 1001 validate_expect(ctx); 1002 1003 ctx->expect = EXPECT_PASS; 1004 } 1005 1006 static void 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 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 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 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 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 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 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 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 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 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 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 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 1201 atf_tc_pass(void) 1202 { 1203 PRE(Current.tc != NULL); 1204 1205 _atf_tc_pass(&Current); 1206 } 1207 1208 #ifdef __FreeBSD__ 1209 void 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 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 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 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 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 1259 atf_tc_expect_pass(void) 1260 { 1261 PRE(Current.tc != NULL); 1262 1263 _atf_tc_expect_pass(&Current); 1264 } 1265 1266 void 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 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 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 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 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 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