1275988Sngie/* Copyright (c) 2007 The NetBSD Foundation, Inc. 2240116Smarcel * All rights reserved. 3240116Smarcel * 4240116Smarcel * Redistribution and use in source and binary forms, with or without 5240116Smarcel * modification, are permitted provided that the following conditions 6240116Smarcel * are met: 7240116Smarcel * 1. Redistributions of source code must retain the above copyright 8240116Smarcel * notice, this list of conditions and the following disclaimer. 9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 10240116Smarcel * notice, this list of conditions and the following disclaimer in the 11240116Smarcel * documentation and/or other materials provided with the distribution. 12240116Smarcel * 13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24275988Sngie * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 25240116Smarcel 26275988Sngie#include "atf-c/detail/process.h" 27275988Sngie 28240116Smarcel#include <sys/types.h> 29240116Smarcel#include <sys/wait.h> 30240116Smarcel 31240116Smarcel#include <errno.h> 32240116Smarcel#include <fcntl.h> 33240116Smarcel#include <stdio.h> 34240116Smarcel#include <stdlib.h> 35240116Smarcel#include <string.h> 36240116Smarcel#include <unistd.h> 37240116Smarcel 38240116Smarcel#include "atf-c/defs.h" 39275988Sngie#include "atf-c/detail/sanity.h" 40240116Smarcel#include "atf-c/error.h" 41240116Smarcel 42240116Smarcel/* This prototype is not in the header file because this is a private 43240116Smarcel * function; however, we need to access it during testing. */ 44240116Smarcelatf_error_t atf_process_status_init(atf_process_status_t *, int); 45240116Smarcel 46240116Smarcel/* --------------------------------------------------------------------- 47240116Smarcel * The "stream_prepare" auxiliary type. 48240116Smarcel * --------------------------------------------------------------------- */ 49240116Smarcel 50240116Smarcelstruct stream_prepare { 51240116Smarcel const atf_process_stream_t *m_sb; 52240116Smarcel 53240116Smarcel bool m_pipefds_ok; 54240116Smarcel int m_pipefds[2]; 55240116Smarcel}; 56240116Smarceltypedef struct stream_prepare stream_prepare_t; 57240116Smarcel 58240116Smarcelstatic 59240116Smarcelatf_error_t 60240116Smarcelstream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb) 61240116Smarcel{ 62240116Smarcel atf_error_t err; 63240116Smarcel 64240116Smarcel const int type = atf_process_stream_type(sb); 65240116Smarcel 66240116Smarcel sp->m_sb = sb; 67240116Smarcel sp->m_pipefds_ok = false; 68240116Smarcel 69240116Smarcel if (type == atf_process_stream_type_capture) { 70240116Smarcel if (pipe(sp->m_pipefds) == -1) 71240116Smarcel err = atf_libc_error(errno, "Failed to create pipe"); 72240116Smarcel else { 73240116Smarcel err = atf_no_error(); 74240116Smarcel sp->m_pipefds_ok = true; 75240116Smarcel } 76240116Smarcel } else 77240116Smarcel err = atf_no_error(); 78240116Smarcel 79240116Smarcel return err; 80240116Smarcel} 81240116Smarcel 82240116Smarcelstatic 83240116Smarcelvoid 84240116Smarcelstream_prepare_fini(stream_prepare_t *sp) 85240116Smarcel{ 86240116Smarcel if (sp->m_pipefds_ok) { 87240116Smarcel close(sp->m_pipefds[0]); 88240116Smarcel close(sp->m_pipefds[1]); 89240116Smarcel } 90240116Smarcel} 91240116Smarcel 92240116Smarcel/* --------------------------------------------------------------------- 93240116Smarcel * The "atf_process_stream" type. 94240116Smarcel * --------------------------------------------------------------------- */ 95240116Smarcel 96240116Smarcelconst int atf_process_stream_type_capture = 1; 97240116Smarcelconst int atf_process_stream_type_connect = 2; 98240116Smarcelconst int atf_process_stream_type_inherit = 3; 99240116Smarcelconst int atf_process_stream_type_redirect_fd = 4; 100240116Smarcelconst int atf_process_stream_type_redirect_path = 5; 101240116Smarcel 102240116Smarcelstatic 103240116Smarcelbool 104240116Smarcelstream_is_valid(const atf_process_stream_t *sb) 105240116Smarcel{ 106240116Smarcel return (sb->m_type == atf_process_stream_type_capture) || 107240116Smarcel (sb->m_type == atf_process_stream_type_connect) || 108240116Smarcel (sb->m_type == atf_process_stream_type_inherit) || 109240116Smarcel (sb->m_type == atf_process_stream_type_redirect_fd) || 110240116Smarcel (sb->m_type == atf_process_stream_type_redirect_path); 111240116Smarcel} 112240116Smarcel 113240116Smarcelatf_error_t 114240116Smarcelatf_process_stream_init_capture(atf_process_stream_t *sb) 115240116Smarcel{ 116240116Smarcel sb->m_type = atf_process_stream_type_capture; 117240116Smarcel 118240116Smarcel POST(stream_is_valid(sb)); 119240116Smarcel return atf_no_error(); 120240116Smarcel} 121240116Smarcel 122240116Smarcelatf_error_t 123240116Smarcelatf_process_stream_init_connect(atf_process_stream_t *sb, 124240116Smarcel const int src_fd, const int tgt_fd) 125240116Smarcel{ 126240116Smarcel PRE(src_fd >= 0); 127240116Smarcel PRE(tgt_fd >= 0); 128240116Smarcel PRE(src_fd != tgt_fd); 129240116Smarcel 130240116Smarcel sb->m_type = atf_process_stream_type_connect; 131240116Smarcel sb->m_src_fd = src_fd; 132240116Smarcel sb->m_tgt_fd = tgt_fd; 133240116Smarcel 134240116Smarcel POST(stream_is_valid(sb)); 135240116Smarcel return atf_no_error(); 136240116Smarcel} 137240116Smarcel 138240116Smarcelatf_error_t 139240116Smarcelatf_process_stream_init_inherit(atf_process_stream_t *sb) 140240116Smarcel{ 141240116Smarcel sb->m_type = atf_process_stream_type_inherit; 142240116Smarcel 143240116Smarcel POST(stream_is_valid(sb)); 144240116Smarcel return atf_no_error(); 145240116Smarcel} 146240116Smarcel 147240116Smarcelatf_error_t 148240116Smarcelatf_process_stream_init_redirect_fd(atf_process_stream_t *sb, 149240116Smarcel const int fd) 150240116Smarcel{ 151240116Smarcel sb->m_type = atf_process_stream_type_redirect_fd; 152240116Smarcel sb->m_fd = fd; 153240116Smarcel 154240116Smarcel POST(stream_is_valid(sb)); 155240116Smarcel return atf_no_error(); 156240116Smarcel} 157240116Smarcel 158240116Smarcelatf_error_t 159240116Smarcelatf_process_stream_init_redirect_path(atf_process_stream_t *sb, 160240116Smarcel const atf_fs_path_t *path) 161240116Smarcel{ 162240116Smarcel sb->m_type = atf_process_stream_type_redirect_path; 163240116Smarcel sb->m_path = path; 164240116Smarcel 165240116Smarcel POST(stream_is_valid(sb)); 166240116Smarcel return atf_no_error(); 167240116Smarcel} 168240116Smarcel 169240116Smarcelvoid 170240116Smarcelatf_process_stream_fini(atf_process_stream_t *sb) 171240116Smarcel{ 172240116Smarcel PRE(stream_is_valid(sb)); 173240116Smarcel} 174240116Smarcel 175240116Smarcelint 176240116Smarcelatf_process_stream_type(const atf_process_stream_t *sb) 177240116Smarcel{ 178240116Smarcel PRE(stream_is_valid(sb)); 179240116Smarcel 180240116Smarcel return sb->m_type; 181240116Smarcel} 182240116Smarcel 183240116Smarcel/* --------------------------------------------------------------------- 184240116Smarcel * The "atf_process_status" type. 185240116Smarcel * --------------------------------------------------------------------- */ 186240116Smarcel 187240116Smarcelatf_error_t 188240116Smarcelatf_process_status_init(atf_process_status_t *s, int status) 189240116Smarcel{ 190240116Smarcel s->m_status = status; 191240116Smarcel 192240116Smarcel return atf_no_error(); 193240116Smarcel} 194240116Smarcel 195240116Smarcelvoid 196240116Smarcelatf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED) 197240116Smarcel{ 198240116Smarcel} 199240116Smarcel 200240116Smarcelbool 201240116Smarcelatf_process_status_exited(const atf_process_status_t *s) 202240116Smarcel{ 203240116Smarcel int mutable_status = s->m_status; 204240116Smarcel return WIFEXITED(mutable_status); 205240116Smarcel} 206240116Smarcel 207240116Smarcelint 208240116Smarcelatf_process_status_exitstatus(const atf_process_status_t *s) 209240116Smarcel{ 210240116Smarcel PRE(atf_process_status_exited(s)); 211240116Smarcel int mutable_status = s->m_status; 212240116Smarcel return WEXITSTATUS(mutable_status); 213240116Smarcel} 214240116Smarcel 215240116Smarcelbool 216240116Smarcelatf_process_status_signaled(const atf_process_status_t *s) 217240116Smarcel{ 218240116Smarcel int mutable_status = s->m_status; 219240116Smarcel return WIFSIGNALED(mutable_status); 220240116Smarcel} 221240116Smarcel 222240116Smarcelint 223240116Smarcelatf_process_status_termsig(const atf_process_status_t *s) 224240116Smarcel{ 225240116Smarcel PRE(atf_process_status_signaled(s)); 226240116Smarcel int mutable_status = s->m_status; 227240116Smarcel return WTERMSIG(mutable_status); 228240116Smarcel} 229240116Smarcel 230240116Smarcelbool 231240116Smarcelatf_process_status_coredump(const atf_process_status_t *s) 232240116Smarcel{ 233240116Smarcel PRE(atf_process_status_signaled(s)); 234240116Smarcel#if defined(WCOREDUMP) 235240116Smarcel int mutable_status = s->m_status; 236240116Smarcel return WCOREDUMP(mutable_status); 237240116Smarcel#else 238240116Smarcel return false; 239240116Smarcel#endif 240240116Smarcel} 241240116Smarcel 242240116Smarcel/* --------------------------------------------------------------------- 243240116Smarcel * The "atf_process_child" type. 244240116Smarcel * --------------------------------------------------------------------- */ 245240116Smarcel 246240116Smarcelstatic 247240116Smarcelatf_error_t 248240116Smarcelatf_process_child_init(atf_process_child_t *c) 249240116Smarcel{ 250240116Smarcel c->m_pid = 0; 251240116Smarcel c->m_stdout = -1; 252240116Smarcel c->m_stderr = -1; 253240116Smarcel 254240116Smarcel return atf_no_error(); 255240116Smarcel} 256240116Smarcel 257240116Smarcelstatic 258240116Smarcelvoid 259240116Smarcelatf_process_child_fini(atf_process_child_t *c) 260240116Smarcel{ 261240116Smarcel if (c->m_stdout != -1) 262240116Smarcel close(c->m_stdout); 263240116Smarcel if (c->m_stderr != -1) 264240116Smarcel close(c->m_stderr); 265240116Smarcel} 266240116Smarcel 267240116Smarcelatf_error_t 268240116Smarcelatf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s) 269240116Smarcel{ 270240116Smarcel atf_error_t err; 271240116Smarcel int status; 272240116Smarcel 273240116Smarcel if (waitpid(c->m_pid, &status, 0) == -1) 274240116Smarcel err = atf_libc_error(errno, "Failed waiting for process %d", 275240116Smarcel c->m_pid); 276240116Smarcel else { 277240116Smarcel atf_process_child_fini(c); 278240116Smarcel err = atf_process_status_init(s, status); 279240116Smarcel } 280240116Smarcel 281240116Smarcel return err; 282240116Smarcel} 283240116Smarcel 284240116Smarcelpid_t 285240116Smarcelatf_process_child_pid(const atf_process_child_t *c) 286240116Smarcel{ 287240116Smarcel return c->m_pid; 288240116Smarcel} 289240116Smarcel 290240116Smarcelint 291240116Smarcelatf_process_child_stdout(atf_process_child_t *c) 292240116Smarcel{ 293240116Smarcel PRE(c->m_stdout != -1); 294240116Smarcel return c->m_stdout; 295240116Smarcel} 296240116Smarcel 297240116Smarcelint 298240116Smarcelatf_process_child_stderr(atf_process_child_t *c) 299240116Smarcel{ 300240116Smarcel PRE(c->m_stderr != -1); 301240116Smarcel return c->m_stderr; 302240116Smarcel} 303240116Smarcel 304240116Smarcel/* --------------------------------------------------------------------- 305240116Smarcel * Free functions. 306240116Smarcel * --------------------------------------------------------------------- */ 307240116Smarcel 308240116Smarcelstatic 309240116Smarcelatf_error_t 310240116Smarcelsafe_dup(const int oldfd, const int newfd) 311240116Smarcel{ 312240116Smarcel atf_error_t err; 313240116Smarcel 314240116Smarcel if (oldfd != newfd) { 315240116Smarcel if (dup2(oldfd, newfd) == -1) { 316240116Smarcel err = atf_libc_error(errno, "Could not allocate file descriptor"); 317240116Smarcel } else { 318240116Smarcel close(oldfd); 319240116Smarcel err = atf_no_error(); 320240116Smarcel } 321240116Smarcel } else 322240116Smarcel err = atf_no_error(); 323240116Smarcel 324240116Smarcel return err; 325240116Smarcel} 326240116Smarcel 327240116Smarcelstatic 328240116Smarcelatf_error_t 329240116Smarcelchild_connect(const stream_prepare_t *sp, int procfd) 330240116Smarcel{ 331240116Smarcel atf_error_t err; 332240116Smarcel const int type = atf_process_stream_type(sp->m_sb); 333240116Smarcel 334240116Smarcel if (type == atf_process_stream_type_capture) { 335240116Smarcel close(sp->m_pipefds[0]); 336240116Smarcel err = safe_dup(sp->m_pipefds[1], procfd); 337240116Smarcel } else if (type == atf_process_stream_type_connect) { 338240116Smarcel if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1) 339240116Smarcel err = atf_libc_error(errno, "Cannot connect descriptor %d to %d", 340240116Smarcel sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd); 341240116Smarcel else 342240116Smarcel err = atf_no_error(); 343240116Smarcel } else if (type == atf_process_stream_type_inherit) { 344240116Smarcel err = atf_no_error(); 345240116Smarcel } else if (type == atf_process_stream_type_redirect_fd) { 346240116Smarcel err = safe_dup(sp->m_sb->m_fd, procfd); 347240116Smarcel } else if (type == atf_process_stream_type_redirect_path) { 348240116Smarcel int aux = open(atf_fs_path_cstring(sp->m_sb->m_path), 349240116Smarcel O_WRONLY | O_CREAT | O_TRUNC, 0644); 350240116Smarcel if (aux == -1) 351240116Smarcel err = atf_libc_error(errno, "Could not create %s", 352240116Smarcel atf_fs_path_cstring(sp->m_sb->m_path)); 353240116Smarcel else { 354240116Smarcel err = safe_dup(aux, procfd); 355240116Smarcel if (atf_is_error(err)) 356240116Smarcel close(aux); 357240116Smarcel } 358240116Smarcel } else { 359240116Smarcel UNREACHABLE; 360240116Smarcel err = atf_no_error(); 361240116Smarcel } 362240116Smarcel 363240116Smarcel return err; 364240116Smarcel} 365240116Smarcel 366240116Smarcelstatic 367240116Smarcelvoid 368240116Smarcelparent_connect(const stream_prepare_t *sp, int *fd) 369240116Smarcel{ 370240116Smarcel const int type = atf_process_stream_type(sp->m_sb); 371240116Smarcel 372240116Smarcel if (type == atf_process_stream_type_capture) { 373240116Smarcel close(sp->m_pipefds[1]); 374240116Smarcel *fd = sp->m_pipefds[0]; 375240116Smarcel } else if (type == atf_process_stream_type_connect) { 376240116Smarcel /* Do nothing. */ 377240116Smarcel } else if (type == atf_process_stream_type_inherit) { 378240116Smarcel /* Do nothing. */ 379240116Smarcel } else if (type == atf_process_stream_type_redirect_fd) { 380240116Smarcel /* Do nothing. */ 381240116Smarcel } else if (type == atf_process_stream_type_redirect_path) { 382240116Smarcel /* Do nothing. */ 383240116Smarcel } else { 384240116Smarcel UNREACHABLE; 385240116Smarcel } 386240116Smarcel} 387240116Smarcel 388240116Smarcelstatic 389240116Smarcelatf_error_t 390240116Smarceldo_parent(atf_process_child_t *c, 391240116Smarcel const pid_t pid, 392240116Smarcel const stream_prepare_t *outsp, 393240116Smarcel const stream_prepare_t *errsp) 394240116Smarcel{ 395240116Smarcel atf_error_t err; 396240116Smarcel 397240116Smarcel err = atf_process_child_init(c); 398240116Smarcel if (atf_is_error(err)) 399240116Smarcel goto out; 400240116Smarcel 401240116Smarcel c->m_pid = pid; 402240116Smarcel 403240116Smarcel parent_connect(outsp, &c->m_stdout); 404240116Smarcel parent_connect(errsp, &c->m_stderr); 405240116Smarcel 406240116Smarcelout: 407240116Smarcel return err; 408240116Smarcel} 409240116Smarcel 410240116Smarcelstatic 411240116Smarcelvoid 412240116Smarceldo_child(void (*)(void *), 413240116Smarcel void *, 414240116Smarcel const stream_prepare_t *, 415240116Smarcel const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN; 416240116Smarcel 417240116Smarcelstatic 418240116Smarcelvoid 419240116Smarceldo_child(void (*start)(void *), 420240116Smarcel void *v, 421240116Smarcel const stream_prepare_t *outsp, 422240116Smarcel const stream_prepare_t *errsp) 423240116Smarcel{ 424240116Smarcel atf_error_t err; 425240116Smarcel 426240116Smarcel err = child_connect(outsp, STDOUT_FILENO); 427240116Smarcel if (atf_is_error(err)) 428240116Smarcel goto out; 429240116Smarcel 430240116Smarcel err = child_connect(errsp, STDERR_FILENO); 431240116Smarcel if (atf_is_error(err)) 432240116Smarcel goto out; 433240116Smarcel 434240116Smarcel start(v); 435240116Smarcel UNREACHABLE; 436240116Smarcel 437240116Smarcelout: 438240116Smarcel if (atf_is_error(err)) { 439240116Smarcel char buf[1024]; 440240116Smarcel 441240116Smarcel atf_error_format(err, buf, sizeof(buf)); 442240116Smarcel fprintf(stderr, "Unhandled error: %s\n", buf); 443240116Smarcel atf_error_free(err); 444240116Smarcel 445240116Smarcel exit(EXIT_FAILURE); 446240116Smarcel } else 447240116Smarcel exit(EXIT_SUCCESS); 448240116Smarcel} 449240116Smarcel 450240116Smarcelstatic 451240116Smarcelatf_error_t 452240116Smarcelfork_with_streams(atf_process_child_t *c, 453240116Smarcel void (*start)(void *), 454240116Smarcel const atf_process_stream_t *outsb, 455240116Smarcel const atf_process_stream_t *errsb, 456240116Smarcel void *v) 457240116Smarcel{ 458240116Smarcel atf_error_t err; 459240116Smarcel stream_prepare_t outsp; 460240116Smarcel stream_prepare_t errsp; 461240116Smarcel pid_t pid; 462240116Smarcel 463240116Smarcel err = stream_prepare_init(&outsp, outsb); 464240116Smarcel if (atf_is_error(err)) 465240116Smarcel goto out; 466240116Smarcel 467240116Smarcel err = stream_prepare_init(&errsp, errsb); 468240116Smarcel if (atf_is_error(err)) 469240116Smarcel goto err_outpipe; 470240116Smarcel 471240116Smarcel pid = fork(); 472240116Smarcel if (pid == -1) { 473240116Smarcel err = atf_libc_error(errno, "Failed to fork"); 474240116Smarcel goto err_errpipe; 475240116Smarcel } 476240116Smarcel 477240116Smarcel if (pid == 0) { 478240116Smarcel do_child(start, v, &outsp, &errsp); 479240116Smarcel UNREACHABLE; 480240116Smarcel abort(); 481240116Smarcel err = atf_no_error(); 482240116Smarcel } else { 483240116Smarcel err = do_parent(c, pid, &outsp, &errsp); 484240116Smarcel if (atf_is_error(err)) 485240116Smarcel goto err_errpipe; 486240116Smarcel } 487240116Smarcel 488240116Smarcel goto out; 489240116Smarcel 490240116Smarcelerr_errpipe: 491240116Smarcel stream_prepare_fini(&errsp); 492240116Smarcelerr_outpipe: 493240116Smarcel stream_prepare_fini(&outsp); 494240116Smarcel 495240116Smarcelout: 496240116Smarcel return err; 497240116Smarcel} 498240116Smarcel 499240116Smarcelstatic 500240116Smarcelatf_error_t 501240116Smarcelinit_stream_w_default(const atf_process_stream_t *usersb, 502240116Smarcel atf_process_stream_t *inheritsb, 503240116Smarcel const atf_process_stream_t **realsb) 504240116Smarcel{ 505240116Smarcel atf_error_t err; 506240116Smarcel 507240116Smarcel if (usersb == NULL) { 508240116Smarcel err = atf_process_stream_init_inherit(inheritsb); 509240116Smarcel if (!atf_is_error(err)) 510240116Smarcel *realsb = inheritsb; 511240116Smarcel } else { 512240116Smarcel err = atf_no_error(); 513240116Smarcel *realsb = usersb; 514240116Smarcel } 515240116Smarcel 516240116Smarcel return err; 517240116Smarcel} 518240116Smarcel 519240116Smarcelatf_error_t 520240116Smarcelatf_process_fork(atf_process_child_t *c, 521240116Smarcel void (*start)(void *), 522240116Smarcel const atf_process_stream_t *outsb, 523240116Smarcel const atf_process_stream_t *errsb, 524240116Smarcel void *v) 525240116Smarcel{ 526240116Smarcel atf_error_t err; 527240116Smarcel atf_process_stream_t inherit_outsb, inherit_errsb; 528240116Smarcel const atf_process_stream_t *real_outsb, *real_errsb; 529240116Smarcel 530240116Smarcel real_outsb = NULL; /* Shut up GCC warning. */ 531240116Smarcel err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb); 532240116Smarcel if (atf_is_error(err)) 533240116Smarcel goto out; 534240116Smarcel 535240116Smarcel real_errsb = NULL; /* Shut up GCC warning. */ 536240116Smarcel err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb); 537240116Smarcel if (atf_is_error(err)) 538240116Smarcel goto out_out; 539240116Smarcel 540240116Smarcel err = fork_with_streams(c, start, real_outsb, real_errsb, v); 541240116Smarcel 542240116Smarcel if (errsb == NULL) 543240116Smarcel atf_process_stream_fini(&inherit_errsb); 544240116Smarcelout_out: 545240116Smarcel if (outsb == NULL) 546240116Smarcel atf_process_stream_fini(&inherit_outsb); 547240116Smarcelout: 548240116Smarcel return err; 549240116Smarcel} 550240116Smarcel 551240116Smarcelstatic 552240116Smarcelint 553240116Smarcelconst_execvp(const char *file, const char *const *argv) 554240116Smarcel{ 555240116Smarcel#define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 556240116Smarcel return execvp(file, UNCONST(argv)); 557240116Smarcel#undef UNCONST 558240116Smarcel} 559240116Smarcel 560240116Smarcelstatic 561240116Smarcelatf_error_t 562240116Smarcellist_to_array(const atf_list_t *l, const char ***ap) 563240116Smarcel{ 564240116Smarcel atf_error_t err; 565240116Smarcel const char **a; 566240116Smarcel 567240116Smarcel a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *)); 568240116Smarcel if (a == NULL) 569240116Smarcel err = atf_no_memory_error(); 570240116Smarcel else { 571240116Smarcel const char **aiter; 572240116Smarcel atf_list_citer_t liter; 573240116Smarcel 574240116Smarcel aiter = a; 575240116Smarcel atf_list_for_each_c(liter, l) { 576240116Smarcel *aiter = (const char *)atf_list_citer_data(liter); 577240116Smarcel aiter++; 578240116Smarcel } 579240116Smarcel *aiter = NULL; 580240116Smarcel 581240116Smarcel err = atf_no_error(); 582240116Smarcel *ap = a; 583240116Smarcel } 584240116Smarcel 585240116Smarcel return err; 586240116Smarcel} 587240116Smarcel 588240116Smarcelstruct exec_args { 589240116Smarcel const atf_fs_path_t *m_prog; 590240116Smarcel const char *const *m_argv; 591240116Smarcel void (*m_prehook)(void); 592240116Smarcel}; 593240116Smarcel 594240116Smarcelstatic 595240116Smarcelvoid 596240116Smarceldo_exec(void *v) 597240116Smarcel{ 598240116Smarcel struct exec_args *ea = v; 599240116Smarcel 600240116Smarcel if (ea->m_prehook != NULL) 601240116Smarcel ea->m_prehook(); 602240116Smarcel 603240116Smarcel const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv); 604240116Smarcel const int errnocopy = errno; 605240116Smarcel INV(ret == -1); 606240116Smarcel fprintf(stderr, "exec(%s) failed: %s\n", 607240116Smarcel atf_fs_path_cstring(ea->m_prog), strerror(errnocopy)); 608240116Smarcel exit(EXIT_FAILURE); 609240116Smarcel} 610240116Smarcel 611240116Smarcelatf_error_t 612240116Smarcelatf_process_exec_array(atf_process_status_t *s, 613240116Smarcel const atf_fs_path_t *prog, 614240116Smarcel const char *const *argv, 615240116Smarcel const atf_process_stream_t *outsb, 616240116Smarcel const atf_process_stream_t *errsb, 617240116Smarcel void (*prehook)(void)) 618240116Smarcel{ 619240116Smarcel atf_error_t err; 620240116Smarcel atf_process_child_t c; 621240116Smarcel struct exec_args ea = { prog, argv, prehook }; 622240116Smarcel 623240116Smarcel PRE(outsb == NULL || 624240116Smarcel atf_process_stream_type(outsb) != atf_process_stream_type_capture); 625240116Smarcel PRE(errsb == NULL || 626240116Smarcel atf_process_stream_type(errsb) != atf_process_stream_type_capture); 627240116Smarcel 628240116Smarcel err = atf_process_fork(&c, do_exec, outsb, errsb, &ea); 629240116Smarcel if (atf_is_error(err)) 630240116Smarcel goto out; 631240116Smarcel 632240116Smarcelagain: 633240116Smarcel err = atf_process_child_wait(&c, s); 634240116Smarcel if (atf_is_error(err)) { 635240116Smarcel INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR); 636240116Smarcel atf_error_free(err); 637240116Smarcel goto again; 638240116Smarcel } 639240116Smarcel 640240116Smarcelout: 641240116Smarcel return err; 642240116Smarcel} 643240116Smarcel 644240116Smarcelatf_error_t 645240116Smarcelatf_process_exec_list(atf_process_status_t *s, 646240116Smarcel const atf_fs_path_t *prog, 647240116Smarcel const atf_list_t *argv, 648240116Smarcel const atf_process_stream_t *outsb, 649240116Smarcel const atf_process_stream_t *errsb, 650240116Smarcel void (*prehook)(void)) 651240116Smarcel{ 652240116Smarcel atf_error_t err; 653240116Smarcel const char **argv2; 654240116Smarcel 655240116Smarcel PRE(outsb == NULL || 656240116Smarcel atf_process_stream_type(outsb) != atf_process_stream_type_capture); 657240116Smarcel PRE(errsb == NULL || 658240116Smarcel atf_process_stream_type(errsb) != atf_process_stream_type_capture); 659240116Smarcel 660240116Smarcel argv2 = NULL; /* Silence GCC warning. */ 661240116Smarcel err = list_to_array(argv, &argv2); 662240116Smarcel if (atf_is_error(err)) 663240116Smarcel goto out; 664240116Smarcel 665240116Smarcel err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook); 666240116Smarcel 667240116Smarcel free(argv2); 668240116Smarcelout: 669240116Smarcel return err; 670240116Smarcel} 671