process.c revision 275988
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. */ 44atf_error_t atf_process_status_init(atf_process_status_t *, int); 45 46/* --------------------------------------------------------------------- 47 * The "stream_prepare" auxiliary type. 48 * --------------------------------------------------------------------- */ 49 50struct stream_prepare { 51 const atf_process_stream_t *m_sb; 52 53 bool m_pipefds_ok; 54 int m_pipefds[2]; 55}; 56typedef struct stream_prepare stream_prepare_t; 57 58static 59atf_error_t 60stream_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 82static 83void 84stream_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 96const int atf_process_stream_type_capture = 1; 97const int atf_process_stream_type_connect = 2; 98const int atf_process_stream_type_inherit = 3; 99const int atf_process_stream_type_redirect_fd = 4; 100const int atf_process_stream_type_redirect_path = 5; 101 102static 103bool 104stream_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 113atf_error_t 114atf_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 122atf_error_t 123atf_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 138atf_error_t 139atf_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 147atf_error_t 148atf_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 158atf_error_t 159atf_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 169void 170atf_process_stream_fini(atf_process_stream_t *sb) 171{ 172 PRE(stream_is_valid(sb)); 173} 174 175int 176atf_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 187atf_error_t 188atf_process_status_init(atf_process_status_t *s, int status) 189{ 190 s->m_status = status; 191 192 return atf_no_error(); 193} 194 195void 196atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED) 197{ 198} 199 200bool 201atf_process_status_exited(const atf_process_status_t *s) 202{ 203 int mutable_status = s->m_status; 204 return WIFEXITED(mutable_status); 205} 206 207int 208atf_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 215bool 216atf_process_status_signaled(const atf_process_status_t *s) 217{ 218 int mutable_status = s->m_status; 219 return WIFSIGNALED(mutable_status); 220} 221 222int 223atf_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 230bool 231atf_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 246static 247atf_error_t 248atf_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 257static 258void 259atf_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 267atf_error_t 268atf_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 284pid_t 285atf_process_child_pid(const atf_process_child_t *c) 286{ 287 return c->m_pid; 288} 289 290int 291atf_process_child_stdout(atf_process_child_t *c) 292{ 293 PRE(c->m_stdout != -1); 294 return c->m_stdout; 295} 296 297int 298atf_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 308static 309atf_error_t 310safe_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 327static 328atf_error_t 329child_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 366static 367void 368parent_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 388static 389atf_error_t 390do_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 406out: 407 return err; 408} 409 410static 411void 412do_child(void (*)(void *), 413 void *, 414 const stream_prepare_t *, 415 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN; 416 417static 418void 419do_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 437out: 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 450static 451atf_error_t 452fork_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 490err_errpipe: 491 stream_prepare_fini(&errsp); 492err_outpipe: 493 stream_prepare_fini(&outsp); 494 495out: 496 return err; 497} 498 499static 500atf_error_t 501init_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 519atf_error_t 520atf_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); 544out_out: 545 if (outsb == NULL) 546 atf_process_stream_fini(&inherit_outsb); 547out: 548 return err; 549} 550 551static 552int 553const_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 560static 561atf_error_t 562list_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 588struct exec_args { 589 const atf_fs_path_t *m_prog; 590 const char *const *m_argv; 591 void (*m_prehook)(void); 592}; 593 594static 595void 596do_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 611atf_error_t 612atf_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 632again: 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 640out: 641 return err; 642} 643 644atf_error_t 645atf_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); 668out: 669 return err; 670} 671