1263320Sdim/* $NetBSD$ */ 2263320Sdim 3263320Sdim/* 4269012Semaste * Automated Testing Framework (atf) 5263320Sdim * 6263320Sdim * Copyright (c) 2007, 2008, 2009, 2010 The NetBSD Foundation, Inc. 7263320Sdim * All rights reserved. 8263320Sdim * 9263320Sdim * Redistribution and use in source and binary forms, with or without 10263320Sdim * modification, are permitted provided that the following conditions 11263320Sdim * are met: 12263320Sdim * 1. Redistributions of source code must retain the above copyright 13263320Sdim * notice, this list of conditions and the following disclaimer. 14263320Sdim * 2. Redistributions in binary form must reproduce the above copyright 15263320Sdim * notice, this list of conditions and the following disclaimer in the 16263320Sdim * documentation and/or other materials provided with the distribution. 17263320Sdim * 18263320Sdim * 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. */ 50atf_error_t atf_process_status_init(atf_process_status_t *, int); 51 52/* --------------------------------------------------------------------- 53 * The "stream_prepare" auxiliary type. 54 * --------------------------------------------------------------------- */ 55 56struct stream_prepare { 57 const atf_process_stream_t *m_sb; 58 59 bool m_pipefds_ok; 60 int m_pipefds[2]; 61}; 62typedef struct stream_prepare stream_prepare_t; 63 64static 65atf_error_t 66stream_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 88static 89void 90stream_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 102const int atf_process_stream_type_capture = 1; 103const int atf_process_stream_type_connect = 2; 104const int atf_process_stream_type_inherit = 3; 105const int atf_process_stream_type_redirect_fd = 4; 106const int atf_process_stream_type_redirect_path = 5; 107 108static 109bool 110stream_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 119atf_error_t 120atf_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 128atf_error_t 129atf_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 144atf_error_t 145atf_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 153atf_error_t 154atf_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 164atf_error_t 165atf_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 175void 176atf_process_stream_fini(atf_process_stream_t *sb) 177{ 178 PRE(stream_is_valid(sb)); 179} 180 181int 182atf_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 193atf_error_t 194atf_process_status_init(atf_process_status_t *s, int status) 195{ 196 s->m_status = status; 197 198 return atf_no_error(); 199} 200 201void 202atf_process_status_fini(atf_process_status_t *s) 203{ 204} 205 206bool 207atf_process_status_exited(const atf_process_status_t *s) 208{ 209 int mutable_status = s->m_status; 210 return WIFEXITED(mutable_status); 211} 212 213int 214atf_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 221bool 222atf_process_status_signaled(const atf_process_status_t *s) 223{ 224 int mutable_status = s->m_status; 225 return WIFSIGNALED(mutable_status); 226} 227 228int 229atf_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 236bool 237atf_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 252static 253atf_error_t 254atf_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 263static 264void 265atf_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 273atf_error_t 274atf_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 290pid_t 291atf_process_child_pid(const atf_process_child_t *c) 292{ 293 return c->m_pid; 294} 295 296int 297atf_process_child_stdout(atf_process_child_t *c) 298{ 299 PRE(c->m_stdout != -1); 300 return c->m_stdout; 301} 302 303int 304atf_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 314static 315atf_error_t 316safe_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 333static 334atf_error_t 335child_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 372static 373void 374parent_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 394static 395atf_error_t 396do_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 412out: 413 return err; 414} 415 416static 417void 418do_child(void (*)(void *), 419 void *, 420 const stream_prepare_t *, 421 const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN; 422 423static 424void 425do_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 443out: 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 456static 457atf_error_t 458fork_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 496err_errpipe: 497 stream_prepare_fini(&errsp); 498err_outpipe: 499 stream_prepare_fini(&outsp); 500 501out: 502 return err; 503} 504 505static 506atf_error_t 507init_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 525atf_error_t 526atf_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); 550out_out: 551 if (outsb == NULL) 552 atf_process_stream_fini(&inherit_outsb); 553out: 554 return err; 555} 556 557static 558int 559const_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 566static 567atf_error_t 568list_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 594struct exec_args { 595 const atf_fs_path_t *m_prog; 596 const char *const *m_argv; 597}; 598 599static 600void 601do_exec(void *v) 602{ 603 struct exec_args *ea = v; 604 605 const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv); 606 const int errnocopy = errno; 607 INV(ret == -1); 608 fprintf(stderr, "exec(%s) failed: %s\n", 609 atf_fs_path_cstring(ea->m_prog), strerror(errnocopy)); 610 exit(EXIT_FAILURE); 611} 612 613atf_error_t 614atf_process_exec_array(atf_process_status_t *s, 615 const atf_fs_path_t *prog, 616 const char *const *argv, 617 const atf_process_stream_t *outsb, 618 const atf_process_stream_t *errsb) 619{ 620 atf_error_t err; 621 atf_process_child_t c; 622 struct exec_args ea = { prog, argv }; 623 624 PRE(outsb == NULL || 625 atf_process_stream_type(outsb) != atf_process_stream_type_capture); 626 PRE(errsb == NULL || 627 atf_process_stream_type(errsb) != atf_process_stream_type_capture); 628 629 err = atf_process_fork(&c, do_exec, outsb, errsb, &ea); 630 if (atf_is_error(err)) 631 goto out; 632 633again: 634 err = atf_process_child_wait(&c, s); 635 if (atf_is_error(err)) { 636 INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR); 637 atf_error_free(err); 638 goto again; 639 } 640 641out: 642 return err; 643} 644 645atf_error_t 646atf_process_exec_list(atf_process_status_t *s, 647 const atf_fs_path_t *prog, 648 const atf_list_t *argv, 649 const atf_process_stream_t *outsb, 650 const atf_process_stream_t *errsb) 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); 666 667 free(argv2); 668out: 669 return err; 670} 671