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/detail/process.h" 27 28 #include <sys/types.h> 29 #ifdef __FreeBSD__ 30 #include <sys/sysctl.h> 31 #endif 32 #include <sys/time.h> 33 #include <sys/resource.h> 34 #include <sys/wait.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <signal.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <atf-c.h> 45 46 #include "atf-c/defs.h" 47 #include "atf-c/detail/sanity.h" 48 #include "atf-c/detail/test_helpers.h" 49 50 atf_error_t atf_process_status_init(atf_process_status_t *, int); 51 52 /* --------------------------------------------------------------------- 53 * Auxiliary functions for testing of 'atf_process_fork'. 54 * --------------------------------------------------------------------- */ 55 56 /* 57 * Testing of atf_process_fork is quite messy. We want to be able to test 58 * all the possible combinations of stdout and stderr behavior to ensure 59 * that the streams are manipulated correctly. 60 * 61 * To do this, the do_fork function is a wrapper for atf_process_fork that 62 * issues stream-specific hooks before fork, while the child is running and 63 * after the child terminates. We then provide test cases that just call 64 * do_fork with different hooks. 65 * 66 * The hooks are described by base_stream, and we then have one *_stream 67 * type for ever possible stream behavior. 68 */ 69 70 enum out_type { stdout_type, stderr_type }; 71 72 struct base_stream { 73 void (*init)(void *); 74 void (*process)(void *, atf_process_child_t *); 75 void (*fini)(void *); 76 77 /* m_sb is initialized by subclasses that need it, but all consumers 78 * must use m_sb_ptr, which may or may not point to m_sb. This allows 79 * us to test the interface with a NULL value, which triggers a 80 * default behavior. */ 81 atf_process_stream_t m_sb; 82 atf_process_stream_t *m_sb_ptr; 83 enum out_type m_type; 84 }; 85 #define BASE_STREAM(ihook, phook, fhook, type) \ 86 { .init = ihook, \ 87 .process = phook, \ 88 .fini = fhook, \ 89 .m_type = type } 90 91 static 92 void 93 check_file(const enum out_type type) 94 { 95 switch (type) { 96 case stdout_type: 97 ATF_CHECK(atf_utils_grep_file("stdout: msg", "stdout")); 98 ATF_CHECK(!atf_utils_grep_file("stderr: msg", "stdout")); 99 break; 100 case stderr_type: 101 ATF_CHECK(atf_utils_grep_file("stderr: msg", "stderr")); 102 ATF_CHECK(!atf_utils_grep_file("stdout: msg", "stderr")); 103 break; 104 default: 105 UNREACHABLE; 106 } 107 } 108 109 struct capture_stream { 110 struct base_stream m_base; 111 112 char *m_msg; 113 }; 114 #define CAPTURE_STREAM(type) \ 115 { .m_base = BASE_STREAM(capture_stream_init, \ 116 capture_stream_process, \ 117 capture_stream_fini, \ 118 type) } 119 120 static 121 void 122 capture_stream_init(void *v) 123 { 124 struct capture_stream *s = v; 125 126 s->m_base.m_sb_ptr = &s->m_base.m_sb; 127 RE(atf_process_stream_init_capture(&s->m_base.m_sb)); 128 s->m_msg = NULL; 129 } 130 131 static 132 void 133 capture_stream_process(void *v, atf_process_child_t *c) 134 { 135 struct capture_stream *s = v; 136 137 switch (s->m_base.m_type) { 138 case stdout_type: 139 s->m_msg = atf_utils_readline(atf_process_child_stdout(c)); 140 break; 141 case stderr_type: 142 s->m_msg = atf_utils_readline(atf_process_child_stderr(c)); 143 break; 144 default: 145 UNREACHABLE; 146 } 147 } 148 149 static 150 void 151 capture_stream_fini(void *v) 152 { 153 struct capture_stream *s = v; 154 155 switch (s->m_base.m_type) { 156 case stdout_type: 157 ATF_CHECK(atf_utils_grep_string("stdout: msg", s->m_msg)); 158 ATF_CHECK(!atf_utils_grep_string("stderr: msg", s->m_msg)); 159 break; 160 case stderr_type: 161 ATF_CHECK(!atf_utils_grep_string("stdout: msg", s->m_msg)); 162 ATF_CHECK(atf_utils_grep_string("stderr: msg", s->m_msg)); 163 break; 164 default: 165 UNREACHABLE; 166 } 167 168 free(s->m_msg); 169 atf_process_stream_fini(&s->m_base.m_sb); 170 } 171 172 struct connect_stream { 173 struct base_stream m_base; 174 175 int m_fd; 176 }; 177 #define CONNECT_STREAM(type) \ 178 { .m_base = BASE_STREAM(connect_stream_init, \ 179 NULL, \ 180 connect_stream_fini, \ 181 type) } 182 183 static 184 void 185 connect_stream_init(void *v) 186 { 187 struct connect_stream *s = v; 188 int src_fd; 189 190 switch (s->m_base.m_type) { 191 case stdout_type: 192 src_fd = STDOUT_FILENO; 193 s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644); 194 break; 195 case stderr_type: 196 src_fd = STDERR_FILENO; 197 s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644); 198 break; 199 default: 200 UNREACHABLE; 201 src_fd = -1; 202 } 203 ATF_REQUIRE(s->m_fd != -1); 204 205 s->m_base.m_sb_ptr = &s->m_base.m_sb; 206 RE(atf_process_stream_init_connect(&s->m_base.m_sb, src_fd, s->m_fd)); 207 } 208 209 static 210 void 211 connect_stream_fini(void *v) 212 { 213 struct connect_stream *s = v; 214 215 ATF_REQUIRE(close(s->m_fd) != -1); 216 217 atf_process_stream_fini(&s->m_base.m_sb); 218 219 check_file(s->m_base.m_type); 220 } 221 222 struct inherit_stream { 223 struct base_stream m_base; 224 int m_fd; 225 226 int m_old_fd; 227 }; 228 #define INHERIT_STREAM(type) \ 229 { .m_base = BASE_STREAM(inherit_stream_init, \ 230 NULL, \ 231 inherit_stream_fini, \ 232 type) } 233 234 static 235 void 236 inherit_stream_init(void *v) 237 { 238 struct inherit_stream *s = v; 239 const char *name; 240 241 s->m_base.m_sb_ptr = &s->m_base.m_sb; 242 RE(atf_process_stream_init_inherit(&s->m_base.m_sb)); 243 244 switch (s->m_base.m_type) { 245 case stdout_type: 246 s->m_fd = STDOUT_FILENO; 247 name = "stdout"; 248 break; 249 case stderr_type: 250 s->m_fd = STDERR_FILENO; 251 name = "stderr"; 252 break; 253 default: 254 UNREACHABLE; 255 name = NULL; 256 } 257 258 s->m_old_fd = dup(s->m_fd); 259 ATF_REQUIRE(s->m_old_fd != -1); 260 ATF_REQUIRE(close(s->m_fd) != -1); 261 ATF_REQUIRE_EQ(open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644), 262 s->m_fd); 263 } 264 265 static 266 void 267 inherit_stream_fini(void *v) 268 { 269 struct inherit_stream *s = v; 270 271 ATF_REQUIRE(dup2(s->m_old_fd, s->m_fd) != -1); 272 ATF_REQUIRE(close(s->m_old_fd) != -1); 273 274 atf_process_stream_fini(&s->m_base.m_sb); 275 276 check_file(s->m_base.m_type); 277 } 278 279 #define default_stream inherit_stream 280 #define DEFAULT_STREAM(type) \ 281 { .m_base = BASE_STREAM(default_stream_init, \ 282 NULL, \ 283 default_stream_fini, \ 284 type) } 285 286 static 287 void 288 default_stream_init(void *v) 289 { 290 struct inherit_stream *s = v; 291 292 inherit_stream_init(v); 293 s->m_base.m_sb_ptr = NULL; 294 } 295 296 static 297 void 298 default_stream_fini(void *v) 299 { 300 inherit_stream_fini(v); 301 } 302 303 struct redirect_fd_stream { 304 struct base_stream m_base; 305 306 int m_fd; 307 }; 308 #define REDIRECT_FD_STREAM(type) \ 309 { .m_base = BASE_STREAM(redirect_fd_stream_init, \ 310 NULL, \ 311 redirect_fd_stream_fini, \ 312 type) } 313 314 static 315 void 316 redirect_fd_stream_init(void *v) 317 { 318 struct redirect_fd_stream *s = v; 319 320 switch (s->m_base.m_type) { 321 case stdout_type: 322 s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644); 323 break; 324 case stderr_type: 325 s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644); 326 break; 327 default: 328 UNREACHABLE; 329 } 330 ATF_REQUIRE(s->m_fd != -1); 331 332 s->m_base.m_sb_ptr = &s->m_base.m_sb; 333 RE(atf_process_stream_init_redirect_fd(&s->m_base.m_sb, s->m_fd)); 334 } 335 336 static 337 void 338 redirect_fd_stream_fini(void *v) 339 { 340 struct redirect_fd_stream *s = v; 341 342 ATF_REQUIRE(close(s->m_fd) != -1); 343 344 atf_process_stream_fini(&s->m_base.m_sb); 345 346 check_file(s->m_base.m_type); 347 } 348 349 struct redirect_path_stream { 350 struct base_stream m_base; 351 352 atf_fs_path_t m_path; 353 }; 354 #define REDIRECT_PATH_STREAM(type) \ 355 { .m_base = BASE_STREAM(redirect_path_stream_init, \ 356 NULL, \ 357 redirect_path_stream_fini, \ 358 type) } 359 360 static 361 void 362 redirect_path_stream_init(void *v) 363 { 364 struct redirect_path_stream *s = v; 365 366 switch (s->m_base.m_type) { 367 case stdout_type: 368 RE(atf_fs_path_init_fmt(&s->m_path, "stdout")); 369 break; 370 case stderr_type: 371 RE(atf_fs_path_init_fmt(&s->m_path, "stderr")); 372 break; 373 default: 374 UNREACHABLE; 375 } 376 377 s->m_base.m_sb_ptr = &s->m_base.m_sb; 378 RE(atf_process_stream_init_redirect_path(&s->m_base.m_sb, &s->m_path)); 379 } 380 381 static 382 void 383 redirect_path_stream_fini(void *v) 384 { 385 struct redirect_path_stream *s = v; 386 387 atf_process_stream_fini(&s->m_base.m_sb); 388 389 atf_fs_path_fini(&s->m_path); 390 391 check_file(s->m_base.m_type); 392 } 393 394 static void child_print(void *) ATF_DEFS_ATTRIBUTE_NORETURN; 395 396 struct child_print_data { 397 const char *m_msg; 398 }; 399 400 static 401 void 402 child_print(void *v) 403 { 404 struct child_print_data *cpd = v; 405 406 fprintf(stdout, "stdout: %s\n", cpd->m_msg); 407 fprintf(stderr, "stderr: %s\n", cpd->m_msg); 408 409 exit(EXIT_SUCCESS); 410 } 411 412 static 413 void 414 do_fork(const struct base_stream *outfs, void *out, 415 const struct base_stream *errfs, void *err) 416 { 417 atf_process_child_t child; 418 atf_process_status_t status; 419 struct child_print_data cpd = { "msg" }; 420 421 outfs->init(out); 422 errfs->init(err); 423 424 RE(atf_process_fork(&child, child_print, outfs->m_sb_ptr, 425 errfs->m_sb_ptr, &cpd)); 426 if (outfs->process != NULL) 427 outfs->process(out, &child); 428 if (errfs->process != NULL) 429 errfs->process(err, &child); 430 RE(atf_process_child_wait(&child, &status)); 431 432 outfs->fini(out); 433 errfs->fini(err); 434 435 atf_process_status_fini(&status); 436 } 437 438 /* --------------------------------------------------------------------- 439 * Test cases for the "stream" type. 440 * --------------------------------------------------------------------- */ 441 442 ATF_TC(stream_init_capture); 443 ATF_TC_HEAD(stream_init_capture, tc) 444 { 445 atf_tc_set_md_var(tc, "descr", "Tests the " 446 "atf_process_stream_init_capture function"); 447 } 448 ATF_TC_BODY(stream_init_capture, tc) 449 { 450 atf_process_stream_t sb; 451 452 RE(atf_process_stream_init_capture(&sb)); 453 454 ATF_CHECK_EQ(atf_process_stream_type(&sb), 455 atf_process_stream_type_capture); 456 457 atf_process_stream_fini(&sb); 458 } 459 460 ATF_TC(stream_init_connect); 461 ATF_TC_HEAD(stream_init_connect, tc) 462 { 463 atf_tc_set_md_var(tc, "descr", "Tests the " 464 "atf_process_stream_init_connect function"); 465 } 466 ATF_TC_BODY(stream_init_connect, tc) 467 { 468 atf_process_stream_t sb; 469 470 RE(atf_process_stream_init_connect(&sb, 1, 2)); 471 472 ATF_CHECK_EQ(atf_process_stream_type(&sb), 473 atf_process_stream_type_connect); 474 475 atf_process_stream_fini(&sb); 476 } 477 478 ATF_TC(stream_init_inherit); 479 ATF_TC_HEAD(stream_init_inherit, tc) 480 { 481 atf_tc_set_md_var(tc, "descr", "Tests the " 482 "atf_process_stream_init_inherit function"); 483 } 484 ATF_TC_BODY(stream_init_inherit, tc) 485 { 486 atf_process_stream_t sb; 487 488 RE(atf_process_stream_init_inherit(&sb)); 489 490 ATF_CHECK_EQ(atf_process_stream_type(&sb), 491 atf_process_stream_type_inherit); 492 493 atf_process_stream_fini(&sb); 494 } 495 496 ATF_TC(stream_init_redirect_fd); 497 ATF_TC_HEAD(stream_init_redirect_fd, tc) 498 { 499 atf_tc_set_md_var(tc, "descr", "Tests the " 500 "atf_process_stream_init_redirect_fd function"); 501 } 502 ATF_TC_BODY(stream_init_redirect_fd, tc) 503 { 504 atf_process_stream_t sb; 505 506 RE(atf_process_stream_init_redirect_fd(&sb, 1)); 507 508 ATF_CHECK_EQ(atf_process_stream_type(&sb), 509 atf_process_stream_type_redirect_fd); 510 511 atf_process_stream_fini(&sb); 512 } 513 514 ATF_TC(stream_init_redirect_path); 515 ATF_TC_HEAD(stream_init_redirect_path, tc) 516 { 517 atf_tc_set_md_var(tc, "descr", "Tests the " 518 "atf_process_stream_init_redirect_path function"); 519 } 520 ATF_TC_BODY(stream_init_redirect_path, tc) 521 { 522 atf_process_stream_t sb; 523 atf_fs_path_t path; 524 525 RE(atf_fs_path_init_fmt(&path, "foo")); 526 RE(atf_process_stream_init_redirect_path(&sb, &path)); 527 528 ATF_CHECK_EQ(atf_process_stream_type(&sb), 529 atf_process_stream_type_redirect_path); 530 531 atf_process_stream_fini(&sb); 532 atf_fs_path_fini(&path); 533 } 534 535 /* --------------------------------------------------------------------- 536 * Test cases for the "status" type. 537 * --------------------------------------------------------------------- */ 538 539 static void child_exit_success(void) ATF_DEFS_ATTRIBUTE_NORETURN; 540 static void child_exit_failure(void) ATF_DEFS_ATTRIBUTE_NORETURN; 541 static void child_sigkill(void) ATF_DEFS_ATTRIBUTE_NORETURN; 542 static void child_sigquit(void) ATF_DEFS_ATTRIBUTE_NORETURN; 543 static void child_sigterm(void) ATF_DEFS_ATTRIBUTE_NORETURN; 544 545 void 546 child_exit_success(void) 547 { 548 exit(EXIT_SUCCESS); 549 } 550 551 void 552 child_exit_failure(void) 553 { 554 exit(EXIT_FAILURE); 555 } 556 557 void 558 child_sigkill(void) 559 { 560 kill(getpid(), SIGKILL); 561 abort(); 562 } 563 564 void 565 child_sigquit(void) 566 { 567 kill(getpid(), SIGQUIT); 568 abort(); 569 } 570 571 void 572 child_sigterm(void) 573 { 574 kill(getpid(), SIGTERM); 575 abort(); 576 } 577 578 static 579 int 580 fork_and_wait_child(void (*child_func)(void)) 581 { 582 pid_t pid; 583 int status; 584 585 pid = fork(); 586 ATF_REQUIRE(pid != -1); 587 if (pid == 0) { 588 status = 0; /* Silence compiler warnings */ 589 child_func(); 590 UNREACHABLE; 591 } else { 592 ATF_REQUIRE(waitpid(pid, &status, 0) != 0); 593 } 594 595 return status; 596 } 597 598 ATF_TC(status_exited); 599 ATF_TC_HEAD(status_exited, tc) 600 { 601 atf_tc_set_md_var(tc, "descr", "Tests the status type for processes " 602 "that exit cleanly"); 603 } 604 ATF_TC_BODY(status_exited, tc) 605 { 606 { 607 const int rawstatus = fork_and_wait_child(child_exit_success); 608 atf_process_status_t s; 609 RE(atf_process_status_init(&s, rawstatus)); 610 ATF_CHECK(atf_process_status_exited(&s)); 611 ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_SUCCESS); 612 ATF_CHECK(!atf_process_status_signaled(&s)); 613 atf_process_status_fini(&s); 614 } 615 616 { 617 const int rawstatus = fork_and_wait_child(child_exit_failure); 618 atf_process_status_t s; 619 RE(atf_process_status_init(&s, rawstatus)); 620 ATF_CHECK(atf_process_status_exited(&s)); 621 ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_FAILURE); 622 ATF_CHECK(!atf_process_status_signaled(&s)); 623 atf_process_status_fini(&s); 624 } 625 } 626 627 ATF_TC(status_signaled); 628 ATF_TC_HEAD(status_signaled, tc) 629 { 630 atf_tc_set_md_var(tc, "descr", "Tests the status type for processes " 631 "that end due to a signal"); 632 } 633 ATF_TC_BODY(status_signaled, tc) 634 { 635 { 636 const int rawstatus = fork_and_wait_child(child_sigkill); 637 atf_process_status_t s; 638 RE(atf_process_status_init(&s, rawstatus)); 639 ATF_CHECK(!atf_process_status_exited(&s)); 640 ATF_CHECK(atf_process_status_signaled(&s)); 641 ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGKILL); 642 ATF_CHECK(!atf_process_status_coredump(&s)); 643 atf_process_status_fini(&s); 644 } 645 646 { 647 const int rawstatus = fork_and_wait_child(child_sigterm); 648 atf_process_status_t s; 649 RE(atf_process_status_init(&s, rawstatus)); 650 ATF_CHECK(!atf_process_status_exited(&s)); 651 ATF_CHECK(atf_process_status_signaled(&s)); 652 ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGTERM); 653 ATF_CHECK(!atf_process_status_coredump(&s)); 654 atf_process_status_fini(&s); 655 } 656 } 657 658 ATF_TC(status_coredump); 659 ATF_TC_HEAD(status_coredump, tc) 660 { 661 atf_tc_set_md_var(tc, "descr", "Tests the status type for processes " 662 "that crash"); 663 } 664 ATF_TC_BODY(status_coredump, tc) 665 { 666 struct rlimit rl; 667 rl.rlim_cur = RLIM_INFINITY; 668 rl.rlim_max = RLIM_INFINITY; 669 if (setrlimit(RLIMIT_CORE, &rl) == -1) 670 atf_tc_skip("Cannot unlimit the core file size; check limits " 671 "manually"); 672 673 #ifdef __FreeBSD__ 674 int coredump_enabled; 675 size_t ce_len = sizeof(coredump_enabled); 676 if (sysctlbyname("kern.coredump", &coredump_enabled, &ce_len, NULL, 677 0) == 0 && !coredump_enabled) 678 atf_tc_skip("Coredumps disabled"); 679 #endif 680 681 const int rawstatus = fork_and_wait_child(child_sigquit); 682 atf_process_status_t s; 683 RE(atf_process_status_init(&s, rawstatus)); 684 ATF_CHECK(!atf_process_status_exited(&s)); 685 ATF_CHECK(atf_process_status_signaled(&s)); 686 ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGQUIT); 687 ATF_CHECK(atf_process_status_coredump(&s)); 688 atf_process_status_fini(&s); 689 } 690 691 /* --------------------------------------------------------------------- 692 * Test cases for the "child" type. 693 * --------------------------------------------------------------------- */ 694 695 static void child_report_pid(void *) ATF_DEFS_ATTRIBUTE_NORETURN; 696 697 static 698 void 699 child_report_pid(void *v ATF_DEFS_ATTRIBUTE_UNUSED) 700 { 701 const pid_t pid = getpid(); 702 if (write(STDOUT_FILENO, &pid, sizeof(pid)) != sizeof(pid)) 703 abort(); 704 fprintf(stderr, "Reporting %d to parent\n", (int)getpid()); 705 exit(EXIT_SUCCESS); 706 } 707 708 ATF_TC(child_pid); 709 ATF_TC_HEAD(child_pid, tc) 710 { 711 atf_tc_set_md_var(tc, "descr", "Tests the correctness of the pid " 712 "stored in the child type"); 713 } 714 ATF_TC_BODY(child_pid, tc) 715 { 716 atf_process_stream_t outsb, errsb; 717 atf_process_child_t child; 718 atf_process_status_t status; 719 pid_t pid; 720 721 RE(atf_process_stream_init_capture(&outsb)); 722 RE(atf_process_stream_init_inherit(&errsb)); 723 724 RE(atf_process_fork(&child, child_report_pid, &outsb, &errsb, NULL)); 725 ATF_CHECK_EQ(read(atf_process_child_stdout(&child), &pid, sizeof(pid)), 726 sizeof(pid)); 727 printf("Expected PID: %d\n", (int)atf_process_child_pid(&child)); 728 printf("Actual PID: %d\n", (int)pid); 729 ATF_CHECK_EQ(atf_process_child_pid(&child), pid); 730 731 RE(atf_process_child_wait(&child, &status)); 732 atf_process_status_fini(&status); 733 734 atf_process_stream_fini(&outsb); 735 atf_process_stream_fini(&errsb); 736 } 737 738 static 739 void 740 child_loop(void *v ATF_DEFS_ATTRIBUTE_UNUSED) 741 { 742 for (;;) 743 sleep(1); 744 } 745 746 static 747 void 748 nop_signal(int sig ATF_DEFS_ATTRIBUTE_UNUSED) 749 { 750 } 751 752 static 753 void 754 child_spawn_loop_and_wait_eintr(void *v ATF_DEFS_ATTRIBUTE_UNUSED) 755 { 756 atf_process_child_t child; 757 atf_process_status_t status; 758 struct sigaction sighup, old_sighup; 759 760 #define RE_ABORT(expr) \ 761 do { \ 762 atf_error_t _aux_err = expr; \ 763 if (atf_is_error(_aux_err)) { \ 764 atf_error_free(_aux_err); \ 765 abort(); \ 766 } \ 767 } while (0) 768 769 { 770 atf_process_stream_t outsb, errsb; 771 772 RE_ABORT(atf_process_stream_init_capture(&outsb)); 773 RE_ABORT(atf_process_stream_init_inherit(&errsb)); 774 RE_ABORT(atf_process_fork(&child, child_loop, &outsb, &errsb, NULL)); 775 atf_process_stream_fini(&outsb); 776 atf_process_stream_fini(&errsb); 777 } 778 779 sighup.sa_handler = nop_signal; 780 sigemptyset(&sighup.sa_mask); 781 sighup.sa_flags = 0; 782 if (sigaction(SIGHUP, &sighup, &old_sighup) == -1) 783 abort(); 784 785 printf("waiting\n"); 786 fflush(stdout); 787 788 fprintf(stderr, "Child entering wait(2)\n"); 789 atf_error_t err = atf_process_child_wait(&child, &status); 790 fprintf(stderr, "Child's wait(2) terminated\n"); 791 if (!atf_is_error(err)) { 792 fprintf(stderr, "wait completed successfully (not interrupted)\n"); 793 abort(); 794 } 795 if (!atf_error_is(err, "libc")) { 796 fprintf(stderr, "wait did not raise libc_error\n"); 797 abort(); 798 } 799 if (atf_libc_error_code(err) != EINTR) { 800 fprintf(stderr, "libc_error is not EINTR\n"); 801 abort(); 802 } 803 atf_error_free(err); 804 805 sigaction(SIGHUP, &old_sighup, NULL); 806 807 fprintf(stderr, "Child is killing subchild\n"); 808 kill(atf_process_child_pid(&child), SIGTERM); 809 810 RE_ABORT(atf_process_child_wait(&child, &status)); 811 atf_process_status_fini(&status); 812 813 #undef RE_ABORT 814 815 exit(EXIT_SUCCESS); 816 } 817 818 ATF_TC(child_wait_eintr); 819 ATF_TC_HEAD(child_wait_eintr, tc) 820 { 821 atf_tc_set_md_var(tc, "descr", "Tests the interruption of the wait " 822 "method by an external signal, and the return of " 823 "an EINTR error"); 824 atf_tc_set_md_var(tc, "timeout", "30"); 825 } 826 ATF_TC_BODY(child_wait_eintr, tc) 827 { 828 atf_process_child_t child; 829 atf_process_status_t status; 830 831 { 832 atf_process_stream_t outsb, errsb; 833 834 RE(atf_process_stream_init_capture(&outsb)); 835 RE(atf_process_stream_init_inherit(&errsb)); 836 RE(atf_process_fork(&child, child_spawn_loop_and_wait_eintr, 837 &outsb, &errsb, NULL)); 838 atf_process_stream_fini(&outsb); 839 atf_process_stream_fini(&errsb); 840 } 841 842 { 843 /* Wait until the child process performs the wait call. This is 844 * racy, because the message we get from it is sent *before* 845 * doing the real system call... but I can't figure any other way 846 * to do this. */ 847 char buf[16]; 848 printf("Waiting for child to issue wait(2)\n"); 849 ATF_REQUIRE(read(atf_process_child_stdout(&child), buf, 850 sizeof(buf)) > 0); 851 sleep(1); 852 } 853 854 printf("Interrupting child's wait(2) call\n"); 855 kill(atf_process_child_pid(&child), SIGHUP); 856 857 printf("Waiting for child's completion\n"); 858 RE(atf_process_child_wait(&child, &status)); 859 ATF_REQUIRE(atf_process_status_exited(&status)); 860 ATF_REQUIRE_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS); 861 atf_process_status_fini(&status); 862 } 863 864 /* --------------------------------------------------------------------- 865 * Tests cases for the free functions. 866 * --------------------------------------------------------------------- */ 867 868 static 869 void 870 do_exec(const atf_tc_t *tc, const char *helper_name, atf_process_status_t *s, 871 void (*prehook)(void)) 872 { 873 atf_fs_path_t process_helpers; 874 const char *argv[3]; 875 876 get_process_helpers_path(tc, true, &process_helpers); 877 878 argv[0] = atf_fs_path_cstring(&process_helpers); 879 argv[1] = helper_name; 880 argv[2] = NULL; 881 printf("Executing %s %s\n", argv[0], argv[1]); 882 883 RE(atf_process_exec_array(s, &process_helpers, argv, NULL, NULL, prehook)); 884 atf_fs_path_fini(&process_helpers); 885 } 886 887 static 888 void 889 check_line(int fd, const char *exp) 890 { 891 char *line = atf_utils_readline(fd); 892 ATF_CHECK(line != NULL); 893 ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp); 894 free(line); 895 } 896 897 ATF_TC(exec_failure); 898 ATF_TC_HEAD(exec_failure, tc) 899 { 900 atf_tc_set_md_var(tc, "descr", "Tests execing a command"); 901 } 902 ATF_TC_BODY(exec_failure, tc) 903 { 904 atf_process_status_t status; 905 906 do_exec(tc, "exit-failure", &status, NULL); 907 ATF_CHECK(atf_process_status_exited(&status)); 908 ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_FAILURE); 909 atf_process_status_fini(&status); 910 } 911 912 ATF_TC(exec_list); 913 ATF_TC_HEAD(exec_list, tc) 914 { 915 atf_tc_set_md_var(tc, "descr", "Tests execing a command"); 916 } 917 ATF_TC_BODY(exec_list, tc) 918 { 919 atf_fs_path_t process_helpers; 920 atf_list_t argv; 921 atf_process_status_t status; 922 923 RE(atf_list_init(&argv)); 924 925 get_process_helpers_path(tc, true, &process_helpers); 926 atf_list_append(&argv, strdup(atf_fs_path_cstring(&process_helpers)), true); 927 atf_list_append(&argv, strdup("echo"), true); 928 atf_list_append(&argv, strdup("test-message"), true); 929 { 930 atf_fs_path_t outpath; 931 atf_process_stream_t outsb; 932 933 RE(atf_fs_path_init_fmt(&outpath, "stdout")); 934 RE(atf_process_stream_init_redirect_path(&outsb, &outpath)); 935 RE(atf_process_exec_list(&status, &process_helpers, &argv, &outsb, 936 NULL, NULL)); 937 atf_process_stream_fini(&outsb); 938 atf_fs_path_fini(&outpath); 939 } 940 atf_list_fini(&argv); 941 942 ATF_CHECK(atf_process_status_exited(&status)); 943 ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS); 944 945 { 946 int fd = open("stdout", O_RDONLY); 947 ATF_CHECK(fd != -1); 948 check_line(fd, "test-message"); 949 close(fd); 950 } 951 952 atf_process_status_fini(&status); 953 atf_fs_path_fini(&process_helpers); 954 } 955 956 static void 957 exit_early(void) 958 { 959 exit(80); 960 } 961 962 ATF_TC(exec_prehook); 963 ATF_TC_HEAD(exec_prehook, tc) 964 { 965 atf_tc_set_md_var(tc, "descr", "Tests execing a command with a prehook"); 966 } 967 ATF_TC_BODY(exec_prehook, tc) 968 { 969 atf_process_status_t status; 970 971 do_exec(tc, "exit-success", &status, exit_early); 972 ATF_CHECK(atf_process_status_exited(&status)); 973 ATF_CHECK_EQ(atf_process_status_exitstatus(&status), 80); 974 atf_process_status_fini(&status); 975 } 976 977 ATF_TC(exec_success); 978 ATF_TC_HEAD(exec_success, tc) 979 { 980 atf_tc_set_md_var(tc, "descr", "Tests execing a command"); 981 } 982 ATF_TC_BODY(exec_success, tc) 983 { 984 atf_process_status_t status; 985 986 do_exec(tc, "exit-success", &status, NULL); 987 ATF_CHECK(atf_process_status_exited(&status)); 988 ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS); 989 atf_process_status_fini(&status); 990 } 991 992 static const int exit_v_null = 1; 993 static const int exit_v_notnull = 2; 994 995 static 996 void 997 child_cookie(void *v) 998 { 999 if (v == NULL) 1000 exit(exit_v_null); 1001 else 1002 exit(exit_v_notnull); 1003 1004 UNREACHABLE; 1005 } 1006 1007 ATF_TC(fork_cookie); 1008 ATF_TC_HEAD(fork_cookie, tc) 1009 { 1010 atf_tc_set_md_var(tc, "descr", "Tests forking a child, with " 1011 "a null and non-null data cookie"); 1012 } 1013 ATF_TC_BODY(fork_cookie, tc) 1014 { 1015 atf_process_stream_t outsb, errsb; 1016 1017 RE(atf_process_stream_init_inherit(&outsb)); 1018 RE(atf_process_stream_init_inherit(&errsb)); 1019 1020 { 1021 atf_process_child_t child; 1022 atf_process_status_t status; 1023 1024 RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, NULL)); 1025 RE(atf_process_child_wait(&child, &status)); 1026 1027 ATF_CHECK(atf_process_status_exited(&status)); 1028 ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_null); 1029 1030 atf_process_status_fini(&status); 1031 } 1032 1033 { 1034 atf_process_child_t child; 1035 atf_process_status_t status; 1036 int dummy_int; 1037 1038 RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, &dummy_int)); 1039 RE(atf_process_child_wait(&child, &status)); 1040 1041 ATF_CHECK(atf_process_status_exited(&status)); 1042 ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_notnull); 1043 1044 atf_process_status_fini(&status); 1045 } 1046 1047 atf_process_stream_fini(&errsb); 1048 atf_process_stream_fini(&outsb); 1049 } 1050 1051 #define TC_FORK_STREAMS(outlc, outuc, errlc, erruc) \ 1052 ATF_TC(fork_out_ ## outlc ## _err_ ## errlc); \ 1053 ATF_TC_HEAD(fork_out_ ## outlc ## _err_ ## errlc, tc) \ 1054 { \ 1055 atf_tc_set_md_var(tc, "descr", "Tests forking a child, with " \ 1056 "stdout " #outlc " and stderr " #errlc); \ 1057 } \ 1058 ATF_TC_BODY(fork_out_ ## outlc ## _err_ ## errlc, tc) \ 1059 { \ 1060 struct outlc ## _stream out = outuc ## _STREAM(stdout_type); \ 1061 struct errlc ## _stream err = erruc ## _STREAM(stderr_type); \ 1062 do_fork(&out.m_base, &out, &err.m_base, &err); \ 1063 } 1064 1065 TC_FORK_STREAMS(capture, CAPTURE, capture, CAPTURE); 1066 TC_FORK_STREAMS(capture, CAPTURE, connect, CONNECT); 1067 TC_FORK_STREAMS(capture, CAPTURE, default, DEFAULT); 1068 TC_FORK_STREAMS(capture, CAPTURE, inherit, INHERIT); 1069 TC_FORK_STREAMS(capture, CAPTURE, redirect_fd, REDIRECT_FD); 1070 TC_FORK_STREAMS(capture, CAPTURE, redirect_path, REDIRECT_PATH); 1071 TC_FORK_STREAMS(connect, CONNECT, capture, CAPTURE); 1072 TC_FORK_STREAMS(connect, CONNECT, connect, CONNECT); 1073 TC_FORK_STREAMS(connect, CONNECT, default, DEFAULT); 1074 TC_FORK_STREAMS(connect, CONNECT, inherit, INHERIT); 1075 TC_FORK_STREAMS(connect, CONNECT, redirect_fd, REDIRECT_FD); 1076 TC_FORK_STREAMS(connect, CONNECT, redirect_path, REDIRECT_PATH); 1077 TC_FORK_STREAMS(default, DEFAULT, capture, CAPTURE); 1078 TC_FORK_STREAMS(default, DEFAULT, connect, CONNECT); 1079 TC_FORK_STREAMS(default, DEFAULT, default, DEFAULT); 1080 TC_FORK_STREAMS(default, DEFAULT, inherit, INHERIT); 1081 TC_FORK_STREAMS(default, DEFAULT, redirect_fd, REDIRECT_FD); 1082 TC_FORK_STREAMS(default, DEFAULT, redirect_path, REDIRECT_PATH); 1083 TC_FORK_STREAMS(inherit, INHERIT, capture, CAPTURE); 1084 TC_FORK_STREAMS(inherit, INHERIT, connect, CONNECT); 1085 TC_FORK_STREAMS(inherit, INHERIT, default, DEFAULT); 1086 TC_FORK_STREAMS(inherit, INHERIT, inherit, INHERIT); 1087 TC_FORK_STREAMS(inherit, INHERIT, redirect_fd, REDIRECT_FD); 1088 TC_FORK_STREAMS(inherit, INHERIT, redirect_path, REDIRECT_PATH); 1089 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, capture, CAPTURE); 1090 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, connect, CONNECT); 1091 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, default, DEFAULT); 1092 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, inherit, INHERIT); 1093 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_fd, REDIRECT_FD); 1094 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_path, REDIRECT_PATH); 1095 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, capture, CAPTURE); 1096 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, connect, CONNECT); 1097 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, default, DEFAULT); 1098 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, inherit, INHERIT); 1099 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_fd, REDIRECT_FD); 1100 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_path, REDIRECT_PATH); 1101 1102 #undef TC_FORK_STREAMS 1103 1104 /* --------------------------------------------------------------------- 1105 * Main. 1106 * --------------------------------------------------------------------- */ 1107 1108 ATF_TP_ADD_TCS(tp) 1109 { 1110 /* Add the tests for the "stream" type. */ 1111 ATF_TP_ADD_TC(tp, stream_init_capture); 1112 ATF_TP_ADD_TC(tp, stream_init_connect); 1113 ATF_TP_ADD_TC(tp, stream_init_inherit); 1114 ATF_TP_ADD_TC(tp, stream_init_redirect_fd); 1115 ATF_TP_ADD_TC(tp, stream_init_redirect_path); 1116 1117 /* Add the tests for the "status" type. */ 1118 ATF_TP_ADD_TC(tp, status_exited); 1119 ATF_TP_ADD_TC(tp, status_signaled); 1120 ATF_TP_ADD_TC(tp, status_coredump); 1121 1122 /* Add the tests for the "child" type. */ 1123 ATF_TP_ADD_TC(tp, child_pid); 1124 ATF_TP_ADD_TC(tp, child_wait_eintr); 1125 1126 /* Add the tests for the free functions. */ 1127 ATF_TP_ADD_TC(tp, exec_failure); 1128 ATF_TP_ADD_TC(tp, exec_list); 1129 ATF_TP_ADD_TC(tp, exec_prehook); 1130 ATF_TP_ADD_TC(tp, exec_success); 1131 ATF_TP_ADD_TC(tp, fork_cookie); 1132 ATF_TP_ADD_TC(tp, fork_out_capture_err_capture); 1133 ATF_TP_ADD_TC(tp, fork_out_capture_err_connect); 1134 ATF_TP_ADD_TC(tp, fork_out_capture_err_default); 1135 ATF_TP_ADD_TC(tp, fork_out_capture_err_inherit); 1136 ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_fd); 1137 ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_path); 1138 ATF_TP_ADD_TC(tp, fork_out_connect_err_capture); 1139 ATF_TP_ADD_TC(tp, fork_out_connect_err_connect); 1140 ATF_TP_ADD_TC(tp, fork_out_connect_err_default); 1141 ATF_TP_ADD_TC(tp, fork_out_connect_err_inherit); 1142 ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_fd); 1143 ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_path); 1144 ATF_TP_ADD_TC(tp, fork_out_default_err_capture); 1145 ATF_TP_ADD_TC(tp, fork_out_default_err_connect); 1146 ATF_TP_ADD_TC(tp, fork_out_default_err_default); 1147 ATF_TP_ADD_TC(tp, fork_out_default_err_inherit); 1148 ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_fd); 1149 ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_path); 1150 ATF_TP_ADD_TC(tp, fork_out_inherit_err_capture); 1151 ATF_TP_ADD_TC(tp, fork_out_inherit_err_connect); 1152 ATF_TP_ADD_TC(tp, fork_out_inherit_err_default); 1153 ATF_TP_ADD_TC(tp, fork_out_inherit_err_inherit); 1154 ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_fd); 1155 ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_path); 1156 ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_capture); 1157 ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_connect); 1158 ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_default); 1159 ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_inherit); 1160 ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_fd); 1161 ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_path); 1162 ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_capture); 1163 ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_connect); 1164 ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_default); 1165 ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_inherit); 1166 ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_fd); 1167 ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_path); 1168 1169 return atf_no_error(); 1170 } 1171