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