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. */ 48atf_error_t atf_process_status_init(atf_process_status_t *, int); 49 50/* --------------------------------------------------------------------- 51 * The "stream_prepare" auxiliary type. 52 * --------------------------------------------------------------------- */ 53 54struct stream_prepare { 55 const atf_process_stream_t *m_sb; 56 57 bool m_pipefds_ok; 58 int m_pipefds[2]; 59}; 60typedef struct stream_prepare stream_prepare_t; 61 62static 63atf_error_t 64stream_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 86static 87void 88stream_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 100const int atf_process_stream_type_capture = 1; 101const int atf_process_stream_type_connect = 2; 102const int atf_process_stream_type_inherit = 3; 103const int atf_process_stream_type_redirect_fd = 4; 104const int atf_process_stream_type_redirect_path = 5; 105 106static 107bool 108stream_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 117atf_error_t 118atf_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 126atf_error_t 127atf_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 142atf_error_t 143atf_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 151atf_error_t 152atf_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 162atf_error_t 163atf_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 173void 174atf_process_stream_fini(atf_process_stream_t *sb) 175{ 176 PRE(stream_is_valid(sb)); 177} 178 179int 180atf_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 191atf_error_t 192atf_process_status_init(atf_process_status_t *s, int status) 193{ 194 s->m_status = status; 195 196 return atf_no_error(); 197} 198 199void 200atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED) 201{ 202} 203 204bool 205atf_process_status_exited(const atf_process_status_t *s) 206{ 207 int mutable_status = s->m_status; 208 return WIFEXITED(mutable_status); 209} 210 211int 212atf_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 219bool 220atf_process_status_signaled(const atf_process_status_t *s) 221{ 222 int mutable_status = s->m_status; 223 return WIFSIGNALED(mutable_status); 224} 225 226int 227atf_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 234bool 235atf_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 250static 251atf_error_t 252atf_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 261static 262void 263atf_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 271atf_error_t 272atf_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 288pid_t 289atf_process_child_pid(const atf_process_child_t *c) 290{ 291 return c->m_pid; 292} 293 294int 295atf_process_child_stdout(atf_process_child_t *c) 296{ 297 PRE(c->m_stdout != -1); 298 return c->m_stdout; 299} 300 301int 302atf_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 312static 313atf_error_t 314safe_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 331static 332atf_error_t 333child_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 370static 371void 372parent_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 392static 393atf_error_t 394do_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 410out: 411 return err; 412} 413 414static 415void 416do_child(void (*)(void *), 417 void *, 418 const stream_prepare_t *, 419 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN; 420 421static 422void 423do_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 441out: 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 454static 455atf_error_t 456fork_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 494err_errpipe: 495 stream_prepare_fini(&errsp); 496err_outpipe: 497 stream_prepare_fini(&outsp); 498 499out: 500 return err; 501} 502 503static 504atf_error_t 505init_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 523atf_error_t 524atf_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); 548out_out: 549 if (outsb == NULL) 550 atf_process_stream_fini(&inherit_outsb); 551out: 552 return err; 553} 554 555static 556int 557const_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 564static 565atf_error_t 566list_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 592struct exec_args { 593 const atf_fs_path_t *m_prog; 594 const char *const *m_argv; 595 void (*m_prehook)(void); 596}; 597 598static 599void 600do_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 615atf_error_t 616atf_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 636again: 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 644out: 645 return err; 646} 647 648atf_error_t 649atf_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); 672out: 673 return err; 674} 675