process_test.c revision 275988
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 47atf_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 67enum out_type { stdout_type, stderr_type }; 68 69struct 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 88static 89void 90check_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 106struct 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 117static 118void 119capture_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 128static 129void 130capture_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 146static 147void 148capture_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 169struct 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 180static 181void 182connect_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 206static 207void 208connect_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 219struct 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 231static 232void 233inherit_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 262static 263void 264inherit_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 283static 284void 285default_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 293static 294void 295default_stream_fini(void *v) 296{ 297 inherit_stream_fini(v); 298} 299 300struct 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 311static 312void 313redirect_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 333static 334void 335redirect_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 346struct 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 357static 358void 359redirect_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 378static 379void 380redirect_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 391static void child_print(void *) ATF_DEFS_ATTRIBUTE_NORETURN; 392 393struct child_print_data { 394 const char *m_msg; 395}; 396 397static 398void 399child_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 409static 410void 411do_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 439ATF_TC(stream_init_capture); 440ATF_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} 445ATF_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 457ATF_TC(stream_init_connect); 458ATF_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} 463ATF_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 475ATF_TC(stream_init_inherit); 476ATF_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} 481ATF_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 493ATF_TC(stream_init_redirect_fd); 494ATF_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} 499ATF_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 511ATF_TC(stream_init_redirect_path); 512ATF_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} 517ATF_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 536static void child_exit_success(void) ATF_DEFS_ATTRIBUTE_NORETURN; 537static void child_exit_failure(void) ATF_DEFS_ATTRIBUTE_NORETURN; 538static void child_sigkill(void) ATF_DEFS_ATTRIBUTE_NORETURN; 539static void child_sigquit(void) ATF_DEFS_ATTRIBUTE_NORETURN; 540static void child_sigterm(void) ATF_DEFS_ATTRIBUTE_NORETURN; 541 542void 543child_exit_success(void) 544{ 545 exit(EXIT_SUCCESS); 546} 547 548void 549child_exit_failure(void) 550{ 551 exit(EXIT_FAILURE); 552} 553 554void 555child_sigkill(void) 556{ 557 kill(getpid(), SIGKILL); 558 abort(); 559} 560 561void 562child_sigquit(void) 563{ 564 kill(getpid(), SIGQUIT); 565 abort(); 566} 567 568void 569child_sigterm(void) 570{ 571 kill(getpid(), SIGTERM); 572 abort(); 573} 574 575static 576int 577fork_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 595ATF_TC(status_exited); 596ATF_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} 601ATF_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 624ATF_TC(status_signaled); 625ATF_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} 630ATF_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 655ATF_TC(status_coredump); 656ATF_TC_HEAD(status_coredump, tc) 657{ 658 atf_tc_set_md_var(tc, "descr", "Tests the status type for processes " 659 "that crash"); 660} 661ATF_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 684static void child_report_pid(void *) ATF_DEFS_ATTRIBUTE_NORETURN; 685 686static 687void 688child_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 697ATF_TC(child_pid); 698ATF_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} 703ATF_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 727static 728void 729child_loop(void *v ATF_DEFS_ATTRIBUTE_UNUSED) 730{ 731 for (;;) 732 sleep(1); 733} 734 735static 736void 737nop_signal(int sig ATF_DEFS_ATTRIBUTE_UNUSED) 738{ 739} 740 741static 742void 743child_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 807ATF_TC(child_wait_eintr); 808ATF_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} 815ATF_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 857static 858void 859do_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 876static 877void 878check_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 886ATF_TC(exec_failure); 887ATF_TC_HEAD(exec_failure, tc) 888{ 889 atf_tc_set_md_var(tc, "descr", "Tests execing a command"); 890} 891ATF_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 901ATF_TC(exec_list); 902ATF_TC_HEAD(exec_list, tc) 903{ 904 atf_tc_set_md_var(tc, "descr", "Tests execing a command"); 905} 906ATF_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 945static void 946exit_early(void) 947{ 948 exit(80); 949} 950 951ATF_TC(exec_prehook); 952ATF_TC_HEAD(exec_prehook, tc) 953{ 954 atf_tc_set_md_var(tc, "descr", "Tests execing a command with a prehook"); 955} 956ATF_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 966ATF_TC(exec_success); 967ATF_TC_HEAD(exec_success, tc) 968{ 969 atf_tc_set_md_var(tc, "descr", "Tests execing a command"); 970} 971ATF_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 981static const int exit_v_null = 1; 982static const int exit_v_notnull = 2; 983 984static 985void 986child_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 996ATF_TC(fork_cookie); 997ATF_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} 1002ATF_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 1054TC_FORK_STREAMS(capture, CAPTURE, capture, CAPTURE); 1055TC_FORK_STREAMS(capture, CAPTURE, connect, CONNECT); 1056TC_FORK_STREAMS(capture, CAPTURE, default, DEFAULT); 1057TC_FORK_STREAMS(capture, CAPTURE, inherit, INHERIT); 1058TC_FORK_STREAMS(capture, CAPTURE, redirect_fd, REDIRECT_FD); 1059TC_FORK_STREAMS(capture, CAPTURE, redirect_path, REDIRECT_PATH); 1060TC_FORK_STREAMS(connect, CONNECT, capture, CAPTURE); 1061TC_FORK_STREAMS(connect, CONNECT, connect, CONNECT); 1062TC_FORK_STREAMS(connect, CONNECT, default, DEFAULT); 1063TC_FORK_STREAMS(connect, CONNECT, inherit, INHERIT); 1064TC_FORK_STREAMS(connect, CONNECT, redirect_fd, REDIRECT_FD); 1065TC_FORK_STREAMS(connect, CONNECT, redirect_path, REDIRECT_PATH); 1066TC_FORK_STREAMS(default, DEFAULT, capture, CAPTURE); 1067TC_FORK_STREAMS(default, DEFAULT, connect, CONNECT); 1068TC_FORK_STREAMS(default, DEFAULT, default, DEFAULT); 1069TC_FORK_STREAMS(default, DEFAULT, inherit, INHERIT); 1070TC_FORK_STREAMS(default, DEFAULT, redirect_fd, REDIRECT_FD); 1071TC_FORK_STREAMS(default, DEFAULT, redirect_path, REDIRECT_PATH); 1072TC_FORK_STREAMS(inherit, INHERIT, capture, CAPTURE); 1073TC_FORK_STREAMS(inherit, INHERIT, connect, CONNECT); 1074TC_FORK_STREAMS(inherit, INHERIT, default, DEFAULT); 1075TC_FORK_STREAMS(inherit, INHERIT, inherit, INHERIT); 1076TC_FORK_STREAMS(inherit, INHERIT, redirect_fd, REDIRECT_FD); 1077TC_FORK_STREAMS(inherit, INHERIT, redirect_path, REDIRECT_PATH); 1078TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, capture, CAPTURE); 1079TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, connect, CONNECT); 1080TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, default, DEFAULT); 1081TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, inherit, INHERIT); 1082TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_fd, REDIRECT_FD); 1083TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_path, REDIRECT_PATH); 1084TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, capture, CAPTURE); 1085TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, connect, CONNECT); 1086TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, default, DEFAULT); 1087TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, inherit, INHERIT); 1088TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_fd, REDIRECT_FD); 1089TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_path, REDIRECT_PATH); 1090 1091#undef TC_FORK_STREAMS 1092 1093/* --------------------------------------------------------------------- 1094 * Main. 1095 * --------------------------------------------------------------------- */ 1096 1097ATF_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