1 /* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/time.h> 32 #include <sys/stat.h> 33 #include <sys/wait.h> 34 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <limits.h> 38 #include <stdarg.h> 39 #include <stdbool.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "atf-c/config.h" 46 #include "atf-c/env.h" 47 #include "atf-c/error.h" 48 #include "atf-c/fs.h" 49 #include "atf-c/process.h" 50 #include "atf-c/sanity.h" 51 #include "atf-c/signals.h" 52 #include "atf-c/tc.h" 53 #include "atf-c/tcr.h" 54 #include "atf-c/text.h" 55 #include "atf-c/user.h" 56 57 /* --------------------------------------------------------------------- 58 * Auxiliary types and functions. 59 * --------------------------------------------------------------------- */ 60 61 /* Parent-only stuff. */ 62 struct timeout_data; 63 static atf_error_t body_parent(const atf_tc_t *, const atf_fs_path_t *, 64 pid_t, atf_tcr_t *); 65 static atf_error_t cleanup_parent(const atf_tc_t *, pid_t); 66 static atf_error_t fork_body(const atf_tc_t *, const atf_fs_path_t *, 67 atf_tcr_t *); 68 static atf_error_t fork_cleanup(const atf_tc_t *, const atf_fs_path_t *); 69 static atf_error_t get_tc_result(const atf_fs_path_t *, atf_tcr_t *); 70 static atf_error_t program_timeout(pid_t, const atf_tc_t *, 71 struct timeout_data *); 72 static void unprogram_timeout(struct timeout_data *); 73 static void sigalrm_handler(int); 74 75 /* Child-only stuff. */ 76 static void body_child(const atf_tc_t *, const atf_fs_path_t *) 77 ATF_DEFS_ATTRIBUTE_NORETURN; 78 static atf_error_t check_arch(const char *, void *); 79 static atf_error_t check_config(const char *, void *); 80 static atf_error_t check_machine(const char *, void *); 81 static atf_error_t check_prog(const char *, void *); 82 static atf_error_t check_prog_in_dir(const char *, void *); 83 static atf_error_t check_requirements(const atf_tc_t *); 84 static void cleanup_child(const atf_tc_t *, const atf_fs_path_t *) 85 ATF_DEFS_ATTRIBUTE_NORETURN; 86 static void fail_internal(const char *, int, const char *, const char *, 87 const char *, va_list, 88 void (*)(const char *, ...)); 89 static void fatal_atf_error(const char *, atf_error_t) 90 ATF_DEFS_ATTRIBUTE_NORETURN; 91 static void fatal_libc_error(const char *, int) 92 ATF_DEFS_ATTRIBUTE_NORETURN; 93 static atf_error_t prepare_child(const atf_tc_t *, const atf_fs_path_t *); 94 static void write_tcr(const atf_tcr_t *); 95 96 /* --------------------------------------------------------------------- 97 * The "atf_tc" type. 98 * --------------------------------------------------------------------- */ 99 100 /* 101 * Constructors/destructors. 102 */ 103 104 atf_error_t 105 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head, 106 atf_tc_body_t body, atf_tc_cleanup_t cleanup, 107 const atf_map_t *config) 108 { 109 atf_error_t err; 110 111 atf_object_init(&tc->m_object); 112 113 tc->m_ident = ident; 114 tc->m_head = head; 115 tc->m_body = body; 116 tc->m_cleanup = cleanup; 117 tc->m_config = config; 118 119 err = atf_map_init(&tc->m_vars); 120 if (atf_is_error(err)) 121 goto err_object; 122 123 err = atf_tc_set_md_var(tc, "ident", ident); 124 if (atf_is_error(err)) 125 goto err_map; 126 127 err = atf_tc_set_md_var(tc, "timeout", "300"); 128 if (atf_is_error(err)) 129 goto err_map; 130 131 /* XXX Should the head be able to return error codes? */ 132 tc->m_head(tc); 133 134 if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) 135 atf_tc_fail("Test case head modified the read-only 'ident' " 136 "property"); 137 138 INV(!atf_is_error(err)); 139 return err; 140 141 err_map: 142 atf_map_fini(&tc->m_vars); 143 err_object: 144 atf_object_fini(&tc->m_object); 145 146 return err; 147 } 148 149 atf_error_t 150 atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack, 151 const atf_map_t *config) 152 { 153 return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body, 154 pack->m_cleanup, config); 155 } 156 157 void 158 atf_tc_fini(atf_tc_t *tc) 159 { 160 atf_map_fini(&tc->m_vars); 161 162 atf_object_fini(&tc->m_object); 163 } 164 165 /* 166 * Getters. 167 */ 168 169 const char * 170 atf_tc_get_ident(const atf_tc_t *tc) 171 { 172 return tc->m_ident; 173 } 174 175 const char * 176 atf_tc_get_config_var(const atf_tc_t *tc, const char *name) 177 { 178 const char *val; 179 atf_map_citer_t iter; 180 181 PRE(atf_tc_has_config_var(tc, name)); 182 iter = atf_map_find_c(tc->m_config, name); 183 val = atf_map_citer_data(iter); 184 INV(val != NULL); 185 186 return val; 187 } 188 189 const char * 190 atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name, 191 const char *defval) 192 { 193 const char *val; 194 195 if (!atf_tc_has_config_var(tc, name)) 196 val = defval; 197 else 198 val = atf_tc_get_config_var(tc, name); 199 200 return val; 201 } 202 203 const char * 204 atf_tc_get_md_var(const atf_tc_t *tc, const char *name) 205 { 206 const char *val; 207 atf_map_citer_t iter; 208 209 PRE(atf_tc_has_md_var(tc, name)); 210 iter = atf_map_find_c(&tc->m_vars, name); 211 val = atf_map_citer_data(iter); 212 INV(val != NULL); 213 214 return val; 215 } 216 217 bool 218 atf_tc_has_config_var(const atf_tc_t *tc, const char *name) 219 { 220 bool found; 221 atf_map_citer_t end, iter; 222 223 if (tc->m_config == NULL) 224 found = false; 225 else { 226 iter = atf_map_find_c(tc->m_config, name); 227 end = atf_map_end_c(tc->m_config); 228 found = !atf_equal_map_citer_map_citer(iter, end); 229 } 230 231 return found; 232 } 233 234 bool 235 atf_tc_has_md_var(const atf_tc_t *tc, const char *name) 236 { 237 atf_map_citer_t end, iter; 238 239 iter = atf_map_find_c(&tc->m_vars, name); 240 end = atf_map_end_c(&tc->m_vars); 241 return !atf_equal_map_citer_map_citer(iter, end); 242 } 243 244 /* 245 * Modifiers. 246 */ 247 248 atf_error_t 249 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...) 250 { 251 atf_error_t err; 252 char *value; 253 va_list ap; 254 255 va_start(ap, fmt); 256 err = atf_text_format_ap(&value, fmt, ap); 257 va_end(ap); 258 259 if (!atf_is_error(err)) 260 err = atf_map_insert(&tc->m_vars, name, value, true); 261 else 262 free(value); 263 264 return err; 265 } 266 267 /* --------------------------------------------------------------------- 268 * Free functions. 269 * --------------------------------------------------------------------- */ 270 271 atf_error_t 272 atf_tc_run(const atf_tc_t *tc, atf_tcr_t *tcr, 273 const atf_fs_path_t *workdirbase) 274 { 275 atf_error_t err, cleanuperr; 276 atf_fs_path_t workdir; 277 278 err = atf_fs_path_copy(&workdir, workdirbase); 279 if (atf_is_error(err)) 280 goto out; 281 282 err = atf_fs_path_append_fmt(&workdir, "atf.XXXXXX"); 283 if (atf_is_error(err)) 284 goto out_workdir; 285 286 err = atf_fs_mkdtemp(&workdir); 287 if (atf_is_error(err)) 288 goto out_workdir; 289 290 err = fork_body(tc, &workdir, tcr); 291 cleanuperr = fork_cleanup(tc, &workdir); 292 if (!atf_is_error(cleanuperr)) 293 (void)atf_fs_cleanup(&workdir); 294 if (!atf_is_error(err)) 295 err = cleanuperr; 296 else if (atf_is_error(cleanuperr)) 297 atf_error_free(cleanuperr); 298 299 out_workdir: 300 atf_fs_path_fini(&workdir); 301 out: 302 return err; 303 } 304 305 /* 306 * Parent-only stuff. 307 */ 308 309 static bool sigalrm_killed = false; 310 static pid_t sigalrm_pid = -1; 311 312 static 313 void 314 sigalrm_handler(int signo) 315 { 316 INV(signo == SIGALRM); 317 318 if (sigalrm_pid != -1) { 319 killpg(sigalrm_pid, SIGTERM); 320 sigalrm_killed = true; 321 } 322 } 323 324 struct timeout_data { 325 bool m_programmed; 326 atf_signal_programmer_t m_sigalrm; 327 }; 328 329 static 330 atf_error_t 331 program_timeout(pid_t pid, const atf_tc_t *tc, struct timeout_data *td) 332 { 333 atf_error_t err; 334 long timeout; 335 336 err = atf_text_to_long(atf_tc_get_md_var(tc, "timeout"), &timeout); 337 if (atf_is_error(err)) 338 goto out; 339 340 if (timeout != 0) { 341 sigalrm_pid = pid; 342 sigalrm_killed = false; 343 344 err = atf_signal_programmer_init(&td->m_sigalrm, SIGALRM, 345 sigalrm_handler); 346 if (atf_is_error(err)) 347 goto out; 348 349 struct itimerval itv; 350 timerclear(&itv.it_interval); 351 timerclear(&itv.it_value); 352 itv.it_value.tv_sec = timeout; 353 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { 354 atf_signal_programmer_fini(&td->m_sigalrm); 355 err = atf_libc_error(errno, "Failed to program timeout " 356 "with %ld seconds", timeout); 357 } 358 359 td->m_programmed = !atf_is_error(err); 360 } else 361 td->m_programmed = false; 362 363 out: 364 return err; 365 } 366 367 static 368 void 369 unprogram_timeout(struct timeout_data *td) 370 { 371 if (td->m_programmed) { 372 atf_signal_programmer_fini(&td->m_sigalrm); 373 sigalrm_pid = -1; 374 sigalrm_killed = false; 375 } 376 } 377 378 static 379 atf_error_t 380 body_parent(const atf_tc_t *tc, const atf_fs_path_t *workdir, pid_t pid, 381 atf_tcr_t *tcr) 382 { 383 atf_error_t err; 384 int state; 385 struct timeout_data td; 386 387 err = program_timeout(pid, tc, &td); 388 if (atf_is_error(err)) { 389 char buf[4096]; 390 391 atf_error_format(err, buf, sizeof(buf)); 392 fprintf(stderr, "Error programming test case's timeout: %s", buf); 393 atf_error_free(err); 394 killpg(pid, SIGKILL); 395 } 396 397 if (waitpid(pid, &state, 0) == -1) { 398 if (errno == EINTR && sigalrm_killed) 399 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state, 400 "Test case timed out after %s " 401 "seconds", 402 atf_tc_get_md_var(tc, "timeout")); 403 else 404 err = atf_libc_error(errno, "Error waiting for child process " 405 "%d", pid); 406 } else { 407 if (!WIFEXITED(state) || WEXITSTATUS(state) != EXIT_SUCCESS) { 408 if (WIFEXITED(state)) 409 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state, 410 "Test case did not exit cleanly; " 411 "exit status was %d", 412 WEXITSTATUS(state)); 413 else if (WIFSIGNALED(state)) 414 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state, 415 "Test case did not exit cleanly: " 416 "%s%s", 417 strsignal(WTERMSIG(state)), 418 WCOREDUMP(state) ? 419 " (core dumped)" : ""); 420 else 421 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state, 422 "Test case did not exit cleanly; " 423 "state was %d", state); 424 } else 425 err = get_tc_result(workdir, tcr); 426 } 427 428 unprogram_timeout(&td); 429 430 return err; 431 } 432 433 static 434 atf_error_t 435 cleanup_parent(const atf_tc_t *tc, pid_t pid) 436 { 437 atf_error_t err; 438 int state; 439 440 if (waitpid(pid, &state, 0) == -1) { 441 err = atf_libc_error(errno, "Error waiting for child process " 442 "%d", pid); 443 goto out; 444 } 445 446 if (!WIFEXITED(state) || WEXITSTATUS(state) != EXIT_SUCCESS) 447 /* XXX Not really a libc error. */ 448 err = atf_libc_error(EINVAL, "Child process did not exit cleanly"); 449 else 450 err = atf_no_error(); 451 452 out: 453 return err; 454 } 455 456 static 457 atf_error_t 458 fork_body(const atf_tc_t *tc, const atf_fs_path_t *workdir, atf_tcr_t *tcr) 459 { 460 atf_error_t err; 461 pid_t pid; 462 463 err = atf_process_fork(&pid); 464 if (atf_is_error(err)) 465 goto out; 466 467 if (pid == 0) { 468 body_child(tc, workdir); 469 UNREACHABLE; 470 abort(); 471 } else { 472 err = body_parent(tc, workdir, pid, tcr); 473 } 474 475 out: 476 return err; 477 } 478 479 static 480 atf_error_t 481 fork_cleanup(const atf_tc_t *tc, const atf_fs_path_t *workdir) 482 { 483 atf_error_t err; 484 pid_t pid; 485 486 if (tc->m_cleanup == NULL) 487 err = atf_no_error(); 488 else { 489 err = atf_process_fork(&pid); 490 if (atf_is_error(err)) 491 goto out; 492 493 if (pid == 0) { 494 cleanup_child(tc, workdir); 495 UNREACHABLE; 496 abort(); 497 } else { 498 err = cleanup_parent(tc, pid); 499 } 500 } 501 502 out: 503 return err; 504 } 505 506 static 507 atf_error_t 508 get_tc_result(const atf_fs_path_t *workdir, atf_tcr_t *tcr) 509 { 510 atf_error_t err; 511 int fd; 512 atf_fs_path_t tcrfile; 513 514 err = atf_fs_path_copy(&tcrfile, workdir); 515 if (atf_is_error(err)) 516 goto out; 517 518 err = atf_fs_path_append_fmt(&tcrfile, "tc-result"); 519 if (atf_is_error(err)) 520 goto out_tcrfile; 521 522 fd = open(atf_fs_path_cstring(&tcrfile), O_RDONLY); 523 if (fd == -1) { 524 err = atf_libc_error(errno, "Cannot retrieve test case result"); 525 goto out_tcrfile; 526 } 527 528 err = atf_tcr_deserialize(tcr, fd); 529 530 close(fd); 531 out_tcrfile: 532 atf_fs_path_fini(&tcrfile); 533 out: 534 return err; 535 } 536 537 /* 538 * Child-only stuff. 539 */ 540 541 static const atf_tc_t *current_tc = NULL; 542 static const atf_fs_path_t *current_workdir = NULL; 543 static size_t current_tc_fail_count = 0; 544 545 static 546 atf_error_t 547 prepare_child(const atf_tc_t *tc, const atf_fs_path_t *workdir) 548 { 549 atf_error_t err; 550 int i, ret; 551 552 current_tc = tc; 553 current_workdir = workdir; 554 current_tc_fail_count = 0; 555 556 ret = setpgid(getpid(), 0); 557 INV(ret != -1); 558 559 umask(S_IWGRP | S_IWOTH); 560 561 for (i = 1; i <= atf_signals_last_signo; i++) 562 atf_signal_reset(i); 563 564 err = atf_env_set("HOME", atf_fs_path_cstring(workdir)); 565 if (atf_is_error(err)) 566 goto out; 567 568 err = atf_env_unset("LANG"); 569 if (atf_is_error(err)) 570 goto out; 571 572 err = atf_env_unset("LC_ALL"); 573 if (atf_is_error(err)) 574 goto out; 575 576 err = atf_env_unset("LC_COLLATE"); 577 if (atf_is_error(err)) 578 goto out; 579 580 err = atf_env_unset("LC_CTYPE"); 581 if (atf_is_error(err)) 582 goto out; 583 584 err = atf_env_unset("LC_MESSAGES"); 585 if (atf_is_error(err)) 586 goto out; 587 588 err = atf_env_unset("LC_MONETARY"); 589 if (atf_is_error(err)) 590 goto out; 591 592 err = atf_env_unset("LC_NUMERIC"); 593 if (atf_is_error(err)) 594 goto out; 595 596 err = atf_env_unset("LC_TIME"); 597 if (atf_is_error(err)) 598 goto out; 599 600 err = atf_env_unset("TZ"); 601 if (atf_is_error(err)) 602 goto out; 603 604 if (chdir(atf_fs_path_cstring(workdir)) == -1) { 605 err = atf_libc_error(errno, "Cannot enter work directory '%s'", 606 atf_fs_path_cstring(workdir)); 607 goto out; 608 } 609 610 err = atf_no_error(); 611 612 out: 613 return err; 614 } 615 616 static 617 void 618 body_child(const atf_tc_t *tc, const atf_fs_path_t *workdir) 619 { 620 atf_error_t err; 621 622 atf_disable_exit_checks(); 623 624 err = prepare_child(tc, workdir); 625 if (atf_is_error(err)) 626 goto print_err; 627 err = check_requirements(tc); 628 if (atf_is_error(err)) 629 goto print_err; 630 tc->m_body(tc); 631 632 if (current_tc_fail_count == 0) 633 atf_tc_pass(); 634 else 635 atf_tc_fail("%d checks failed; see output for more details", 636 current_tc_fail_count); 637 638 UNREACHABLE; 639 abort(); 640 641 print_err: 642 INV(atf_is_error(err)); 643 { 644 char buf[4096]; 645 646 atf_error_format(err, buf, sizeof(buf)); 647 atf_error_free(err); 648 649 atf_tc_fail("Error while preparing child process: %s", buf); 650 } 651 652 UNREACHABLE; 653 abort(); 654 } 655 656 static 657 atf_error_t 658 check_arch(const char *arch, void *data) 659 { 660 bool *found = data; 661 662 if (strcmp(arch, atf_config_get("atf_arch")) == 0) 663 *found = true; 664 665 return atf_no_error(); 666 } 667 668 static 669 atf_error_t 670 check_config(const char *var, void *data) 671 { 672 if (!atf_tc_has_config_var(current_tc, var)) 673 atf_tc_skip("Required configuration variable %s not defined", var); 674 675 return atf_no_error(); 676 } 677 678 static 679 atf_error_t 680 check_machine(const char *machine, void *data) 681 { 682 bool *found = data; 683 684 if (strcmp(machine, atf_config_get("atf_machine")) == 0) 685 *found = true; 686 687 return atf_no_error(); 688 } 689 690 struct prog_found_pair { 691 const char *prog; 692 bool found; 693 }; 694 695 static 696 atf_error_t 697 check_prog(const char *prog, void *data) 698 { 699 atf_error_t err; 700 atf_fs_path_t p; 701 702 err = atf_fs_path_init_fmt(&p, "%s", prog); 703 if (atf_is_error(err)) 704 goto out; 705 706 if (atf_fs_path_is_absolute(&p)) { 707 if (atf_is_error(atf_fs_eaccess(&p, atf_fs_access_x))) 708 atf_tc_skip("The required program %s could not be found", prog); 709 } else { 710 const char *path = atf_env_get("PATH"); 711 struct prog_found_pair pf; 712 atf_fs_path_t bp; 713 714 err = atf_fs_path_branch_path(&p, &bp); 715 if (atf_is_error(err)) 716 goto out_p; 717 718 if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) 719 atf_tc_fail("Relative paths are not allowed when searching for " 720 "a program (%s)", prog); 721 722 pf.prog = prog; 723 pf.found = false; 724 err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf); 725 if (atf_is_error(err)) 726 goto out_bp; 727 728 if (!pf.found) 729 atf_tc_skip("The required program %s could not be found in " 730 "the PATH", prog); 731 732 out_bp: 733 atf_fs_path_fini(&bp); 734 } 735 736 out_p: 737 atf_fs_path_fini(&p); 738 out: 739 return err; 740 } 741 742 static 743 atf_error_t 744 check_prog_in_dir(const char *dir, void *data) 745 { 746 struct prog_found_pair *pf = data; 747 atf_error_t err; 748 749 if (pf->found) 750 err = atf_no_error(); 751 else { 752 atf_fs_path_t p; 753 754 err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog); 755 if (atf_is_error(err)) 756 goto out_p; 757 758 if (!atf_is_error(atf_fs_eaccess(&p, atf_fs_access_x))) 759 pf->found = true; 760 761 out_p: 762 atf_fs_path_fini(&p); 763 } 764 765 return err; 766 } 767 768 static 769 atf_error_t 770 check_requirements(const atf_tc_t *tc) 771 { 772 atf_error_t err; 773 774 err = atf_no_error(); 775 776 if (atf_tc_has_md_var(tc, "require.arch")) { 777 const char *arches = atf_tc_get_md_var(tc, "require.arch"); 778 bool found = false; 779 780 if (strlen(arches) == 0) 781 atf_tc_fail("Invalid value in the require.arch property"); 782 else { 783 err = atf_text_for_each_word(arches, " ", check_arch, &found); 784 if (atf_is_error(err)) 785 goto out; 786 787 if (!found) 788 atf_tc_skip("Requires one of the '%s' architectures", 789 arches); 790 } 791 } 792 793 if (atf_tc_has_md_var(tc, "require.config")) { 794 const char *vars = atf_tc_get_md_var(tc, "require.config"); 795 796 if (strlen(vars) == 0) 797 atf_tc_fail("Invalid value in the require.config property"); 798 else { 799 err = atf_text_for_each_word(vars, " ", check_config, NULL); 800 if (atf_is_error(err)) 801 goto out; 802 } 803 } 804 805 if (atf_tc_has_md_var(tc, "require.machine")) { 806 const char *machines = atf_tc_get_md_var(tc, "require.machine"); 807 bool found = false; 808 809 if (strlen(machines) == 0) 810 atf_tc_fail("Invalid value in the require.machine property"); 811 else { 812 err = atf_text_for_each_word(machines, " ", check_machine, 813 &found); 814 if (atf_is_error(err)) 815 goto out; 816 817 if (!found) 818 atf_tc_skip("Requires one of the '%s' machine types", 819 machines); 820 } 821 } 822 823 if (atf_tc_has_md_var(tc, "require.progs")) { 824 const char *progs = atf_tc_get_md_var(tc, "require.progs"); 825 826 if (strlen(progs) == 0) 827 atf_tc_fail("Invalid value in the require.progs property"); 828 else { 829 err = atf_text_for_each_word(progs, " ", check_prog, NULL); 830 if (atf_is_error(err)) 831 goto out; 832 } 833 } 834 835 if (atf_tc_has_md_var(tc, "require.user")) { 836 const char *u = atf_tc_get_md_var(tc, "require.user"); 837 838 if (strcmp(u, "root") == 0) { 839 if (!atf_user_is_root()) 840 atf_tc_skip("Requires root privileges"); 841 } else if (strcmp(u, "unprivileged") == 0) { 842 if (atf_user_is_root()) 843 atf_tc_skip("Requires an unprivileged user"); 844 } else 845 atf_tc_fail("Invalid value in the require.user property"); 846 } 847 848 INV(!atf_is_error(err)); 849 out: 850 return err; 851 } 852 853 static 854 void 855 cleanup_child(const atf_tc_t *tc, const atf_fs_path_t *workdir) 856 { 857 atf_error_t err; 858 859 atf_disable_exit_checks(); 860 861 err = prepare_child(tc, workdir); 862 if (atf_is_error(err)) 863 exit(EXIT_FAILURE); 864 else { 865 tc->m_cleanup(tc); 866 exit(EXIT_SUCCESS); 867 } 868 869 UNREACHABLE; 870 abort(); 871 } 872 873 static 874 void 875 fatal_atf_error(const char *prefix, atf_error_t err) 876 { 877 char buf[1024]; 878 879 INV(atf_is_error(err)); 880 881 atf_error_format(err, buf, sizeof(buf)); 882 atf_error_free(err); 883 884 fprintf(stderr, "%s: %s", prefix, buf); 885 886 abort(); 887 } 888 889 static 890 void 891 fatal_libc_error(const char *prefix, int err) 892 { 893 fprintf(stderr, "%s: %s", prefix, strerror(err)); 894 895 abort(); 896 } 897 898 static 899 void 900 write_tcr(const atf_tcr_t *tcr) 901 { 902 atf_error_t err; 903 int fd; 904 atf_fs_path_t tcrfile; 905 906 err = atf_fs_path_copy(&tcrfile, current_workdir); 907 if (atf_is_error(err)) 908 fatal_atf_error("Cannot write test case results", err); 909 910 err = atf_fs_path_append_fmt(&tcrfile, "tc-result"); 911 if (atf_is_error(err)) 912 fatal_atf_error("Cannot write test case results", err); 913 914 fd = open(atf_fs_path_cstring(&tcrfile), 915 O_WRONLY | O_CREAT | O_TRUNC, 0755); 916 if (fd == -1) 917 fatal_libc_error("Cannot write test case results", errno); 918 919 err = atf_tcr_serialize(tcr, fd); 920 if (atf_is_error(err)) 921 fatal_atf_error("Cannot write test case results", err); 922 923 close(fd); 924 } 925 926 void 927 atf_tc_fail(const char *fmt, ...) 928 { 929 va_list ap; 930 atf_tcr_t tcr; 931 atf_error_t err; 932 933 PRE(current_tc != NULL); 934 935 va_start(ap, fmt); 936 err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap); 937 va_end(ap); 938 if (atf_is_error(err)) 939 abort(); 940 941 write_tcr(&tcr); 942 943 atf_tcr_fini(&tcr); 944 945 exit(EXIT_SUCCESS); 946 } 947 948 void 949 atf_tc_fail_nonfatal(const char *fmt, ...) 950 { 951 va_list ap; 952 953 va_start(ap, fmt); 954 vfprintf(stderr, fmt, ap); 955 va_end(ap); 956 fprintf(stderr, "\n"); 957 958 current_tc_fail_count++; 959 } 960 961 void 962 atf_tc_fail_check(const char *file, int line, const char *fmt, ...) 963 { 964 va_list ap; 965 966 va_start(ap, fmt); 967 fail_internal(file, line, "Check failed", "*** ", fmt, ap, 968 atf_tc_fail_nonfatal); 969 va_end(ap); 970 } 971 972 void 973 atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...) 974 { 975 va_list ap; 976 977 va_start(ap, fmt); 978 fail_internal(file, line, "Requirement failed", "", fmt, ap, 979 atf_tc_fail); 980 va_end(ap); 981 982 UNREACHABLE; 983 abort(); 984 } 985 986 static 987 void 988 fail_internal(const char *file, int line, const char *reason, 989 const char *prefix, const char *fmt, va_list ap, 990 void (*failfunc)(const char *, ...)) 991 { 992 va_list ap2; 993 atf_error_t err; 994 atf_dynstr_t msg; 995 996 err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line, 997 reason); 998 if (atf_is_error(err)) 999 goto backup; 1000 1001 va_copy(ap2, ap); 1002 err = atf_dynstr_append_ap(&msg, fmt, ap2); 1003 va_end(ap2); 1004 if (atf_is_error(err)) { 1005 atf_dynstr_fini(&msg); 1006 goto backup; 1007 } 1008 1009 va_copy(ap2, ap); 1010 failfunc("%s", atf_dynstr_cstring(&msg)); 1011 atf_dynstr_fini(&msg); 1012 return; 1013 1014 backup: 1015 va_copy(ap2, ap); 1016 failfunc(fmt, ap2); 1017 va_end(ap2); 1018 } 1019 1020 void 1021 atf_tc_pass(void) 1022 { 1023 atf_tcr_t tcr; 1024 atf_error_t err; 1025 1026 PRE(current_tc != NULL); 1027 1028 err = atf_tcr_init(&tcr, atf_tcr_passed_state); 1029 if (atf_is_error(err)) 1030 abort(); 1031 1032 write_tcr(&tcr); 1033 1034 atf_tcr_fini(&tcr); 1035 1036 exit(EXIT_SUCCESS); 1037 } 1038 1039 void 1040 atf_tc_require_prog(const char *prog) 1041 { 1042 atf_error_t err; 1043 1044 err = check_prog(prog, NULL); 1045 if (atf_is_error(err)) 1046 atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */ 1047 } 1048 1049 void 1050 atf_tc_skip(const char *fmt, ...) 1051 { 1052 va_list ap; 1053 atf_tcr_t tcr; 1054 atf_error_t err; 1055 1056 PRE(current_tc != NULL); 1057 1058 va_start(ap, fmt); 1059 err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap); 1060 va_end(ap); 1061 if (atf_is_error(err)) 1062 abort(); 1063 1064 write_tcr(&tcr); 1065 1066 atf_tcr_fini(&tcr); 1067 1068 exit(EXIT_SUCCESS); 1069 } 1070