Path: blob/main/contrib/atf/atf-c/detail/process_test.c
39536 views
/* Copyright (c) 2008 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#ifdef __FreeBSD__29#include <sys/sysctl.h>30#endif31#include <sys/time.h>32#include <sys/resource.h>33#include <sys/wait.h>3435#include <errno.h>36#include <fcntl.h>37#include <signal.h>38#include <stdio.h>39#include <stdlib.h>40#include <string.h>41#include <unistd.h>4243#include <atf-c.h>4445#include "atf-c/defs.h"46#include "atf-c/detail/sanity.h"47#include "atf-c/detail/test_helpers.h"4849atf_error_t atf_process_status_init(atf_process_status_t *, int);5051/* ---------------------------------------------------------------------52* Auxiliary functions for testing of 'atf_process_fork'.53* --------------------------------------------------------------------- */5455/*56* Testing of atf_process_fork is quite messy. We want to be able to test57* all the possible combinations of stdout and stderr behavior to ensure58* that the streams are manipulated correctly.59*60* To do this, the do_fork function is a wrapper for atf_process_fork that61* issues stream-specific hooks before fork, while the child is running and62* after the child terminates. We then provide test cases that just call63* do_fork with different hooks.64*65* The hooks are described by base_stream, and we then have one *_stream66* type for ever possible stream behavior.67*/6869enum out_type { stdout_type, stderr_type };7071struct base_stream {72void (*init)(void *);73void (*process)(void *, atf_process_child_t *);74void (*fini)(void *);7576/* m_sb is initialized by subclasses that need it, but all consumers77* must use m_sb_ptr, which may or may not point to m_sb. This allows78* us to test the interface with a NULL value, which triggers a79* default behavior. */80atf_process_stream_t m_sb;81atf_process_stream_t *m_sb_ptr;82enum out_type m_type;83};84#define BASE_STREAM(ihook, phook, fhook, type) \85{ .init = ihook, \86.process = phook, \87.fini = fhook, \88.m_type = type }8990static91void92check_file(const enum out_type type)93{94switch (type) {95case stdout_type:96ATF_CHECK(atf_utils_grep_file("stdout: msg", "stdout"));97ATF_CHECK(!atf_utils_grep_file("stderr: msg", "stdout"));98break;99case stderr_type:100ATF_CHECK(atf_utils_grep_file("stderr: msg", "stderr"));101ATF_CHECK(!atf_utils_grep_file("stdout: msg", "stderr"));102break;103default:104UNREACHABLE;105}106}107108struct capture_stream {109struct base_stream m_base;110111char *m_msg;112};113#define CAPTURE_STREAM(type) \114{ .m_base = BASE_STREAM(capture_stream_init, \115capture_stream_process, \116capture_stream_fini, \117type) }118119static120void121capture_stream_init(void *v)122{123struct capture_stream *s = v;124125s->m_base.m_sb_ptr = &s->m_base.m_sb;126RE(atf_process_stream_init_capture(&s->m_base.m_sb));127s->m_msg = NULL;128}129130static131void132capture_stream_process(void *v, atf_process_child_t *c)133{134struct capture_stream *s = v;135136switch (s->m_base.m_type) {137case stdout_type:138s->m_msg = atf_utils_readline(atf_process_child_stdout(c));139break;140case stderr_type:141s->m_msg = atf_utils_readline(atf_process_child_stderr(c));142break;143default:144UNREACHABLE;145}146}147148static149void150capture_stream_fini(void *v)151{152struct capture_stream *s = v;153154switch (s->m_base.m_type) {155case stdout_type:156ATF_CHECK(atf_utils_grep_string("stdout: msg", s->m_msg));157ATF_CHECK(!atf_utils_grep_string("stderr: msg", s->m_msg));158break;159case stderr_type:160ATF_CHECK(!atf_utils_grep_string("stdout: msg", s->m_msg));161ATF_CHECK(atf_utils_grep_string("stderr: msg", s->m_msg));162break;163default:164UNREACHABLE;165}166167free(s->m_msg);168atf_process_stream_fini(&s->m_base.m_sb);169}170171struct connect_stream {172struct base_stream m_base;173174int m_fd;175};176#define CONNECT_STREAM(type) \177{ .m_base = BASE_STREAM(connect_stream_init, \178NULL, \179connect_stream_fini, \180type) }181182static183void184connect_stream_init(void *v)185{186struct connect_stream *s = v;187int src_fd;188189switch (s->m_base.m_type) {190case stdout_type:191src_fd = STDOUT_FILENO;192s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644);193break;194case stderr_type:195src_fd = STDERR_FILENO;196s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644);197break;198default:199UNREACHABLE;200src_fd = -1;201}202ATF_REQUIRE(s->m_fd != -1);203204s->m_base.m_sb_ptr = &s->m_base.m_sb;205RE(atf_process_stream_init_connect(&s->m_base.m_sb, src_fd, s->m_fd));206}207208static209void210connect_stream_fini(void *v)211{212struct connect_stream *s = v;213214ATF_REQUIRE(close(s->m_fd) != -1);215216atf_process_stream_fini(&s->m_base.m_sb);217218check_file(s->m_base.m_type);219}220221struct inherit_stream {222struct base_stream m_base;223int m_fd;224225int m_old_fd;226};227#define INHERIT_STREAM(type) \228{ .m_base = BASE_STREAM(inherit_stream_init, \229NULL, \230inherit_stream_fini, \231type) }232233static234void235inherit_stream_init(void *v)236{237struct inherit_stream *s = v;238const char *name;239240s->m_base.m_sb_ptr = &s->m_base.m_sb;241RE(atf_process_stream_init_inherit(&s->m_base.m_sb));242243switch (s->m_base.m_type) {244case stdout_type:245s->m_fd = STDOUT_FILENO;246name = "stdout";247break;248case stderr_type:249s->m_fd = STDERR_FILENO;250name = "stderr";251break;252default:253UNREACHABLE;254name = NULL;255}256257s->m_old_fd = dup(s->m_fd);258ATF_REQUIRE(s->m_old_fd != -1);259ATF_REQUIRE(close(s->m_fd) != -1);260ATF_REQUIRE_EQ(open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644),261s->m_fd);262}263264static265void266inherit_stream_fini(void *v)267{268struct inherit_stream *s = v;269270ATF_REQUIRE(dup2(s->m_old_fd, s->m_fd) != -1);271ATF_REQUIRE(close(s->m_old_fd) != -1);272273atf_process_stream_fini(&s->m_base.m_sb);274275check_file(s->m_base.m_type);276}277278#define default_stream inherit_stream279#define DEFAULT_STREAM(type) \280{ .m_base = BASE_STREAM(default_stream_init, \281NULL, \282default_stream_fini, \283type) }284285static286void287default_stream_init(void *v)288{289struct inherit_stream *s = v;290291inherit_stream_init(v);292s->m_base.m_sb_ptr = NULL;293}294295static296void297default_stream_fini(void *v)298{299inherit_stream_fini(v);300}301302struct redirect_fd_stream {303struct base_stream m_base;304305int m_fd;306};307#define REDIRECT_FD_STREAM(type) \308{ .m_base = BASE_STREAM(redirect_fd_stream_init, \309NULL, \310redirect_fd_stream_fini, \311type) }312313static314void315redirect_fd_stream_init(void *v)316{317struct redirect_fd_stream *s = v;318319switch (s->m_base.m_type) {320case stdout_type:321s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644);322break;323case stderr_type:324s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644);325break;326default:327UNREACHABLE;328}329ATF_REQUIRE(s->m_fd != -1);330331s->m_base.m_sb_ptr = &s->m_base.m_sb;332RE(atf_process_stream_init_redirect_fd(&s->m_base.m_sb, s->m_fd));333}334335static336void337redirect_fd_stream_fini(void *v)338{339struct redirect_fd_stream *s = v;340341ATF_REQUIRE(close(s->m_fd) != -1);342343atf_process_stream_fini(&s->m_base.m_sb);344345check_file(s->m_base.m_type);346}347348struct redirect_path_stream {349struct base_stream m_base;350351atf_fs_path_t m_path;352};353#define REDIRECT_PATH_STREAM(type) \354{ .m_base = BASE_STREAM(redirect_path_stream_init, \355NULL, \356redirect_path_stream_fini, \357type) }358359static360void361redirect_path_stream_init(void *v)362{363struct redirect_path_stream *s = v;364365switch (s->m_base.m_type) {366case stdout_type:367RE(atf_fs_path_init_fmt(&s->m_path, "stdout"));368break;369case stderr_type:370RE(atf_fs_path_init_fmt(&s->m_path, "stderr"));371break;372default:373UNREACHABLE;374}375376s->m_base.m_sb_ptr = &s->m_base.m_sb;377RE(atf_process_stream_init_redirect_path(&s->m_base.m_sb, &s->m_path));378}379380static381void382redirect_path_stream_fini(void *v)383{384struct redirect_path_stream *s = v;385386atf_process_stream_fini(&s->m_base.m_sb);387388atf_fs_path_fini(&s->m_path);389390check_file(s->m_base.m_type);391}392393static void child_print(void *) ATF_DEFS_ATTRIBUTE_NORETURN;394395struct child_print_data {396const char *m_msg;397};398399static400void401child_print(void *v)402{403struct child_print_data *cpd = v;404405fprintf(stdout, "stdout: %s\n", cpd->m_msg);406fprintf(stderr, "stderr: %s\n", cpd->m_msg);407408exit(EXIT_SUCCESS);409}410411static412void413do_fork(const struct base_stream *outfs, void *out,414const struct base_stream *errfs, void *err)415{416atf_process_child_t child;417atf_process_status_t status;418struct child_print_data cpd = { "msg" };419420outfs->init(out);421errfs->init(err);422423RE(atf_process_fork(&child, child_print, outfs->m_sb_ptr,424errfs->m_sb_ptr, &cpd));425if (outfs->process != NULL)426outfs->process(out, &child);427if (errfs->process != NULL)428errfs->process(err, &child);429RE(atf_process_child_wait(&child, &status));430431outfs->fini(out);432errfs->fini(err);433434atf_process_status_fini(&status);435}436437/* ---------------------------------------------------------------------438* Test cases for the "stream" type.439* --------------------------------------------------------------------- */440441ATF_TC(stream_init_capture);442ATF_TC_HEAD(stream_init_capture, tc)443{444atf_tc_set_md_var(tc, "descr", "Tests the "445"atf_process_stream_init_capture function");446}447ATF_TC_BODY(stream_init_capture, tc)448{449atf_process_stream_t sb;450451RE(atf_process_stream_init_capture(&sb));452453ATF_CHECK_EQ(atf_process_stream_type(&sb),454atf_process_stream_type_capture);455456atf_process_stream_fini(&sb);457}458459ATF_TC(stream_init_connect);460ATF_TC_HEAD(stream_init_connect, tc)461{462atf_tc_set_md_var(tc, "descr", "Tests the "463"atf_process_stream_init_connect function");464}465ATF_TC_BODY(stream_init_connect, tc)466{467atf_process_stream_t sb;468469RE(atf_process_stream_init_connect(&sb, 1, 2));470471ATF_CHECK_EQ(atf_process_stream_type(&sb),472atf_process_stream_type_connect);473474atf_process_stream_fini(&sb);475}476477ATF_TC(stream_init_inherit);478ATF_TC_HEAD(stream_init_inherit, tc)479{480atf_tc_set_md_var(tc, "descr", "Tests the "481"atf_process_stream_init_inherit function");482}483ATF_TC_BODY(stream_init_inherit, tc)484{485atf_process_stream_t sb;486487RE(atf_process_stream_init_inherit(&sb));488489ATF_CHECK_EQ(atf_process_stream_type(&sb),490atf_process_stream_type_inherit);491492atf_process_stream_fini(&sb);493}494495ATF_TC(stream_init_redirect_fd);496ATF_TC_HEAD(stream_init_redirect_fd, tc)497{498atf_tc_set_md_var(tc, "descr", "Tests the "499"atf_process_stream_init_redirect_fd function");500}501ATF_TC_BODY(stream_init_redirect_fd, tc)502{503atf_process_stream_t sb;504505RE(atf_process_stream_init_redirect_fd(&sb, 1));506507ATF_CHECK_EQ(atf_process_stream_type(&sb),508atf_process_stream_type_redirect_fd);509510atf_process_stream_fini(&sb);511}512513ATF_TC(stream_init_redirect_path);514ATF_TC_HEAD(stream_init_redirect_path, tc)515{516atf_tc_set_md_var(tc, "descr", "Tests the "517"atf_process_stream_init_redirect_path function");518}519ATF_TC_BODY(stream_init_redirect_path, tc)520{521atf_process_stream_t sb;522atf_fs_path_t path;523524RE(atf_fs_path_init_fmt(&path, "foo"));525RE(atf_process_stream_init_redirect_path(&sb, &path));526527ATF_CHECK_EQ(atf_process_stream_type(&sb),528atf_process_stream_type_redirect_path);529530atf_process_stream_fini(&sb);531atf_fs_path_fini(&path);532}533534/* ---------------------------------------------------------------------535* Test cases for the "status" type.536* --------------------------------------------------------------------- */537538static void child_exit_success(void) ATF_DEFS_ATTRIBUTE_NORETURN;539static void child_exit_failure(void) ATF_DEFS_ATTRIBUTE_NORETURN;540static void child_sigkill(void) ATF_DEFS_ATTRIBUTE_NORETURN;541static void child_sigquit(void) ATF_DEFS_ATTRIBUTE_NORETURN;542static void child_sigterm(void) ATF_DEFS_ATTRIBUTE_NORETURN;543544void545child_exit_success(void)546{547exit(EXIT_SUCCESS);548}549550void551child_exit_failure(void)552{553exit(EXIT_FAILURE);554}555556void557child_sigkill(void)558{559kill(getpid(), SIGKILL);560abort();561}562563void564child_sigquit(void)565{566kill(getpid(), SIGQUIT);567abort();568}569570void571child_sigterm(void)572{573kill(getpid(), SIGTERM);574abort();575}576577static578int579fork_and_wait_child(void (*child_func)(void))580{581pid_t pid;582int status;583584pid = fork();585ATF_REQUIRE(pid != -1);586if (pid == 0) {587status = 0; /* Silence compiler warnings */588child_func();589UNREACHABLE;590} else {591ATF_REQUIRE(waitpid(pid, &status, 0) != 0);592}593594return status;595}596597ATF_TC(status_exited);598ATF_TC_HEAD(status_exited, tc)599{600atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "601"that exit cleanly");602}603ATF_TC_BODY(status_exited, tc)604{605{606const int rawstatus = fork_and_wait_child(child_exit_success);607atf_process_status_t s;608RE(atf_process_status_init(&s, rawstatus));609ATF_CHECK(atf_process_status_exited(&s));610ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_SUCCESS);611ATF_CHECK(!atf_process_status_signaled(&s));612atf_process_status_fini(&s);613}614615{616const int rawstatus = fork_and_wait_child(child_exit_failure);617atf_process_status_t s;618RE(atf_process_status_init(&s, rawstatus));619ATF_CHECK(atf_process_status_exited(&s));620ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_FAILURE);621ATF_CHECK(!atf_process_status_signaled(&s));622atf_process_status_fini(&s);623}624}625626ATF_TC(status_signaled);627ATF_TC_HEAD(status_signaled, tc)628{629atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "630"that end due to a signal");631}632ATF_TC_BODY(status_signaled, tc)633{634{635const int rawstatus = fork_and_wait_child(child_sigkill);636atf_process_status_t s;637RE(atf_process_status_init(&s, rawstatus));638ATF_CHECK(!atf_process_status_exited(&s));639ATF_CHECK(atf_process_status_signaled(&s));640ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGKILL);641ATF_CHECK(!atf_process_status_coredump(&s));642atf_process_status_fini(&s);643}644645{646const int rawstatus = fork_and_wait_child(child_sigterm);647atf_process_status_t s;648RE(atf_process_status_init(&s, rawstatus));649ATF_CHECK(!atf_process_status_exited(&s));650ATF_CHECK(atf_process_status_signaled(&s));651ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGTERM);652ATF_CHECK(!atf_process_status_coredump(&s));653atf_process_status_fini(&s);654}655}656657ATF_TC(status_coredump);658ATF_TC_HEAD(status_coredump, tc)659{660atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "661"that crash");662}663ATF_TC_BODY(status_coredump, tc)664{665struct rlimit rl;666rl.rlim_cur = RLIM_INFINITY;667rl.rlim_max = RLIM_INFINITY;668if (setrlimit(RLIMIT_CORE, &rl) == -1)669atf_tc_skip("Cannot unlimit the core file size; check limits "670"manually");671672#ifdef __FreeBSD__673int coredump_enabled;674size_t ce_len = sizeof(coredump_enabled);675if (sysctlbyname("kern.coredump", &coredump_enabled, &ce_len, NULL,6760) == 0 && !coredump_enabled)677atf_tc_skip("Coredumps disabled");678#endif679680const int rawstatus = fork_and_wait_child(child_sigquit);681atf_process_status_t s;682RE(atf_process_status_init(&s, rawstatus));683ATF_CHECK(!atf_process_status_exited(&s));684ATF_CHECK(atf_process_status_signaled(&s));685ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGQUIT);686ATF_CHECK(atf_process_status_coredump(&s));687atf_process_status_fini(&s);688}689690/* ---------------------------------------------------------------------691* Test cases for the "child" type.692* --------------------------------------------------------------------- */693694static void child_report_pid(void *) ATF_DEFS_ATTRIBUTE_NORETURN;695696static697void698child_report_pid(void *v ATF_DEFS_ATTRIBUTE_UNUSED)699{700const pid_t pid = getpid();701if (write(STDOUT_FILENO, &pid, sizeof(pid)) != sizeof(pid))702abort();703fprintf(stderr, "Reporting %d to parent\n", (int)getpid());704exit(EXIT_SUCCESS);705}706707ATF_TC(child_pid);708ATF_TC_HEAD(child_pid, tc)709{710atf_tc_set_md_var(tc, "descr", "Tests the correctness of the pid "711"stored in the child type");712}713ATF_TC_BODY(child_pid, tc)714{715atf_process_stream_t outsb, errsb;716atf_process_child_t child;717atf_process_status_t status;718pid_t pid;719720RE(atf_process_stream_init_capture(&outsb));721RE(atf_process_stream_init_inherit(&errsb));722723RE(atf_process_fork(&child, child_report_pid, &outsb, &errsb, NULL));724ATF_CHECK_EQ(read(atf_process_child_stdout(&child), &pid, sizeof(pid)),725sizeof(pid));726printf("Expected PID: %d\n", (int)atf_process_child_pid(&child));727printf("Actual PID: %d\n", (int)pid);728ATF_CHECK_EQ(atf_process_child_pid(&child), pid);729730RE(atf_process_child_wait(&child, &status));731atf_process_status_fini(&status);732733atf_process_stream_fini(&outsb);734atf_process_stream_fini(&errsb);735}736737static738void739child_loop(void *v ATF_DEFS_ATTRIBUTE_UNUSED)740{741for (;;)742sleep(1);743}744745static746void747nop_signal(int sig ATF_DEFS_ATTRIBUTE_UNUSED)748{749}750751static752void753child_spawn_loop_and_wait_eintr(void *v ATF_DEFS_ATTRIBUTE_UNUSED)754{755atf_process_child_t child;756atf_process_status_t status;757struct sigaction sighup, old_sighup;758759#define RE_ABORT(expr) \760do { \761atf_error_t _aux_err = expr; \762if (atf_is_error(_aux_err)) { \763atf_error_free(_aux_err); \764abort(); \765} \766} while (0)767768{769atf_process_stream_t outsb, errsb;770771RE_ABORT(atf_process_stream_init_capture(&outsb));772RE_ABORT(atf_process_stream_init_inherit(&errsb));773RE_ABORT(atf_process_fork(&child, child_loop, &outsb, &errsb, NULL));774atf_process_stream_fini(&outsb);775atf_process_stream_fini(&errsb);776}777778sighup.sa_handler = nop_signal;779sigemptyset(&sighup.sa_mask);780sighup.sa_flags = 0;781if (sigaction(SIGHUP, &sighup, &old_sighup) == -1)782abort();783784printf("waiting\n");785fflush(stdout);786787fprintf(stderr, "Child entering wait(2)\n");788atf_error_t err = atf_process_child_wait(&child, &status);789fprintf(stderr, "Child's wait(2) terminated\n");790if (!atf_is_error(err)) {791fprintf(stderr, "wait completed successfully (not interrupted)\n");792abort();793}794if (!atf_error_is(err, "libc")) {795fprintf(stderr, "wait did not raise libc_error\n");796abort();797}798if (atf_libc_error_code(err) != EINTR) {799fprintf(stderr, "libc_error is not EINTR\n");800abort();801}802atf_error_free(err);803804sigaction(SIGHUP, &old_sighup, NULL);805806fprintf(stderr, "Child is killing subchild\n");807kill(atf_process_child_pid(&child), SIGTERM);808809RE_ABORT(atf_process_child_wait(&child, &status));810atf_process_status_fini(&status);811812#undef RE_ABORT813814exit(EXIT_SUCCESS);815}816817ATF_TC(child_wait_eintr);818ATF_TC_HEAD(child_wait_eintr, tc)819{820atf_tc_set_md_var(tc, "descr", "Tests the interruption of the wait "821"method by an external signal, and the return of "822"an EINTR error");823atf_tc_set_md_var(tc, "timeout", "30");824}825ATF_TC_BODY(child_wait_eintr, tc)826{827atf_process_child_t child;828atf_process_status_t status;829830{831atf_process_stream_t outsb, errsb;832833RE(atf_process_stream_init_capture(&outsb));834RE(atf_process_stream_init_inherit(&errsb));835RE(atf_process_fork(&child, child_spawn_loop_and_wait_eintr,836&outsb, &errsb, NULL));837atf_process_stream_fini(&outsb);838atf_process_stream_fini(&errsb);839}840841{842/* Wait until the child process performs the wait call. This is843* racy, because the message we get from it is sent *before*844* doing the real system call... but I can't figure any other way845* to do this. */846char buf[16];847printf("Waiting for child to issue wait(2)\n");848ATF_REQUIRE(read(atf_process_child_stdout(&child), buf,849sizeof(buf)) > 0);850sleep(1);851}852853printf("Interrupting child's wait(2) call\n");854kill(atf_process_child_pid(&child), SIGHUP);855856printf("Waiting for child's completion\n");857RE(atf_process_child_wait(&child, &status));858ATF_REQUIRE(atf_process_status_exited(&status));859ATF_REQUIRE_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);860atf_process_status_fini(&status);861}862863/* ---------------------------------------------------------------------864* Tests cases for the free functions.865* --------------------------------------------------------------------- */866867static868void869do_exec(const atf_tc_t *tc, const char *helper_name, atf_process_status_t *s,870void (*prehook)(void))871{872atf_fs_path_t process_helpers;873const char *argv[3];874875get_process_helpers_path(tc, true, &process_helpers);876877argv[0] = atf_fs_path_cstring(&process_helpers);878argv[1] = helper_name;879argv[2] = NULL;880printf("Executing %s %s\n", argv[0], argv[1]);881882RE(atf_process_exec_array(s, &process_helpers, argv, NULL, NULL, prehook));883atf_fs_path_fini(&process_helpers);884}885886static887void888check_line(int fd, const char *exp)889{890char *line = atf_utils_readline(fd);891ATF_CHECK(line != NULL);892ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp);893free(line);894}895896ATF_TC(exec_failure);897ATF_TC_HEAD(exec_failure, tc)898{899atf_tc_set_md_var(tc, "descr", "Tests execing a command");900}901ATF_TC_BODY(exec_failure, tc)902{903atf_process_status_t status;904905do_exec(tc, "exit-failure", &status, NULL);906ATF_CHECK(atf_process_status_exited(&status));907ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_FAILURE);908atf_process_status_fini(&status);909}910911ATF_TC(exec_list);912ATF_TC_HEAD(exec_list, tc)913{914atf_tc_set_md_var(tc, "descr", "Tests execing a command");915}916ATF_TC_BODY(exec_list, tc)917{918atf_fs_path_t process_helpers;919atf_list_t argv;920atf_process_status_t status;921922RE(atf_list_init(&argv));923924get_process_helpers_path(tc, true, &process_helpers);925atf_list_append(&argv, strdup(atf_fs_path_cstring(&process_helpers)), true);926atf_list_append(&argv, strdup("echo"), true);927atf_list_append(&argv, strdup("test-message"), true);928{929atf_fs_path_t outpath;930atf_process_stream_t outsb;931932RE(atf_fs_path_init_fmt(&outpath, "stdout"));933RE(atf_process_stream_init_redirect_path(&outsb, &outpath));934RE(atf_process_exec_list(&status, &process_helpers, &argv, &outsb,935NULL, NULL));936atf_process_stream_fini(&outsb);937atf_fs_path_fini(&outpath);938}939atf_list_fini(&argv);940941ATF_CHECK(atf_process_status_exited(&status));942ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);943944{945int fd = open("stdout", O_RDONLY);946ATF_CHECK(fd != -1);947check_line(fd, "test-message");948close(fd);949}950951atf_process_status_fini(&status);952atf_fs_path_fini(&process_helpers);953}954955static void956exit_early(void)957{958exit(80);959}960961ATF_TC(exec_prehook);962ATF_TC_HEAD(exec_prehook, tc)963{964atf_tc_set_md_var(tc, "descr", "Tests execing a command with a prehook");965}966ATF_TC_BODY(exec_prehook, tc)967{968atf_process_status_t status;969970do_exec(tc, "exit-success", &status, exit_early);971ATF_CHECK(atf_process_status_exited(&status));972ATF_CHECK_EQ(atf_process_status_exitstatus(&status), 80);973atf_process_status_fini(&status);974}975976ATF_TC(exec_success);977ATF_TC_HEAD(exec_success, tc)978{979atf_tc_set_md_var(tc, "descr", "Tests execing a command");980}981ATF_TC_BODY(exec_success, tc)982{983atf_process_status_t status;984985do_exec(tc, "exit-success", &status, NULL);986ATF_CHECK(atf_process_status_exited(&status));987ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);988atf_process_status_fini(&status);989}990991static const int exit_v_null = 1;992static const int exit_v_notnull = 2;993994static995void996child_cookie(void *v)997{998if (v == NULL)999exit(exit_v_null);1000else1001exit(exit_v_notnull);10021003UNREACHABLE;1004}10051006ATF_TC(fork_cookie);1007ATF_TC_HEAD(fork_cookie, tc)1008{1009atf_tc_set_md_var(tc, "descr", "Tests forking a child, with "1010"a null and non-null data cookie");1011}1012ATF_TC_BODY(fork_cookie, tc)1013{1014atf_process_stream_t outsb, errsb;10151016RE(atf_process_stream_init_inherit(&outsb));1017RE(atf_process_stream_init_inherit(&errsb));10181019{1020atf_process_child_t child;1021atf_process_status_t status;10221023RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, NULL));1024RE(atf_process_child_wait(&child, &status));10251026ATF_CHECK(atf_process_status_exited(&status));1027ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_null);10281029atf_process_status_fini(&status);1030}10311032{1033atf_process_child_t child;1034atf_process_status_t status;1035int dummy_int;10361037RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, &dummy_int));1038RE(atf_process_child_wait(&child, &status));10391040ATF_CHECK(atf_process_status_exited(&status));1041ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_notnull);10421043atf_process_status_fini(&status);1044}10451046atf_process_stream_fini(&errsb);1047atf_process_stream_fini(&outsb);1048}10491050#define TC_FORK_STREAMS(outlc, outuc, errlc, erruc) \1051ATF_TC(fork_out_ ## outlc ## _err_ ## errlc); \1052ATF_TC_HEAD(fork_out_ ## outlc ## _err_ ## errlc, tc) \1053{ \1054atf_tc_set_md_var(tc, "descr", "Tests forking a child, with " \1055"stdout " #outlc " and stderr " #errlc); \1056} \1057ATF_TC_BODY(fork_out_ ## outlc ## _err_ ## errlc, tc) \1058{ \1059struct outlc ## _stream out = outuc ## _STREAM(stdout_type); \1060struct errlc ## _stream err = erruc ## _STREAM(stderr_type); \1061do_fork(&out.m_base, &out, &err.m_base, &err); \1062}10631064TC_FORK_STREAMS(capture, CAPTURE, capture, CAPTURE);1065TC_FORK_STREAMS(capture, CAPTURE, connect, CONNECT);1066TC_FORK_STREAMS(capture, CAPTURE, default, DEFAULT);1067TC_FORK_STREAMS(capture, CAPTURE, inherit, INHERIT);1068TC_FORK_STREAMS(capture, CAPTURE, redirect_fd, REDIRECT_FD);1069TC_FORK_STREAMS(capture, CAPTURE, redirect_path, REDIRECT_PATH);1070TC_FORK_STREAMS(connect, CONNECT, capture, CAPTURE);1071TC_FORK_STREAMS(connect, CONNECT, connect, CONNECT);1072TC_FORK_STREAMS(connect, CONNECT, default, DEFAULT);1073TC_FORK_STREAMS(connect, CONNECT, inherit, INHERIT);1074TC_FORK_STREAMS(connect, CONNECT, redirect_fd, REDIRECT_FD);1075TC_FORK_STREAMS(connect, CONNECT, redirect_path, REDIRECT_PATH);1076TC_FORK_STREAMS(default, DEFAULT, capture, CAPTURE);1077TC_FORK_STREAMS(default, DEFAULT, connect, CONNECT);1078TC_FORK_STREAMS(default, DEFAULT, default, DEFAULT);1079TC_FORK_STREAMS(default, DEFAULT, inherit, INHERIT);1080TC_FORK_STREAMS(default, DEFAULT, redirect_fd, REDIRECT_FD);1081TC_FORK_STREAMS(default, DEFAULT, redirect_path, REDIRECT_PATH);1082TC_FORK_STREAMS(inherit, INHERIT, capture, CAPTURE);1083TC_FORK_STREAMS(inherit, INHERIT, connect, CONNECT);1084TC_FORK_STREAMS(inherit, INHERIT, default, DEFAULT);1085TC_FORK_STREAMS(inherit, INHERIT, inherit, INHERIT);1086TC_FORK_STREAMS(inherit, INHERIT, redirect_fd, REDIRECT_FD);1087TC_FORK_STREAMS(inherit, INHERIT, redirect_path, REDIRECT_PATH);1088TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, capture, CAPTURE);1089TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, connect, CONNECT);1090TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, default, DEFAULT);1091TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, inherit, INHERIT);1092TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_fd, REDIRECT_FD);1093TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_path, REDIRECT_PATH);1094TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, capture, CAPTURE);1095TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, connect, CONNECT);1096TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, default, DEFAULT);1097TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, inherit, INHERIT);1098TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_fd, REDIRECT_FD);1099TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_path, REDIRECT_PATH);11001101#undef TC_FORK_STREAMS11021103/* ---------------------------------------------------------------------1104* Main.1105* --------------------------------------------------------------------- */11061107ATF_TP_ADD_TCS(tp)1108{1109/* Add the tests for the "stream" type. */1110ATF_TP_ADD_TC(tp, stream_init_capture);1111ATF_TP_ADD_TC(tp, stream_init_connect);1112ATF_TP_ADD_TC(tp, stream_init_inherit);1113ATF_TP_ADD_TC(tp, stream_init_redirect_fd);1114ATF_TP_ADD_TC(tp, stream_init_redirect_path);11151116/* Add the tests for the "status" type. */1117ATF_TP_ADD_TC(tp, status_exited);1118ATF_TP_ADD_TC(tp, status_signaled);1119ATF_TP_ADD_TC(tp, status_coredump);11201121/* Add the tests for the "child" type. */1122ATF_TP_ADD_TC(tp, child_pid);1123ATF_TP_ADD_TC(tp, child_wait_eintr);11241125/* Add the tests for the free functions. */1126ATF_TP_ADD_TC(tp, exec_failure);1127ATF_TP_ADD_TC(tp, exec_list);1128ATF_TP_ADD_TC(tp, exec_prehook);1129ATF_TP_ADD_TC(tp, exec_success);1130ATF_TP_ADD_TC(tp, fork_cookie);1131ATF_TP_ADD_TC(tp, fork_out_capture_err_capture);1132ATF_TP_ADD_TC(tp, fork_out_capture_err_connect);1133ATF_TP_ADD_TC(tp, fork_out_capture_err_default);1134ATF_TP_ADD_TC(tp, fork_out_capture_err_inherit);1135ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_fd);1136ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_path);1137ATF_TP_ADD_TC(tp, fork_out_connect_err_capture);1138ATF_TP_ADD_TC(tp, fork_out_connect_err_connect);1139ATF_TP_ADD_TC(tp, fork_out_connect_err_default);1140ATF_TP_ADD_TC(tp, fork_out_connect_err_inherit);1141ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_fd);1142ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_path);1143ATF_TP_ADD_TC(tp, fork_out_default_err_capture);1144ATF_TP_ADD_TC(tp, fork_out_default_err_connect);1145ATF_TP_ADD_TC(tp, fork_out_default_err_default);1146ATF_TP_ADD_TC(tp, fork_out_default_err_inherit);1147ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_fd);1148ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_path);1149ATF_TP_ADD_TC(tp, fork_out_inherit_err_capture);1150ATF_TP_ADD_TC(tp, fork_out_inherit_err_connect);1151ATF_TP_ADD_TC(tp, fork_out_inherit_err_default);1152ATF_TP_ADD_TC(tp, fork_out_inherit_err_inherit);1153ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_fd);1154ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_path);1155ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_capture);1156ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_connect);1157ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_default);1158ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_inherit);1159ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_fd);1160ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_path);1161ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_capture);1162ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_connect);1163ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_default);1164ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_inherit);1165ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_fd);1166ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_path);11671168return atf_no_error();1169}117011711172