Path: blob/main/contrib/atf/atf-c/detail/process.c
39507 views
/* Copyright (c) 2007 The NetBSD Foundation, Inc.1* All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6* 1. Redistributions of source code must retain the above copyright7* notice, this list of conditions and the following disclaimer.8* 2. Redistributions in binary form must reproduce the above copyright9* notice, this list of conditions and the following disclaimer in the10* documentation and/or other materials provided with the distribution.11*12* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND13* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,14* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF15* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.16* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY17* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE19* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS20* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER21* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR22* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN23* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */2425#include "atf-c/detail/process.h"2627#include <sys/types.h>28#include <sys/wait.h>2930#include <errno.h>31#include <fcntl.h>32#include <stdint.h>33#include <stdio.h>34#include <stdlib.h>35#include <string.h>36#include <unistd.h>3738#include "atf-c/defs.h"39#include "atf-c/detail/sanity.h"40#include "atf-c/error.h"4142/* This prototype is not in the header file because this is a private43* function; however, we need to access it during testing. */44atf_error_t atf_process_status_init(atf_process_status_t *, int);4546/* ---------------------------------------------------------------------47* The "stream_prepare" auxiliary type.48* --------------------------------------------------------------------- */4950struct stream_prepare {51const atf_process_stream_t *m_sb;5253bool m_pipefds_ok;54int m_pipefds[2];55};56typedef struct stream_prepare stream_prepare_t;5758static59atf_error_t60stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)61{62atf_error_t err;6364const int type = atf_process_stream_type(sb);6566sp->m_sb = sb;67sp->m_pipefds_ok = false;6869if (type == atf_process_stream_type_capture) {70if (pipe(sp->m_pipefds) == -1)71err = atf_libc_error(errno, "Failed to create pipe");72else {73err = atf_no_error();74sp->m_pipefds_ok = true;75}76} else77err = atf_no_error();7879return err;80}8182static83void84stream_prepare_fini(stream_prepare_t *sp)85{86if (sp->m_pipefds_ok) {87close(sp->m_pipefds[0]);88close(sp->m_pipefds[1]);89}90}9192/* ---------------------------------------------------------------------93* The "atf_process_stream" type.94* --------------------------------------------------------------------- */9596const int atf_process_stream_type_capture = 1;97const int atf_process_stream_type_connect = 2;98const int atf_process_stream_type_inherit = 3;99const int atf_process_stream_type_redirect_fd = 4;100const int atf_process_stream_type_redirect_path = 5;101102static103bool104stream_is_valid(const atf_process_stream_t *sb)105{106return (sb->m_type == atf_process_stream_type_capture) ||107(sb->m_type == atf_process_stream_type_connect) ||108(sb->m_type == atf_process_stream_type_inherit) ||109(sb->m_type == atf_process_stream_type_redirect_fd) ||110(sb->m_type == atf_process_stream_type_redirect_path);111}112113atf_error_t114atf_process_stream_init_capture(atf_process_stream_t *sb)115{116sb->m_type = atf_process_stream_type_capture;117118POST(stream_is_valid(sb));119return atf_no_error();120}121122atf_error_t123atf_process_stream_init_connect(atf_process_stream_t *sb,124const int src_fd, const int tgt_fd)125{126PRE(src_fd >= 0);127PRE(tgt_fd >= 0);128PRE(src_fd != tgt_fd);129130sb->m_type = atf_process_stream_type_connect;131sb->m_src_fd = src_fd;132sb->m_tgt_fd = tgt_fd;133134POST(stream_is_valid(sb));135return atf_no_error();136}137138atf_error_t139atf_process_stream_init_inherit(atf_process_stream_t *sb)140{141sb->m_type = atf_process_stream_type_inherit;142143POST(stream_is_valid(sb));144return atf_no_error();145}146147atf_error_t148atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,149const int fd)150{151sb->m_type = atf_process_stream_type_redirect_fd;152sb->m_fd = fd;153154POST(stream_is_valid(sb));155return atf_no_error();156}157158atf_error_t159atf_process_stream_init_redirect_path(atf_process_stream_t *sb,160const atf_fs_path_t *path)161{162sb->m_type = atf_process_stream_type_redirect_path;163sb->m_path = path;164165POST(stream_is_valid(sb));166return atf_no_error();167}168169void170atf_process_stream_fini(atf_process_stream_t *sb)171{172PRE(stream_is_valid(sb));173}174175int176atf_process_stream_type(const atf_process_stream_t *sb)177{178PRE(stream_is_valid(sb));179180return sb->m_type;181}182183/* ---------------------------------------------------------------------184* The "atf_process_status" type.185* --------------------------------------------------------------------- */186187atf_error_t188atf_process_status_init(atf_process_status_t *s, int status)189{190s->m_status = status;191192return atf_no_error();193}194195void196atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)197{198}199200bool201atf_process_status_exited(const atf_process_status_t *s)202{203int mutable_status = s->m_status;204return WIFEXITED(mutable_status);205}206207int208atf_process_status_exitstatus(const atf_process_status_t *s)209{210PRE(atf_process_status_exited(s));211int mutable_status = s->m_status;212return WEXITSTATUS(mutable_status);213}214215bool216atf_process_status_signaled(const atf_process_status_t *s)217{218int mutable_status = s->m_status;219return WIFSIGNALED(mutable_status);220}221222int223atf_process_status_termsig(const atf_process_status_t *s)224{225PRE(atf_process_status_signaled(s));226int mutable_status = s->m_status;227return WTERMSIG(mutable_status);228}229230bool231atf_process_status_coredump(const atf_process_status_t *s)232{233PRE(atf_process_status_signaled(s));234#if defined(WCOREDUMP)235int mutable_status = s->m_status;236return WCOREDUMP(mutable_status);237#else238return false;239#endif240}241242/* ---------------------------------------------------------------------243* The "atf_process_child" type.244* --------------------------------------------------------------------- */245246static247atf_error_t248atf_process_child_init(atf_process_child_t *c)249{250c->m_pid = 0;251c->m_stdout = -1;252c->m_stderr = -1;253254return atf_no_error();255}256257static258void259atf_process_child_fini(atf_process_child_t *c)260{261if (c->m_stdout != -1)262close(c->m_stdout);263if (c->m_stderr != -1)264close(c->m_stderr);265}266267atf_error_t268atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)269{270atf_error_t err;271int status;272273if (waitpid(c->m_pid, &status, 0) == -1)274err = atf_libc_error(errno, "Failed waiting for process %d",275c->m_pid);276else {277atf_process_child_fini(c);278err = atf_process_status_init(s, status);279}280281return err;282}283284pid_t285atf_process_child_pid(const atf_process_child_t *c)286{287return c->m_pid;288}289290int291atf_process_child_stdout(atf_process_child_t *c)292{293PRE(c->m_stdout != -1);294return c->m_stdout;295}296297int298atf_process_child_stderr(atf_process_child_t *c)299{300PRE(c->m_stderr != -1);301return c->m_stderr;302}303304/* ---------------------------------------------------------------------305* Free functions.306* --------------------------------------------------------------------- */307308static309atf_error_t310safe_dup(const int oldfd, const int newfd)311{312atf_error_t err;313314if (oldfd != newfd) {315if (dup2(oldfd, newfd) == -1) {316err = atf_libc_error(errno, "Could not allocate file descriptor");317} else {318close(oldfd);319err = atf_no_error();320}321} else322err = atf_no_error();323324return err;325}326327static328atf_error_t329child_connect(const stream_prepare_t *sp, int procfd)330{331atf_error_t err;332const int type = atf_process_stream_type(sp->m_sb);333334if (type == atf_process_stream_type_capture) {335close(sp->m_pipefds[0]);336err = safe_dup(sp->m_pipefds[1], procfd);337} else if (type == atf_process_stream_type_connect) {338if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)339err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",340sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);341else342err = atf_no_error();343} else if (type == atf_process_stream_type_inherit) {344err = atf_no_error();345} else if (type == atf_process_stream_type_redirect_fd) {346err = safe_dup(sp->m_sb->m_fd, procfd);347} else if (type == atf_process_stream_type_redirect_path) {348int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),349O_WRONLY | O_CREAT | O_TRUNC, 0644);350if (aux == -1)351err = atf_libc_error(errno, "Could not create %s",352atf_fs_path_cstring(sp->m_sb->m_path));353else {354err = safe_dup(aux, procfd);355if (atf_is_error(err))356close(aux);357}358} else {359UNREACHABLE;360err = atf_no_error();361}362363return err;364}365366static367void368parent_connect(const stream_prepare_t *sp, int *fd)369{370const int type = atf_process_stream_type(sp->m_sb);371372if (type == atf_process_stream_type_capture) {373close(sp->m_pipefds[1]);374*fd = sp->m_pipefds[0];375} else if (type == atf_process_stream_type_connect) {376/* Do nothing. */377} else if (type == atf_process_stream_type_inherit) {378/* Do nothing. */379} else if (type == atf_process_stream_type_redirect_fd) {380/* Do nothing. */381} else if (type == atf_process_stream_type_redirect_path) {382/* Do nothing. */383} else {384UNREACHABLE;385}386}387388static389atf_error_t390do_parent(atf_process_child_t *c,391const pid_t pid,392const stream_prepare_t *outsp,393const stream_prepare_t *errsp)394{395atf_error_t err;396397err = atf_process_child_init(c);398if (atf_is_error(err))399goto out;400401c->m_pid = pid;402403parent_connect(outsp, &c->m_stdout);404parent_connect(errsp, &c->m_stderr);405406out:407return err;408}409410static411void412do_child(void (*)(void *),413void *,414const stream_prepare_t *,415const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;416417static418void419do_child(void (*start)(void *),420void *v,421const stream_prepare_t *outsp,422const stream_prepare_t *errsp)423{424atf_error_t err;425426err = child_connect(outsp, STDOUT_FILENO);427if (atf_is_error(err))428goto out;429430err = child_connect(errsp, STDERR_FILENO);431if (atf_is_error(err))432goto out;433434start(v);435UNREACHABLE;436437out:438if (atf_is_error(err)) {439char buf[1024];440441atf_error_format(err, buf, sizeof(buf));442fprintf(stderr, "Unhandled error: %s\n", buf);443atf_error_free(err);444445exit(EXIT_FAILURE);446} else447exit(EXIT_SUCCESS);448}449450static451atf_error_t452fork_with_streams(atf_process_child_t *c,453void (*start)(void *),454const atf_process_stream_t *outsb,455const atf_process_stream_t *errsb,456void *v)457{458atf_error_t err;459stream_prepare_t outsp;460stream_prepare_t errsp;461pid_t pid;462463err = stream_prepare_init(&outsp, outsb);464if (atf_is_error(err))465goto out;466467err = stream_prepare_init(&errsp, errsb);468if (atf_is_error(err))469goto err_outpipe;470471pid = fork();472if (pid == -1) {473err = atf_libc_error(errno, "Failed to fork");474goto err_errpipe;475}476477if (pid == 0) {478do_child(start, v, &outsp, &errsp);479UNREACHABLE;480abort();481err = atf_no_error();482} else {483err = do_parent(c, pid, &outsp, &errsp);484if (atf_is_error(err))485goto err_errpipe;486}487488goto out;489490err_errpipe:491stream_prepare_fini(&errsp);492err_outpipe:493stream_prepare_fini(&outsp);494495out:496return err;497}498499static500atf_error_t501init_stream_w_default(const atf_process_stream_t *usersb,502atf_process_stream_t *inheritsb,503const atf_process_stream_t **realsb)504{505atf_error_t err;506507if (usersb == NULL) {508err = atf_process_stream_init_inherit(inheritsb);509if (!atf_is_error(err))510*realsb = inheritsb;511} else {512err = atf_no_error();513*realsb = usersb;514}515516return err;517}518519atf_error_t520atf_process_fork(atf_process_child_t *c,521void (*start)(void *),522const atf_process_stream_t *outsb,523const atf_process_stream_t *errsb,524void *v)525{526atf_error_t err;527atf_process_stream_t inherit_outsb, inherit_errsb;528const atf_process_stream_t *real_outsb, *real_errsb;529530real_outsb = NULL; /* Shut up GCC warning. */531err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);532if (atf_is_error(err))533goto out;534535real_errsb = NULL; /* Shut up GCC warning. */536err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);537if (atf_is_error(err))538goto out_out;539540err = fork_with_streams(c, start, real_outsb, real_errsb, v);541542if (errsb == NULL)543atf_process_stream_fini(&inherit_errsb);544out_out:545if (outsb == NULL)546atf_process_stream_fini(&inherit_outsb);547out:548return err;549}550551static552int553const_execvp(const char *file, const char *const *argv)554{555#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))556return execvp(file, UNCONST(argv));557#undef UNCONST558}559560static561atf_error_t562list_to_array(const atf_list_t *l, const char ***ap)563{564atf_error_t err;565const char **a;566567a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));568if (a == NULL)569err = atf_no_memory_error();570else {571const char **aiter;572atf_list_citer_t liter;573574aiter = a;575atf_list_for_each_c(liter, l) {576*aiter = (const char *)atf_list_citer_data(liter);577aiter++;578}579*aiter = NULL;580581err = atf_no_error();582*ap = a;583}584585return err;586}587588struct exec_args {589const atf_fs_path_t *m_prog;590const char *const *m_argv;591void (*m_prehook)(void);592};593594static595void596do_exec(void *v)597{598struct exec_args *ea = v;599600if (ea->m_prehook != NULL)601ea->m_prehook();602603const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);604const int errnocopy = errno;605INV(ret == -1);606fprintf(stderr, "exec(%s) failed: %s\n",607atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));608exit(EXIT_FAILURE);609}610611atf_error_t612atf_process_exec_array(atf_process_status_t *s,613const atf_fs_path_t *prog,614const char *const *argv,615const atf_process_stream_t *outsb,616const atf_process_stream_t *errsb,617void (*prehook)(void))618{619atf_error_t err;620atf_process_child_t c;621struct exec_args ea = { prog, argv, prehook };622623PRE(outsb == NULL ||624atf_process_stream_type(outsb) != atf_process_stream_type_capture);625PRE(errsb == NULL ||626atf_process_stream_type(errsb) != atf_process_stream_type_capture);627628err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);629if (atf_is_error(err))630goto out;631632again:633err = atf_process_child_wait(&c, s);634if (atf_is_error(err)) {635INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);636atf_error_free(err);637goto again;638}639640out:641return err;642}643644atf_error_t645atf_process_exec_list(atf_process_status_t *s,646const atf_fs_path_t *prog,647const atf_list_t *argv,648const atf_process_stream_t *outsb,649const atf_process_stream_t *errsb,650void (*prehook)(void))651{652atf_error_t err;653const char **argv2;654655PRE(outsb == NULL ||656atf_process_stream_type(outsb) != atf_process_stream_type_capture);657PRE(errsb == NULL ||658atf_process_stream_type(errsb) != atf_process_stream_type_capture);659660argv2 = NULL; /* Silence GCC warning. */661err = list_to_array(argv, &argv2);662if (atf_is_error(err))663goto out;664665err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);666667free(argv2);668out:669return err;670}671672673