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