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. */ 45 atf_error_t atf_process_status_init(atf_process_status_t *, int); 46 47 /* --------------------------------------------------------------------- 48 * The "stream_prepare" auxiliary type. 49 * --------------------------------------------------------------------- */ 50 51 struct stream_prepare { 52 const atf_process_stream_t *m_sb; 53 54 bool m_pipefds_ok; 55 int m_pipefds[2]; 56 }; 57 typedef struct stream_prepare stream_prepare_t; 58 59 static 60 atf_error_t 61 stream_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 83 static 84 void 85 stream_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 97 const int atf_process_stream_type_capture = 1; 98 const int atf_process_stream_type_connect = 2; 99 const int atf_process_stream_type_inherit = 3; 100 const int atf_process_stream_type_redirect_fd = 4; 101 const int atf_process_stream_type_redirect_path = 5; 102 103 static 104 bool 105 stream_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 114 atf_error_t 115 atf_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 123 atf_error_t 124 atf_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 139 atf_error_t 140 atf_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 148 atf_error_t 149 atf_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 159 atf_error_t 160 atf_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 170 void 171 atf_process_stream_fini(atf_process_stream_t *sb) 172 { 173 PRE(stream_is_valid(sb)); 174 } 175 176 int 177 atf_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 188 atf_error_t 189 atf_process_status_init(atf_process_status_t *s, int status) 190 { 191 s->m_status = status; 192 193 return atf_no_error(); 194 } 195 196 void 197 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED) 198 { 199 } 200 201 bool 202 atf_process_status_exited(const atf_process_status_t *s) 203 { 204 int mutable_status = s->m_status; 205 return WIFEXITED(mutable_status); 206 } 207 208 int 209 atf_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 216 bool 217 atf_process_status_signaled(const atf_process_status_t *s) 218 { 219 int mutable_status = s->m_status; 220 return WIFSIGNALED(mutable_status); 221 } 222 223 int 224 atf_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 231 bool 232 atf_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 247 static 248 atf_error_t 249 atf_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 258 static 259 void 260 atf_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 268 atf_error_t 269 atf_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 285 pid_t 286 atf_process_child_pid(const atf_process_child_t *c) 287 { 288 return c->m_pid; 289 } 290 291 int 292 atf_process_child_stdout(atf_process_child_t *c) 293 { 294 PRE(c->m_stdout != -1); 295 return c->m_stdout; 296 } 297 298 int 299 atf_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 309 static 310 atf_error_t 311 safe_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 328 static 329 atf_error_t 330 child_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 367 static 368 void 369 parent_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 389 static 390 atf_error_t 391 do_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 407 out: 408 return err; 409 } 410 411 static 412 void 413 do_child(void (*)(void *), 414 void *, 415 const stream_prepare_t *, 416 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN; 417 418 static 419 void 420 do_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 438 out: 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 451 static 452 atf_error_t 453 fork_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 491 err_errpipe: 492 stream_prepare_fini(&errsp); 493 err_outpipe: 494 stream_prepare_fini(&outsp); 495 496 out: 497 return err; 498 } 499 500 static 501 atf_error_t 502 init_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 520 atf_error_t 521 atf_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); 545 out_out: 546 if (outsb == NULL) 547 atf_process_stream_fini(&inherit_outsb); 548 out: 549 return err; 550 } 551 552 static 553 int 554 const_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 561 static 562 atf_error_t 563 list_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 589 struct exec_args { 590 const atf_fs_path_t *m_prog; 591 const char *const *m_argv; 592 void (*m_prehook)(void); 593 }; 594 595 static 596 void 597 do_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 612 atf_error_t 613 atf_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 633 again: 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 641 out: 642 return err; 643 } 644 645 atf_error_t 646 atf_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); 669 out: 670 return err; 671 } 672