1 /* $NetBSD: process.c,v 1.3 2014/12/10 04:38:03 christos Exp $ */ 2 3 /* 4 * Automated Testing Framework (atf) 5 * 6 * Copyright (c) 2007 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 19 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 29 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/wait.h> 34 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include "atf-c/defs.h" 43 #include "atf-c/error.h" 44 45 #include "process.h" 46 #include "sanity.h" 47 48 /* This prototype is not in the header file because this is a private 49 * function; however, we need to access it during testing. */ 50 atf_error_t atf_process_status_init(atf_process_status_t *, int); 51 52 /* --------------------------------------------------------------------- 53 * The "stream_prepare" auxiliary type. 54 * --------------------------------------------------------------------- */ 55 56 struct stream_prepare { 57 const atf_process_stream_t *m_sb; 58 59 bool m_pipefds_ok; 60 int m_pipefds[2]; 61 }; 62 typedef struct stream_prepare stream_prepare_t; 63 64 static 65 atf_error_t 66 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb) 67 { 68 atf_error_t err; 69 70 const int type = atf_process_stream_type(sb); 71 72 sp->m_sb = sb; 73 sp->m_pipefds_ok = false; 74 75 if (type == atf_process_stream_type_capture) { 76 if (pipe(sp->m_pipefds) == -1) 77 err = atf_libc_error(errno, "Failed to create pipe"); 78 else { 79 err = atf_no_error(); 80 sp->m_pipefds_ok = true; 81 } 82 } else 83 err = atf_no_error(); 84 85 return err; 86 } 87 88 static 89 void 90 stream_prepare_fini(stream_prepare_t *sp) 91 { 92 if (sp->m_pipefds_ok) { 93 close(sp->m_pipefds[0]); 94 close(sp->m_pipefds[1]); 95 } 96 } 97 98 /* --------------------------------------------------------------------- 99 * The "atf_process_stream" type. 100 * --------------------------------------------------------------------- */ 101 102 const int atf_process_stream_type_capture = 1; 103 const int atf_process_stream_type_connect = 2; 104 const int atf_process_stream_type_inherit = 3; 105 const int atf_process_stream_type_redirect_fd = 4; 106 const int atf_process_stream_type_redirect_path = 5; 107 108 static 109 bool 110 stream_is_valid(const atf_process_stream_t *sb) 111 { 112 return (sb->m_type == atf_process_stream_type_capture) || 113 (sb->m_type == atf_process_stream_type_connect) || 114 (sb->m_type == atf_process_stream_type_inherit) || 115 (sb->m_type == atf_process_stream_type_redirect_fd) || 116 (sb->m_type == atf_process_stream_type_redirect_path); 117 } 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 const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv); 610 const int errnocopy = errno; 611 INV(ret == -1); 612 fprintf(stderr, "exec(%s) failed: %s\n", 613 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy)); 614 exit(EXIT_FAILURE); 615 } 616 617 atf_error_t 618 atf_process_exec_array(atf_process_status_t *s, 619 const atf_fs_path_t *prog, 620 const char *const *argv, 621 const atf_process_stream_t *outsb, 622 const atf_process_stream_t *errsb, 623 void (*prehook)(void)) 624 { 625 atf_error_t err; 626 atf_process_child_t c; 627 struct exec_args ea = { prog, argv, prehook }; 628 629 PRE(outsb == NULL || 630 atf_process_stream_type(outsb) != atf_process_stream_type_capture); 631 PRE(errsb == NULL || 632 atf_process_stream_type(errsb) != atf_process_stream_type_capture); 633 634 err = atf_process_fork(&c, do_exec, outsb, errsb, &ea); 635 if (atf_is_error(err)) 636 goto out; 637 638 again: 639 err = atf_process_child_wait(&c, s); 640 if (atf_is_error(err)) { 641 INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR); 642 atf_error_free(err); 643 goto again; 644 } 645 646 out: 647 return err; 648 } 649 650 atf_error_t 651 atf_process_exec_list(atf_process_status_t *s, 652 const atf_fs_path_t *prog, 653 const atf_list_t *argv, 654 const atf_process_stream_t *outsb, 655 const atf_process_stream_t *errsb, 656 void (*prehook)(void)) 657 { 658 atf_error_t err; 659 const char **argv2; 660 661 PRE(outsb == NULL || 662 atf_process_stream_type(outsb) != atf_process_stream_type_capture); 663 PRE(errsb == NULL || 664 atf_process_stream_type(errsb) != atf_process_stream_type_capture); 665 666 argv2 = NULL; /* Silence GCC warning. */ 667 err = list_to_array(argv, &argv2); 668 if (atf_is_error(err)) 669 goto out; 670 671 err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook); 672 673 free(argv2); 674 out: 675 return err; 676 } 677