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 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state, 409 "Test case did not exit cleanly; " 410 "state was %d", state); 411 else 412 err = get_tc_result(workdir, tcr); 413 } 414 415 unprogram_timeout(&td); 416 417 return err; 418 } 419 420 static 421 atf_error_t 422 cleanup_parent(const atf_tc_t *tc, pid_t pid) 423 { 424 atf_error_t err; 425 int state; 426 427 if (waitpid(pid, &state, 0) == -1) { 428 err = atf_libc_error(errno, "Error waiting for child process " 429 "%d", pid); 430 goto out; 431 } 432 433 if (!WIFEXITED(state) || WEXITSTATUS(state) != EXIT_SUCCESS) 434 /* XXX Not really a libc error. */ 435 err = atf_libc_error(EINVAL, "Child process did not exit cleanly"); 436 else 437 err = atf_no_error(); 438 439 out: 440 return err; 441 } 442 443 static 444 atf_error_t 445 fork_body(const atf_tc_t *tc, const atf_fs_path_t *workdir, atf_tcr_t *tcr) 446 { 447 atf_error_t err; 448 pid_t pid; 449 450 err = atf_process_fork(&pid); 451 if (atf_is_error(err)) 452 goto out; 453 454 if (pid == 0) { 455 body_child(tc, workdir); 456 UNREACHABLE; 457 abort(); 458 } else { 459 err = body_parent(tc, workdir, pid, tcr); 460 } 461 462 out: 463 return err; 464 } 465 466 static 467 atf_error_t 468 fork_cleanup(const atf_tc_t *tc, const atf_fs_path_t *workdir) 469 { 470 atf_error_t err; 471 pid_t pid; 472 473 if (tc->m_cleanup == NULL) 474 err = atf_no_error(); 475 else { 476 err = atf_process_fork(&pid); 477 if (atf_is_error(err)) 478 goto out; 479 480 if (pid == 0) { 481 cleanup_child(tc, workdir); 482 UNREACHABLE; 483 abort(); 484 } else { 485 err = cleanup_parent(tc, pid); 486 } 487 } 488 489 out: 490 return err; 491 } 492 493 static 494 atf_error_t 495 get_tc_result(const atf_fs_path_t *workdir, atf_tcr_t *tcr) 496 { 497 atf_error_t err; 498 int fd; 499 atf_fs_path_t tcrfile; 500 501 err = atf_fs_path_copy(&tcrfile, workdir); 502 if (atf_is_error(err)) 503 goto out; 504 505 err = atf_fs_path_append_fmt(&tcrfile, "tc-result"); 506 if (atf_is_error(err)) 507 goto out_tcrfile; 508 509 fd = open(atf_fs_path_cstring(&tcrfile), O_RDONLY); 510 if (fd == -1) { 511 err = atf_libc_error(errno, "Cannot retrieve test case result"); 512 goto out_tcrfile; 513 } 514 515 err = atf_tcr_deserialize(tcr, fd); 516 517 close(fd); 518 out_tcrfile: 519 atf_fs_path_fini(&tcrfile); 520 out: 521 return err; 522 } 523 524 /* 525 * Child-only stuff. 526 */ 527 528 static const atf_tc_t *current_tc = NULL; 529 static const atf_fs_path_t *current_workdir = NULL; 530 static size_t current_tc_fail_count = 0; 531 532 static 533 atf_error_t 534 prepare_child(const atf_tc_t *tc, const atf_fs_path_t *workdir) 535 { 536 atf_error_t err; 537 int i, ret; 538 539 current_tc = tc; 540 current_workdir = workdir; 541 current_tc_fail_count = 0; 542 543 ret = setpgid(getpid(), 0); 544 INV(ret != -1); 545 546 umask(S_IWGRP | S_IWOTH); 547 548 for (i = 1; i <= atf_signals_last_signo; i++) 549 atf_signal_reset(i); 550 551 err = atf_env_set("HOME", atf_fs_path_cstring(workdir)); 552 if (atf_is_error(err)) 553 goto out; 554 555 err = atf_env_unset("LANG"); 556 if (atf_is_error(err)) 557 goto out; 558 559 err = atf_env_unset("LC_ALL"); 560 if (atf_is_error(err)) 561 goto out; 562 563 err = atf_env_unset("LC_COLLATE"); 564 if (atf_is_error(err)) 565 goto out; 566 567 err = atf_env_unset("LC_CTYPE"); 568 if (atf_is_error(err)) 569 goto out; 570 571 err = atf_env_unset("LC_MESSAGES"); 572 if (atf_is_error(err)) 573 goto out; 574 575 err = atf_env_unset("LC_MONETARY"); 576 if (atf_is_error(err)) 577 goto out; 578 579 err = atf_env_unset("LC_NUMERIC"); 580 if (atf_is_error(err)) 581 goto out; 582 583 err = atf_env_unset("LC_TIME"); 584 if (atf_is_error(err)) 585 goto out; 586 587 err = atf_env_unset("TZ"); 588 if (atf_is_error(err)) 589 goto out; 590 591 if (chdir(atf_fs_path_cstring(workdir)) == -1) { 592 err = atf_libc_error(errno, "Cannot enter work directory '%s'", 593 atf_fs_path_cstring(workdir)); 594 goto out; 595 } 596 597 err = atf_no_error(); 598 599 out: 600 return err; 601 } 602 603 static 604 void 605 body_child(const atf_tc_t *tc, const atf_fs_path_t *workdir) 606 { 607 atf_error_t err; 608 609 atf_disable_exit_checks(); 610 611 err = prepare_child(tc, workdir); 612 if (atf_is_error(err)) 613 goto print_err; 614 err = check_requirements(tc); 615 if (atf_is_error(err)) 616 goto print_err; 617 tc->m_body(tc); 618 619 if (current_tc_fail_count == 0) 620 atf_tc_pass(); 621 else 622 atf_tc_fail("%d checks failed; see output for more details", 623 current_tc_fail_count); 624 625 UNREACHABLE; 626 abort(); 627 628 print_err: 629 INV(atf_is_error(err)); 630 { 631 char buf[4096]; 632 633 atf_error_format(err, buf, sizeof(buf)); 634 atf_error_free(err); 635 636 atf_tc_fail("Error while preparing child process: %s", buf); 637 } 638 639 UNREACHABLE; 640 abort(); 641 } 642 643 static 644 atf_error_t 645 check_arch(const char *arch, void *data) 646 { 647 bool *found = data; 648 649 if (strcmp(arch, atf_config_get("atf_arch")) == 0) 650 *found = true; 651 652 return atf_no_error(); 653 } 654 655 static 656 atf_error_t 657 check_config(const char *var, void *data) 658 { 659 if (!atf_tc_has_config_var(current_tc, var)) 660 atf_tc_skip("Required configuration variable %s not defined", var); 661 662 return atf_no_error(); 663 } 664 665 static 666 atf_error_t 667 check_machine(const char *machine, void *data) 668 { 669 bool *found = data; 670 671 if (strcmp(machine, atf_config_get("atf_machine")) == 0) 672 *found = true; 673 674 return atf_no_error(); 675 } 676 677 struct prog_found_pair { 678 const char *prog; 679 bool found; 680 }; 681 682 static 683 atf_error_t 684 check_prog(const char *prog, void *data) 685 { 686 atf_error_t err; 687 atf_fs_path_t p; 688 689 err = atf_fs_path_init_fmt(&p, "%s", prog); 690 if (atf_is_error(err)) 691 goto out; 692 693 if (atf_fs_path_is_absolute(&p)) { 694 if (atf_is_error(atf_fs_eaccess(&p, atf_fs_access_x))) 695 atf_tc_skip("The required program %s could not be found", prog); 696 } else { 697 const char *path = atf_env_get("PATH"); 698 struct prog_found_pair pf; 699 atf_fs_path_t bp; 700 701 err = atf_fs_path_branch_path(&p, &bp); 702 if (atf_is_error(err)) 703 goto out_p; 704 705 if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) 706 atf_tc_fail("Relative paths are not allowed when searching for " 707 "a program (%s)", prog); 708 709 pf.prog = prog; 710 pf.found = false; 711 err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf); 712 if (atf_is_error(err)) 713 goto out_bp; 714 715 if (!pf.found) 716 atf_tc_skip("The required program %s could not be found in " 717 "the PATH", prog); 718 719 out_bp: 720 atf_fs_path_fini(&bp); 721 } 722 723 out_p: 724 atf_fs_path_fini(&p); 725 out: 726 return err; 727 } 728 729 static 730 atf_error_t 731 check_prog_in_dir(const char *dir, void *data) 732 { 733 struct prog_found_pair *pf = data; 734 atf_error_t err; 735 736 if (pf->found) 737 err = atf_no_error(); 738 else { 739 atf_fs_path_t p; 740 741 err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog); 742 if (atf_is_error(err)) 743 goto out_p; 744 745 if (!atf_is_error(atf_fs_eaccess(&p, atf_fs_access_x))) 746 pf->found = true; 747 748 out_p: 749 atf_fs_path_fini(&p); 750 } 751 752 return err; 753 } 754 755 static 756 atf_error_t 757 check_requirements(const atf_tc_t *tc) 758 { 759 atf_error_t err; 760 761 err = atf_no_error(); 762 763 if (atf_tc_has_md_var(tc, "require.arch")) { 764 const char *arches = atf_tc_get_md_var(tc, "require.arch"); 765 bool found = false; 766 767 if (strlen(arches) == 0) 768 atf_tc_fail("Invalid value in the require.arch property"); 769 else { 770 err = atf_text_for_each_word(arches, " ", check_arch, &found); 771 if (atf_is_error(err)) 772 goto out; 773 774 if (!found) 775 atf_tc_skip("Requires one of the '%s' architectures", 776 arches); 777 } 778 } 779 780 if (atf_tc_has_md_var(tc, "require.config")) { 781 const char *vars = atf_tc_get_md_var(tc, "require.config"); 782 783 if (strlen(vars) == 0) 784 atf_tc_fail("Invalid value in the require.config property"); 785 else { 786 err = atf_text_for_each_word(vars, " ", check_config, NULL); 787 if (atf_is_error(err)) 788 goto out; 789 } 790 } 791 792 if (atf_tc_has_md_var(tc, "require.machine")) { 793 const char *machines = atf_tc_get_md_var(tc, "require.machine"); 794 bool found = false; 795 796 if (strlen(machines) == 0) 797 atf_tc_fail("Invalid value in the require.machine property"); 798 else { 799 err = atf_text_for_each_word(machines, " ", check_machine, 800 &found); 801 if (atf_is_error(err)) 802 goto out; 803 804 if (!found) 805 atf_tc_skip("Requires one of the '%s' machine types", 806 machines); 807 } 808 } 809 810 if (atf_tc_has_md_var(tc, "require.progs")) { 811 const char *progs = atf_tc_get_md_var(tc, "require.progs"); 812 813 if (strlen(progs) == 0) 814 atf_tc_fail("Invalid value in the require.progs property"); 815 else { 816 err = atf_text_for_each_word(progs, " ", check_prog, NULL); 817 if (atf_is_error(err)) 818 goto out; 819 } 820 } 821 822 if (atf_tc_has_md_var(tc, "require.user")) { 823 const char *u = atf_tc_get_md_var(tc, "require.user"); 824 825 if (strcmp(u, "root") == 0) { 826 if (!atf_user_is_root()) 827 atf_tc_skip("Requires root privileges"); 828 } else if (strcmp(u, "unprivileged") == 0) { 829 if (atf_user_is_root()) 830 atf_tc_skip("Requires an unprivileged user"); 831 } else 832 atf_tc_fail("Invalid value in the require.user property"); 833 } 834 835 INV(!atf_is_error(err)); 836 out: 837 return err; 838 } 839 840 static 841 void 842 cleanup_child(const atf_tc_t *tc, const atf_fs_path_t *workdir) 843 { 844 atf_error_t err; 845 846 atf_disable_exit_checks(); 847 848 err = prepare_child(tc, workdir); 849 if (atf_is_error(err)) 850 exit(EXIT_FAILURE); 851 else { 852 tc->m_cleanup(tc); 853 exit(EXIT_SUCCESS); 854 } 855 856 UNREACHABLE; 857 abort(); 858 } 859 860 static 861 void 862 fatal_atf_error(const char *prefix, atf_error_t err) 863 { 864 char buf[1024]; 865 866 INV(atf_is_error(err)); 867 868 atf_error_format(err, buf, sizeof(buf)); 869 atf_error_free(err); 870 871 fprintf(stderr, "%s: %s", prefix, buf); 872 873 abort(); 874 } 875 876 static 877 void 878 fatal_libc_error(const char *prefix, int err) 879 { 880 fprintf(stderr, "%s: %s", prefix, strerror(err)); 881 882 abort(); 883 } 884 885 static 886 void 887 write_tcr(const atf_tcr_t *tcr) 888 { 889 atf_error_t err; 890 int fd; 891 atf_fs_path_t tcrfile; 892 893 err = atf_fs_path_copy(&tcrfile, current_workdir); 894 if (atf_is_error(err)) 895 fatal_atf_error("Cannot write test case results", err); 896 897 err = atf_fs_path_append_fmt(&tcrfile, "tc-result"); 898 if (atf_is_error(err)) 899 fatal_atf_error("Cannot write test case results", err); 900 901 fd = open(atf_fs_path_cstring(&tcrfile), 902 O_WRONLY | O_CREAT | O_TRUNC, 0755); 903 if (fd == -1) 904 fatal_libc_error("Cannot write test case results", errno); 905 906 err = atf_tcr_serialize(tcr, fd); 907 if (atf_is_error(err)) 908 fatal_atf_error("Cannot write test case results", err); 909 910 close(fd); 911 } 912 913 void 914 atf_tc_fail(const char *fmt, ...) 915 { 916 va_list ap; 917 atf_tcr_t tcr; 918 atf_error_t err; 919 920 PRE(current_tc != NULL); 921 922 va_start(ap, fmt); 923 err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap); 924 va_end(ap); 925 if (atf_is_error(err)) 926 abort(); 927 928 write_tcr(&tcr); 929 930 atf_tcr_fini(&tcr); 931 932 exit(EXIT_SUCCESS); 933 } 934 935 void 936 atf_tc_fail_nonfatal(const char *fmt, ...) 937 { 938 va_list ap; 939 940 va_start(ap, fmt); 941 vfprintf(stderr, fmt, ap); 942 va_end(ap); 943 fprintf(stderr, "\n"); 944 945 current_tc_fail_count++; 946 } 947 948 void 949 atf_tc_fail_check(const char *file, int line, const char *fmt, ...) 950 { 951 va_list ap; 952 953 va_start(ap, fmt); 954 fail_internal(file, line, "Check failed", "*** ", fmt, ap, 955 atf_tc_fail_nonfatal); 956 va_end(ap); 957 } 958 959 void 960 atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...) 961 { 962 va_list ap; 963 964 va_start(ap, fmt); 965 fail_internal(file, line, "Requirement failed", "", fmt, ap, 966 atf_tc_fail); 967 va_end(ap); 968 969 UNREACHABLE; 970 abort(); 971 } 972 973 static 974 void 975 fail_internal(const char *file, int line, const char *reason, 976 const char *prefix, const char *fmt, va_list ap, 977 void (*failfunc)(const char *, ...)) 978 { 979 va_list ap2; 980 atf_error_t err; 981 atf_dynstr_t msg; 982 983 err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line, 984 reason); 985 if (atf_is_error(err)) 986 goto backup; 987 988 va_copy(ap2, ap); 989 err = atf_dynstr_append_ap(&msg, fmt, ap2); 990 va_end(ap2); 991 if (atf_is_error(err)) { 992 atf_dynstr_fini(&msg); 993 goto backup; 994 } 995 996 va_copy(ap2, ap); 997 failfunc("%s", atf_dynstr_cstring(&msg)); 998 atf_dynstr_fini(&msg); 999 return; 1000 1001 backup: 1002 va_copy(ap2, ap); 1003 failfunc(fmt, ap2); 1004 va_end(ap2); 1005 } 1006 1007 void 1008 atf_tc_pass(void) 1009 { 1010 atf_tcr_t tcr; 1011 atf_error_t err; 1012 1013 PRE(current_tc != NULL); 1014 1015 err = atf_tcr_init(&tcr, atf_tcr_passed_state); 1016 if (atf_is_error(err)) 1017 abort(); 1018 1019 write_tcr(&tcr); 1020 1021 atf_tcr_fini(&tcr); 1022 1023 exit(EXIT_SUCCESS); 1024 } 1025 1026 void 1027 atf_tc_require_prog(const char *prog) 1028 { 1029 atf_error_t err; 1030 1031 err = check_prog(prog, NULL); 1032 if (atf_is_error(err)) 1033 atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */ 1034 } 1035 1036 void 1037 atf_tc_skip(const char *fmt, ...) 1038 { 1039 va_list ap; 1040 atf_tcr_t tcr; 1041 atf_error_t err; 1042 1043 PRE(current_tc != NULL); 1044 1045 va_start(ap, fmt); 1046 err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap); 1047 va_end(ap); 1048 if (atf_is_error(err)) 1049 abort(); 1050 1051 write_tcr(&tcr); 1052 1053 atf_tcr_fini(&tcr); 1054 1055 exit(EXIT_SUCCESS); 1056 } 1057