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