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