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