1 /* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/wait.h> 32 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include "atf-c/defs.h" 41 #include "atf-c/error.h" 42 43 #include "process.h" 44 #include "sanity.h" 45 46 /* This prototype is not in the header file because this is a private 47 * function; however, we need to access it during testing. */ 48 atf_error_t atf_process_status_init(atf_process_status_t *, int); 49 50 /* --------------------------------------------------------------------- 51 * The "stream_prepare" auxiliary type. 52 * --------------------------------------------------------------------- */ 53 54 struct stream_prepare { 55 const atf_process_stream_t *m_sb; 56 57 bool m_pipefds_ok; 58 int m_pipefds[2]; 59 }; 60 typedef struct stream_prepare stream_prepare_t; 61 62 static 63 atf_error_t 64 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb) 65 { 66 atf_error_t err; 67 68 const int type = atf_process_stream_type(sb); 69 70 sp->m_sb = sb; 71 sp->m_pipefds_ok = false; 72 73 if (type == atf_process_stream_type_capture) { 74 if (pipe(sp->m_pipefds) == -1) 75 err = atf_libc_error(errno, "Failed to create pipe"); 76 else { 77 err = atf_no_error(); 78 sp->m_pipefds_ok = true; 79 } 80 } else 81 err = atf_no_error(); 82 83 return err; 84 } 85 86 static 87 void 88 stream_prepare_fini(stream_prepare_t *sp) 89 { 90 if (sp->m_pipefds_ok) { 91 close(sp->m_pipefds[0]); 92 close(sp->m_pipefds[1]); 93 } 94 } 95 96 /* --------------------------------------------------------------------- 97 * The "atf_process_stream" type. 98 * --------------------------------------------------------------------- */ 99 100 const int atf_process_stream_type_capture = 1; 101 const int atf_process_stream_type_connect = 2; 102 const int atf_process_stream_type_inherit = 3; 103 const int atf_process_stream_type_redirect_fd = 4; 104 const int atf_process_stream_type_redirect_path = 5; 105 106 #if defined(__minix) && !defined(NDEBUG) 107 static 108 bool 109 stream_is_valid(const atf_process_stream_t *sb) 110 { 111 return (sb->m_type == atf_process_stream_type_capture) || 112 (sb->m_type == atf_process_stream_type_connect) || 113 (sb->m_type == atf_process_stream_type_inherit) || 114 (sb->m_type == atf_process_stream_type_redirect_fd) || 115 (sb->m_type == atf_process_stream_type_redirect_path); 116 } 117 #endif /* defined(__minix) && !defined(NDEBUG) */ 118 119 atf_error_t 120 atf_process_stream_init_capture(atf_process_stream_t *sb) 121 { 122 sb->m_type = atf_process_stream_type_capture; 123 124 POST(stream_is_valid(sb)); 125 return atf_no_error(); 126 } 127 128 atf_error_t 129 atf_process_stream_init_connect(atf_process_stream_t *sb, 130 const int src_fd, const int tgt_fd) 131 { 132 PRE(src_fd >= 0); 133 PRE(tgt_fd >= 0); 134 PRE(src_fd != tgt_fd); 135 136 sb->m_type = atf_process_stream_type_connect; 137 sb->m_src_fd = src_fd; 138 sb->m_tgt_fd = tgt_fd; 139 140 POST(stream_is_valid(sb)); 141 return atf_no_error(); 142 } 143 144 atf_error_t 145 atf_process_stream_init_inherit(atf_process_stream_t *sb) 146 { 147 sb->m_type = atf_process_stream_type_inherit; 148 149 POST(stream_is_valid(sb)); 150 return atf_no_error(); 151 } 152 153 atf_error_t 154 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb, 155 const int fd) 156 { 157 sb->m_type = atf_process_stream_type_redirect_fd; 158 sb->m_fd = fd; 159 160 POST(stream_is_valid(sb)); 161 return atf_no_error(); 162 } 163 164 atf_error_t 165 atf_process_stream_init_redirect_path(atf_process_stream_t *sb, 166 const atf_fs_path_t *path) 167 { 168 sb->m_type = atf_process_stream_type_redirect_path; 169 sb->m_path = path; 170 171 POST(stream_is_valid(sb)); 172 return atf_no_error(); 173 } 174 175 void 176 atf_process_stream_fini(atf_process_stream_t *sb) 177 { 178 PRE(stream_is_valid(sb)); 179 } 180 181 int 182 atf_process_stream_type(const atf_process_stream_t *sb) 183 { 184 PRE(stream_is_valid(sb)); 185 186 return sb->m_type; 187 } 188 189 /* --------------------------------------------------------------------- 190 * The "atf_process_status" type. 191 * --------------------------------------------------------------------- */ 192 193 atf_error_t 194 atf_process_status_init(atf_process_status_t *s, int status) 195 { 196 s->m_status = status; 197 198 return atf_no_error(); 199 } 200 201 void 202 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED) 203 { 204 } 205 206 bool 207 atf_process_status_exited(const atf_process_status_t *s) 208 { 209 int mutable_status = s->m_status; 210 return WIFEXITED(mutable_status); 211 } 212 213 int 214 atf_process_status_exitstatus(const atf_process_status_t *s) 215 { 216 PRE(atf_process_status_exited(s)); 217 int mutable_status = s->m_status; 218 return WEXITSTATUS(mutable_status); 219 } 220 221 bool 222 atf_process_status_signaled(const atf_process_status_t *s) 223 { 224 int mutable_status = s->m_status; 225 return WIFSIGNALED(mutable_status); 226 } 227 228 int 229 atf_process_status_termsig(const atf_process_status_t *s) 230 { 231 PRE(atf_process_status_signaled(s)); 232 int mutable_status = s->m_status; 233 return WTERMSIG(mutable_status); 234 } 235 236 bool 237 atf_process_status_coredump(const atf_process_status_t *s) 238 { 239 PRE(atf_process_status_signaled(s)); 240 #if defined(WCOREDUMP) 241 int mutable_status = s->m_status; 242 return WCOREDUMP(mutable_status); 243 #else 244 return false; 245 #endif 246 } 247 248 /* --------------------------------------------------------------------- 249 * The "atf_process_child" type. 250 * --------------------------------------------------------------------- */ 251 252 static 253 atf_error_t 254 atf_process_child_init(atf_process_child_t *c) 255 { 256 c->m_pid = 0; 257 c->m_stdout = -1; 258 c->m_stderr = -1; 259 260 return atf_no_error(); 261 } 262 263 static 264 void 265 atf_process_child_fini(atf_process_child_t *c) 266 { 267 if (c->m_stdout != -1) 268 close(c->m_stdout); 269 if (c->m_stderr != -1) 270 close(c->m_stderr); 271 } 272 273 atf_error_t 274 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s) 275 { 276 atf_error_t err; 277 int status; 278 279 if (waitpid(c->m_pid, &status, 0) == -1) 280 err = atf_libc_error(errno, "Failed waiting for process %d", 281 c->m_pid); 282 else { 283 atf_process_child_fini(c); 284 err = atf_process_status_init(s, status); 285 } 286 287 return err; 288 } 289 290 pid_t 291 atf_process_child_pid(const atf_process_child_t *c) 292 { 293 return c->m_pid; 294 } 295 296 int 297 atf_process_child_stdout(atf_process_child_t *c) 298 { 299 PRE(c->m_stdout != -1); 300 return c->m_stdout; 301 } 302 303 int 304 atf_process_child_stderr(atf_process_child_t *c) 305 { 306 PRE(c->m_stderr != -1); 307 return c->m_stderr; 308 } 309 310 /* --------------------------------------------------------------------- 311 * Free functions. 312 * --------------------------------------------------------------------- */ 313 314 static 315 atf_error_t 316 safe_dup(const int oldfd, const int newfd) 317 { 318 atf_error_t err; 319 320 if (oldfd != newfd) { 321 if (dup2(oldfd, newfd) == -1) { 322 err = atf_libc_error(errno, "Could not allocate file descriptor"); 323 } else { 324 close(oldfd); 325 err = atf_no_error(); 326 } 327 } else 328 err = atf_no_error(); 329 330 return err; 331 } 332 333 static 334 atf_error_t 335 child_connect(const stream_prepare_t *sp, int procfd) 336 { 337 atf_error_t err; 338 const int type = atf_process_stream_type(sp->m_sb); 339 340 if (type == atf_process_stream_type_capture) { 341 close(sp->m_pipefds[0]); 342 err = safe_dup(sp->m_pipefds[1], procfd); 343 } else if (type == atf_process_stream_type_connect) { 344 if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1) 345 err = atf_libc_error(errno, "Cannot connect descriptor %d to %d", 346 sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd); 347 else 348 err = atf_no_error(); 349 } else if (type == atf_process_stream_type_inherit) { 350 err = atf_no_error(); 351 } else if (type == atf_process_stream_type_redirect_fd) { 352 err = safe_dup(sp->m_sb->m_fd, procfd); 353 } else if (type == atf_process_stream_type_redirect_path) { 354 int aux = open(atf_fs_path_cstring(sp->m_sb->m_path), 355 O_WRONLY | O_CREAT | O_TRUNC, 0644); 356 if (aux == -1) 357 err = atf_libc_error(errno, "Could not create %s", 358 atf_fs_path_cstring(sp->m_sb->m_path)); 359 else { 360 err = safe_dup(aux, procfd); 361 if (atf_is_error(err)) 362 close(aux); 363 } 364 } else { 365 UNREACHABLE; 366 err = atf_no_error(); 367 } 368 369 return err; 370 } 371 372 static 373 void 374 parent_connect(const stream_prepare_t *sp, int *fd) 375 { 376 const int type = atf_process_stream_type(sp->m_sb); 377 378 if (type == atf_process_stream_type_capture) { 379 close(sp->m_pipefds[1]); 380 *fd = sp->m_pipefds[0]; 381 } else if (type == atf_process_stream_type_connect) { 382 /* Do nothing. */ 383 } else if (type == atf_process_stream_type_inherit) { 384 /* Do nothing. */ 385 } else if (type == atf_process_stream_type_redirect_fd) { 386 /* Do nothing. */ 387 } else if (type == atf_process_stream_type_redirect_path) { 388 /* Do nothing. */ 389 } else { 390 UNREACHABLE; 391 } 392 } 393 394 static 395 atf_error_t 396 do_parent(atf_process_child_t *c, 397 const pid_t pid, 398 const stream_prepare_t *outsp, 399 const stream_prepare_t *errsp) 400 { 401 atf_error_t err; 402 403 err = atf_process_child_init(c); 404 if (atf_is_error(err)) 405 goto out; 406 407 c->m_pid = pid; 408 409 parent_connect(outsp, &c->m_stdout); 410 parent_connect(errsp, &c->m_stderr); 411 412 out: 413 return err; 414 } 415 416 static 417 void 418 do_child(void (*)(void *), 419 void *, 420 const stream_prepare_t *, 421 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN; 422 423 static 424 void 425 do_child(void (*start)(void *), 426 void *v, 427 const stream_prepare_t *outsp, 428 const stream_prepare_t *errsp) 429 { 430 atf_error_t err; 431 432 err = child_connect(outsp, STDOUT_FILENO); 433 if (atf_is_error(err)) 434 goto out; 435 436 err = child_connect(errsp, STDERR_FILENO); 437 if (atf_is_error(err)) 438 goto out; 439 440 start(v); 441 UNREACHABLE; 442 443 out: 444 if (atf_is_error(err)) { 445 char buf[1024]; 446 447 atf_error_format(err, buf, sizeof(buf)); 448 fprintf(stderr, "Unhandled error: %s\n", buf); 449 atf_error_free(err); 450 451 exit(EXIT_FAILURE); 452 } else 453 exit(EXIT_SUCCESS); 454 } 455 456 static 457 atf_error_t 458 fork_with_streams(atf_process_child_t *c, 459 void (*start)(void *), 460 const atf_process_stream_t *outsb, 461 const atf_process_stream_t *errsb, 462 void *v) 463 { 464 atf_error_t err; 465 stream_prepare_t outsp; 466 stream_prepare_t errsp; 467 pid_t pid; 468 469 err = stream_prepare_init(&outsp, outsb); 470 if (atf_is_error(err)) 471 goto out; 472 473 err = stream_prepare_init(&errsp, errsb); 474 if (atf_is_error(err)) 475 goto err_outpipe; 476 477 pid = fork(); 478 if (pid == -1) { 479 err = atf_libc_error(errno, "Failed to fork"); 480 goto err_errpipe; 481 } 482 483 if (pid == 0) { 484 do_child(start, v, &outsp, &errsp); 485 UNREACHABLE; 486 abort(); 487 err = atf_no_error(); 488 } else { 489 err = do_parent(c, pid, &outsp, &errsp); 490 if (atf_is_error(err)) 491 goto err_errpipe; 492 } 493 494 goto out; 495 496 err_errpipe: 497 stream_prepare_fini(&errsp); 498 err_outpipe: 499 stream_prepare_fini(&outsp); 500 501 out: 502 return err; 503 } 504 505 static 506 atf_error_t 507 init_stream_w_default(const atf_process_stream_t *usersb, 508 atf_process_stream_t *inheritsb, 509 const atf_process_stream_t **realsb) 510 { 511 atf_error_t err; 512 513 if (usersb == NULL) { 514 err = atf_process_stream_init_inherit(inheritsb); 515 if (!atf_is_error(err)) 516 *realsb = inheritsb; 517 } else { 518 err = atf_no_error(); 519 *realsb = usersb; 520 } 521 522 return err; 523 } 524 525 atf_error_t 526 atf_process_fork(atf_process_child_t *c, 527 void (*start)(void *), 528 const atf_process_stream_t *outsb, 529 const atf_process_stream_t *errsb, 530 void *v) 531 { 532 atf_error_t err; 533 atf_process_stream_t inherit_outsb, inherit_errsb; 534 const atf_process_stream_t *real_outsb, *real_errsb; 535 536 real_outsb = NULL; /* Shut up GCC warning. */ 537 err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb); 538 if (atf_is_error(err)) 539 goto out; 540 541 real_errsb = NULL; /* Shut up GCC warning. */ 542 err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb); 543 if (atf_is_error(err)) 544 goto out_out; 545 546 err = fork_with_streams(c, start, real_outsb, real_errsb, v); 547 548 if (errsb == NULL) 549 atf_process_stream_fini(&inherit_errsb); 550 out_out: 551 if (outsb == NULL) 552 atf_process_stream_fini(&inherit_outsb); 553 out: 554 return err; 555 } 556 557 static 558 int 559 const_execvp(const char *file, const char *const *argv) 560 { 561 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 562 return execvp(file, UNCONST(argv)); 563 #undef UNCONST 564 } 565 566 static 567 atf_error_t 568 list_to_array(const atf_list_t *l, const char ***ap) 569 { 570 atf_error_t err; 571 const char **a; 572 573 a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *)); 574 if (a == NULL) 575 err = atf_no_memory_error(); 576 else { 577 const char **aiter; 578 atf_list_citer_t liter; 579 580 aiter = a; 581 atf_list_for_each_c(liter, l) { 582 *aiter = (const char *)atf_list_citer_data(liter); 583 aiter++; 584 } 585 *aiter = NULL; 586 587 err = atf_no_error(); 588 *ap = a; 589 } 590 591 return err; 592 } 593 594 struct exec_args { 595 const atf_fs_path_t *m_prog; 596 const char *const *m_argv; 597 void (*m_prehook)(void); 598 }; 599 600 static 601 void 602 do_exec(void *v) 603 { 604 struct exec_args *ea = v; 605 606 if (ea->m_prehook != NULL) 607 ea->m_prehook(); 608 609 #if defined(__minix) && !defined(NDEBUG) 610 const int ret = 611 #endif /* defined(__minix) && !defined(NDEBUG) */ 612 const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv); 613 const int errnocopy = errno; 614 INV(ret == -1); 615 fprintf(stderr, "exec(%s) failed: %s\n", 616 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy)); 617 exit(EXIT_FAILURE); 618 } 619 620 atf_error_t 621 atf_process_exec_array(atf_process_status_t *s, 622 const atf_fs_path_t *prog, 623 const char *const *argv, 624 const atf_process_stream_t *outsb, 625 const atf_process_stream_t *errsb, 626 void (*prehook)(void)) 627 { 628 atf_error_t err; 629 atf_process_child_t c = { .m_pid = 0, .m_stdout = 1, .m_stderr = 2 }; /* MINIX: Complain in -O3 */ 630 struct exec_args ea = { prog, argv, prehook }; 631 632 PRE(outsb == NULL || 633 atf_process_stream_type(outsb) != atf_process_stream_type_capture); 634 PRE(errsb == NULL || 635 atf_process_stream_type(errsb) != atf_process_stream_type_capture); 636 637 err = atf_process_fork(&c, do_exec, outsb, errsb, &ea); 638 if (atf_is_error(err)) 639 goto out; 640 641 again: 642 err = atf_process_child_wait(&c, s); 643 if (atf_is_error(err)) { 644 INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR); 645 atf_error_free(err); 646 goto again; 647 } 648 649 out: 650 return err; 651 } 652 653 atf_error_t 654 atf_process_exec_list(atf_process_status_t *s, 655 const atf_fs_path_t *prog, 656 const atf_list_t *argv, 657 const atf_process_stream_t *outsb, 658 const atf_process_stream_t *errsb, 659 void (*prehook)(void)) 660 { 661 atf_error_t err; 662 const char **argv2; 663 664 PRE(outsb == NULL || 665 atf_process_stream_type(outsb) != atf_process_stream_type_capture); 666 PRE(errsb == NULL || 667 atf_process_stream_type(errsb) != atf_process_stream_type_capture); 668 669 argv2 = NULL; /* Silence GCC warning. */ 670 err = list_to_array(argv, &argv2); 671 if (atf_is_error(err)) 672 goto out; 673 674 err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook); 675 676 free(argv2); 677 out: 678 return err; 679 } 680