1273929Sjmmv/* Copyright (c) 2008 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
24273929Sjmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25240116Smarcel
26273929Sjmmv#include "atf-c/detail/process.h"
27273929Sjmmv
28240116Smarcel#include <sys/types.h>
29240116Smarcel#include <sys/time.h>
30240116Smarcel#include <sys/resource.h>
31240116Smarcel#include <sys/wait.h>
32240116Smarcel
33240116Smarcel#include <errno.h>
34240116Smarcel#include <fcntl.h>
35240116Smarcel#include <signal.h>
36240116Smarcel#include <stdio.h>
37240116Smarcel#include <stdlib.h>
38240116Smarcel#include <string.h>
39240116Smarcel#include <unistd.h>
40240116Smarcel
41240116Smarcel#include <atf-c.h>
42240116Smarcel
43240116Smarcel#include "atf-c/defs.h"
44273929Sjmmv#include "atf-c/detail/sanity.h"
45273929Sjmmv#include "atf-c/detail/test_helpers.h"
46240116Smarcel
47240116Smarcelatf_error_t atf_process_status_init(atf_process_status_t *, int);
48240116Smarcel
49240116Smarcel/* ---------------------------------------------------------------------
50240116Smarcel * Auxiliary functions for testing of 'atf_process_fork'.
51240116Smarcel * --------------------------------------------------------------------- */
52240116Smarcel
53240116Smarcel/*
54240116Smarcel * Testing of atf_process_fork is quite messy.  We want to be able to test
55240116Smarcel * all the possible combinations of stdout and stderr behavior to ensure
56240116Smarcel * that the streams are manipulated correctly.
57240116Smarcel *
58240116Smarcel * To do this, the do_fork function is a wrapper for atf_process_fork that
59240116Smarcel * issues stream-specific hooks before fork, while the child is running and
60240116Smarcel * after the child terminates.  We then provide test cases that just call
61240116Smarcel * do_fork with different hooks.
62240116Smarcel *
63240116Smarcel * The hooks are described by base_stream, and we then have one *_stream
64240116Smarcel * type for ever possible stream behavior.
65240116Smarcel */
66240116Smarcel
67240116Smarcelenum out_type { stdout_type, stderr_type };
68240116Smarcel
69240116Smarcelstruct base_stream {
70240116Smarcel    void (*init)(void *);
71240116Smarcel    void (*process)(void *, atf_process_child_t *);
72240116Smarcel    void (*fini)(void *);
73240116Smarcel
74240116Smarcel    /* m_sb is initialized by subclasses that need it, but all consumers
75240116Smarcel     * must use m_sb_ptr, which may or may not point to m_sb.  This allows
76240116Smarcel     * us to test the interface with a NULL value, which triggers a
77240116Smarcel     * default behavior. */
78240116Smarcel    atf_process_stream_t m_sb;
79240116Smarcel    atf_process_stream_t *m_sb_ptr;
80240116Smarcel    enum out_type m_type;
81240116Smarcel};
82240116Smarcel#define BASE_STREAM(ihook, phook, fhook, type) \
83240116Smarcel    { .init = ihook, \
84240116Smarcel      .process = phook, \
85240116Smarcel      .fini = fhook, \
86240116Smarcel      .m_type = type }
87240116Smarcel
88240116Smarcelstatic
89240116Smarcelvoid
90240116Smarcelcheck_file(const enum out_type type)
91240116Smarcel{
92240116Smarcel    switch (type) {
93240116Smarcel    case stdout_type:
94258289Sjmmv        ATF_CHECK(atf_utils_grep_file("stdout: msg", "stdout"));
95258289Sjmmv        ATF_CHECK(!atf_utils_grep_file("stderr: msg", "stdout"));
96240116Smarcel        break;
97240116Smarcel    case stderr_type:
98258289Sjmmv        ATF_CHECK(atf_utils_grep_file("stderr: msg", "stderr"));
99258289Sjmmv        ATF_CHECK(!atf_utils_grep_file("stdout: msg", "stderr"));
100240116Smarcel        break;
101240116Smarcel    default:
102240116Smarcel        UNREACHABLE;
103240116Smarcel    }
104240116Smarcel}
105240116Smarcel
106240116Smarcelstruct capture_stream {
107240116Smarcel    struct base_stream m_base;
108240116Smarcel
109258289Sjmmv    char *m_msg;
110240116Smarcel};
111240116Smarcel#define CAPTURE_STREAM(type) \
112240116Smarcel    { .m_base = BASE_STREAM(capture_stream_init, \
113240116Smarcel                            capture_stream_process, \
114240116Smarcel                            capture_stream_fini, \
115240116Smarcel                            type) }
116240116Smarcel
117240116Smarcelstatic
118240116Smarcelvoid
119240116Smarcelcapture_stream_init(void *v)
120240116Smarcel{
121240116Smarcel    struct capture_stream *s = v;
122240116Smarcel
123240116Smarcel    s->m_base.m_sb_ptr = &s->m_base.m_sb;
124240116Smarcel    RE(atf_process_stream_init_capture(&s->m_base.m_sb));
125258289Sjmmv    s->m_msg = NULL;
126240116Smarcel}
127240116Smarcel
128240116Smarcelstatic
129240116Smarcelvoid
130240116Smarcelcapture_stream_process(void *v, atf_process_child_t *c)
131240116Smarcel{
132240116Smarcel    struct capture_stream *s = v;
133240116Smarcel
134240116Smarcel    switch (s->m_base.m_type) {
135240116Smarcel    case stdout_type:
136258289Sjmmv        s->m_msg = atf_utils_readline(atf_process_child_stdout(c));
137240116Smarcel        break;
138240116Smarcel    case stderr_type:
139258289Sjmmv        s->m_msg = atf_utils_readline(atf_process_child_stderr(c));
140240116Smarcel        break;
141240116Smarcel    default:
142240116Smarcel        UNREACHABLE;
143240116Smarcel    }
144240116Smarcel}
145240116Smarcel
146240116Smarcelstatic
147240116Smarcelvoid
148240116Smarcelcapture_stream_fini(void *v)
149240116Smarcel{
150240116Smarcel    struct capture_stream *s = v;
151240116Smarcel
152240116Smarcel    switch (s->m_base.m_type) {
153240116Smarcel    case stdout_type:
154258289Sjmmv        ATF_CHECK(atf_utils_grep_string("stdout: msg", s->m_msg));
155258289Sjmmv        ATF_CHECK(!atf_utils_grep_string("stderr: msg", s->m_msg));
156240116Smarcel        break;
157240116Smarcel    case stderr_type:
158258289Sjmmv        ATF_CHECK(!atf_utils_grep_string("stdout: msg", s->m_msg));
159258289Sjmmv        ATF_CHECK(atf_utils_grep_string("stderr: msg", s->m_msg));
160240116Smarcel        break;
161240116Smarcel    default:
162240116Smarcel        UNREACHABLE;
163240116Smarcel    }
164240116Smarcel
165258289Sjmmv    free(s->m_msg);
166240116Smarcel    atf_process_stream_fini(&s->m_base.m_sb);
167240116Smarcel}
168240116Smarcel
169240116Smarcelstruct connect_stream {
170240116Smarcel    struct base_stream m_base;
171240116Smarcel
172240116Smarcel    int m_fd;
173240116Smarcel};
174240116Smarcel#define CONNECT_STREAM(type) \
175240116Smarcel    { .m_base = BASE_STREAM(connect_stream_init, \
176240116Smarcel                            NULL, \
177240116Smarcel                            connect_stream_fini, \
178240116Smarcel                            type) }
179240116Smarcel
180240116Smarcelstatic
181240116Smarcelvoid
182240116Smarcelconnect_stream_init(void *v)
183240116Smarcel{
184240116Smarcel    struct connect_stream *s = v;
185240116Smarcel    int src_fd;
186240116Smarcel
187240116Smarcel    switch (s->m_base.m_type) {
188240116Smarcel    case stdout_type:
189240116Smarcel        src_fd = STDOUT_FILENO;
190240116Smarcel        s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644);
191240116Smarcel        break;
192240116Smarcel    case stderr_type:
193240116Smarcel        src_fd = STDERR_FILENO;
194240116Smarcel        s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644);
195240116Smarcel        break;
196240116Smarcel    default:
197240116Smarcel        UNREACHABLE;
198240116Smarcel        src_fd = -1;
199240116Smarcel    }
200240116Smarcel    ATF_REQUIRE(s->m_fd != -1);
201240116Smarcel
202240116Smarcel    s->m_base.m_sb_ptr = &s->m_base.m_sb;
203240116Smarcel    RE(atf_process_stream_init_connect(&s->m_base.m_sb, src_fd, s->m_fd));
204240116Smarcel}
205240116Smarcel
206240116Smarcelstatic
207240116Smarcelvoid
208240116Smarcelconnect_stream_fini(void *v)
209240116Smarcel{
210240116Smarcel    struct connect_stream *s = v;
211240116Smarcel
212240116Smarcel    ATF_REQUIRE(close(s->m_fd) != -1);
213240116Smarcel
214240116Smarcel    atf_process_stream_fini(&s->m_base.m_sb);
215240116Smarcel
216240116Smarcel    check_file(s->m_base.m_type);
217240116Smarcel}
218240116Smarcel
219240116Smarcelstruct inherit_stream {
220240116Smarcel    struct base_stream m_base;
221240116Smarcel    int m_fd;
222240116Smarcel
223240116Smarcel    int m_old_fd;
224240116Smarcel};
225240116Smarcel#define INHERIT_STREAM(type) \
226240116Smarcel    { .m_base = BASE_STREAM(inherit_stream_init, \
227240116Smarcel                            NULL, \
228240116Smarcel                            inherit_stream_fini, \
229240116Smarcel                            type) }
230240116Smarcel
231240116Smarcelstatic
232240116Smarcelvoid
233240116Smarcelinherit_stream_init(void *v)
234240116Smarcel{
235240116Smarcel    struct inherit_stream *s = v;
236240116Smarcel    const char *name;
237240116Smarcel
238240116Smarcel    s->m_base.m_sb_ptr = &s->m_base.m_sb;
239240116Smarcel    RE(atf_process_stream_init_inherit(&s->m_base.m_sb));
240240116Smarcel
241240116Smarcel    switch (s->m_base.m_type) {
242240116Smarcel    case stdout_type:
243240116Smarcel        s->m_fd = STDOUT_FILENO;
244240116Smarcel        name = "stdout";
245240116Smarcel        break;
246240116Smarcel    case stderr_type:
247240116Smarcel        s->m_fd = STDERR_FILENO;
248240116Smarcel        name = "stderr";
249240116Smarcel        break;
250240116Smarcel    default:
251240116Smarcel        UNREACHABLE;
252240116Smarcel        name = NULL;
253240116Smarcel    }
254240116Smarcel
255240116Smarcel    s->m_old_fd = dup(s->m_fd);
256240116Smarcel    ATF_REQUIRE(s->m_old_fd != -1);
257240116Smarcel    ATF_REQUIRE(close(s->m_fd) != -1);
258240116Smarcel    ATF_REQUIRE_EQ(open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644),
259240116Smarcel                   s->m_fd);
260240116Smarcel}
261240116Smarcel
262240116Smarcelstatic
263240116Smarcelvoid
264240116Smarcelinherit_stream_fini(void *v)
265240116Smarcel{
266240116Smarcel    struct inherit_stream *s = v;
267240116Smarcel
268240116Smarcel    ATF_REQUIRE(dup2(s->m_old_fd, s->m_fd) != -1);
269240116Smarcel    ATF_REQUIRE(close(s->m_old_fd) != -1);
270240116Smarcel
271240116Smarcel    atf_process_stream_fini(&s->m_base.m_sb);
272240116Smarcel
273240116Smarcel    check_file(s->m_base.m_type);
274240116Smarcel}
275240116Smarcel
276240116Smarcel#define default_stream inherit_stream
277240116Smarcel#define DEFAULT_STREAM(type) \
278240116Smarcel    { .m_base = BASE_STREAM(default_stream_init, \
279240116Smarcel                            NULL, \
280240116Smarcel                            default_stream_fini, \
281240116Smarcel                            type) }
282240116Smarcel
283240116Smarcelstatic
284240116Smarcelvoid
285240116Smarceldefault_stream_init(void *v)
286240116Smarcel{
287240116Smarcel    struct inherit_stream *s = v;
288240116Smarcel
289240116Smarcel    inherit_stream_init(v);
290240116Smarcel    s->m_base.m_sb_ptr = NULL;
291240116Smarcel}
292240116Smarcel
293240116Smarcelstatic
294240116Smarcelvoid
295240116Smarceldefault_stream_fini(void *v)
296240116Smarcel{
297240116Smarcel    inherit_stream_fini(v);
298240116Smarcel}
299240116Smarcel
300240116Smarcelstruct redirect_fd_stream {
301240116Smarcel    struct base_stream m_base;
302240116Smarcel
303240116Smarcel    int m_fd;
304240116Smarcel};
305240116Smarcel#define REDIRECT_FD_STREAM(type) \
306240116Smarcel    { .m_base = BASE_STREAM(redirect_fd_stream_init, \
307240116Smarcel                            NULL, \
308240116Smarcel                            redirect_fd_stream_fini, \
309240116Smarcel                            type) }
310240116Smarcel
311240116Smarcelstatic
312240116Smarcelvoid
313240116Smarcelredirect_fd_stream_init(void *v)
314240116Smarcel{
315240116Smarcel    struct redirect_fd_stream *s = v;
316240116Smarcel
317240116Smarcel    switch (s->m_base.m_type) {
318240116Smarcel    case stdout_type:
319240116Smarcel        s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644);
320240116Smarcel        break;
321240116Smarcel    case stderr_type:
322240116Smarcel        s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644);
323240116Smarcel        break;
324240116Smarcel    default:
325240116Smarcel        UNREACHABLE;
326240116Smarcel    }
327240116Smarcel    ATF_REQUIRE(s->m_fd != -1);
328240116Smarcel
329240116Smarcel    s->m_base.m_sb_ptr = &s->m_base.m_sb;
330240116Smarcel    RE(atf_process_stream_init_redirect_fd(&s->m_base.m_sb, s->m_fd));
331240116Smarcel}
332240116Smarcel
333240116Smarcelstatic
334240116Smarcelvoid
335240116Smarcelredirect_fd_stream_fini(void *v)
336240116Smarcel{
337240116Smarcel    struct redirect_fd_stream *s = v;
338240116Smarcel
339240116Smarcel    ATF_REQUIRE(close(s->m_fd) != -1);
340240116Smarcel
341240116Smarcel    atf_process_stream_fini(&s->m_base.m_sb);
342240116Smarcel
343240116Smarcel    check_file(s->m_base.m_type);
344240116Smarcel}
345240116Smarcel
346240116Smarcelstruct redirect_path_stream {
347240116Smarcel    struct base_stream m_base;
348240116Smarcel
349240116Smarcel    atf_fs_path_t m_path;
350240116Smarcel};
351240116Smarcel#define REDIRECT_PATH_STREAM(type) \
352240116Smarcel    { .m_base = BASE_STREAM(redirect_path_stream_init, \
353240116Smarcel                            NULL, \
354240116Smarcel                            redirect_path_stream_fini, \
355240116Smarcel                            type) }
356240116Smarcel
357240116Smarcelstatic
358240116Smarcelvoid
359240116Smarcelredirect_path_stream_init(void *v)
360240116Smarcel{
361240116Smarcel    struct redirect_path_stream *s = v;
362240116Smarcel
363240116Smarcel    switch (s->m_base.m_type) {
364240116Smarcel    case stdout_type:
365240116Smarcel        RE(atf_fs_path_init_fmt(&s->m_path, "stdout"));
366240116Smarcel        break;
367240116Smarcel    case stderr_type:
368240116Smarcel        RE(atf_fs_path_init_fmt(&s->m_path, "stderr"));
369240116Smarcel        break;
370240116Smarcel    default:
371240116Smarcel        UNREACHABLE;
372240116Smarcel    }
373240116Smarcel
374240116Smarcel    s->m_base.m_sb_ptr = &s->m_base.m_sb;
375240116Smarcel    RE(atf_process_stream_init_redirect_path(&s->m_base.m_sb, &s->m_path));
376240116Smarcel}
377240116Smarcel
378240116Smarcelstatic
379240116Smarcelvoid
380240116Smarcelredirect_path_stream_fini(void *v)
381240116Smarcel{
382240116Smarcel    struct redirect_path_stream *s = v;
383240116Smarcel
384240116Smarcel    atf_process_stream_fini(&s->m_base.m_sb);
385240116Smarcel
386240116Smarcel    atf_fs_path_fini(&s->m_path);
387240116Smarcel
388240116Smarcel    check_file(s->m_base.m_type);
389240116Smarcel}
390240116Smarcel
391240116Smarcelstatic void child_print(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
392240116Smarcel
393240116Smarcelstruct child_print_data {
394240116Smarcel    const char *m_msg;
395240116Smarcel};
396240116Smarcel
397240116Smarcelstatic
398240116Smarcelvoid
399240116Smarcelchild_print(void *v)
400240116Smarcel{
401240116Smarcel    struct child_print_data *cpd = v;
402240116Smarcel
403240116Smarcel    fprintf(stdout, "stdout: %s\n", cpd->m_msg);
404240116Smarcel    fprintf(stderr, "stderr: %s\n", cpd->m_msg);
405240116Smarcel
406240116Smarcel    exit(EXIT_SUCCESS);
407240116Smarcel}
408240116Smarcel
409240116Smarcelstatic
410240116Smarcelvoid
411240116Smarceldo_fork(const struct base_stream *outfs, void *out,
412240116Smarcel        const struct base_stream *errfs, void *err)
413240116Smarcel{
414240116Smarcel    atf_process_child_t child;
415240116Smarcel    atf_process_status_t status;
416240116Smarcel    struct child_print_data cpd = { "msg" };
417240116Smarcel
418240116Smarcel    outfs->init(out);
419240116Smarcel    errfs->init(err);
420240116Smarcel
421240116Smarcel    RE(atf_process_fork(&child, child_print, outfs->m_sb_ptr,
422240116Smarcel                        errfs->m_sb_ptr, &cpd));
423240116Smarcel    if (outfs->process != NULL)
424240116Smarcel        outfs->process(out, &child);
425240116Smarcel    if (errfs->process != NULL)
426240116Smarcel        errfs->process(err, &child);
427240116Smarcel    RE(atf_process_child_wait(&child, &status));
428240116Smarcel
429240116Smarcel    outfs->fini(out);
430240116Smarcel    errfs->fini(err);
431240116Smarcel
432240116Smarcel    atf_process_status_fini(&status);
433240116Smarcel}
434240116Smarcel
435240116Smarcel/* ---------------------------------------------------------------------
436240116Smarcel * Test cases for the "stream" type.
437240116Smarcel * --------------------------------------------------------------------- */
438240116Smarcel
439240116SmarcelATF_TC(stream_init_capture);
440240116SmarcelATF_TC_HEAD(stream_init_capture, tc)
441240116Smarcel{
442240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the "
443240116Smarcel                      "atf_process_stream_init_capture function");
444240116Smarcel}
445240116SmarcelATF_TC_BODY(stream_init_capture, tc)
446240116Smarcel{
447240116Smarcel    atf_process_stream_t sb;
448240116Smarcel
449240116Smarcel    RE(atf_process_stream_init_capture(&sb));
450240116Smarcel
451240116Smarcel    ATF_CHECK_EQ(atf_process_stream_type(&sb),
452240116Smarcel                 atf_process_stream_type_capture);
453240116Smarcel
454240116Smarcel    atf_process_stream_fini(&sb);
455240116Smarcel}
456240116Smarcel
457240116SmarcelATF_TC(stream_init_connect);
458240116SmarcelATF_TC_HEAD(stream_init_connect, tc)
459240116Smarcel{
460240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the "
461240116Smarcel                      "atf_process_stream_init_connect function");
462240116Smarcel}
463240116SmarcelATF_TC_BODY(stream_init_connect, tc)
464240116Smarcel{
465240116Smarcel    atf_process_stream_t sb;
466240116Smarcel
467240116Smarcel    RE(atf_process_stream_init_connect(&sb, 1, 2));
468240116Smarcel
469240116Smarcel    ATF_CHECK_EQ(atf_process_stream_type(&sb),
470240116Smarcel                 atf_process_stream_type_connect);
471240116Smarcel
472240116Smarcel    atf_process_stream_fini(&sb);
473240116Smarcel}
474240116Smarcel
475240116SmarcelATF_TC(stream_init_inherit);
476240116SmarcelATF_TC_HEAD(stream_init_inherit, tc)
477240116Smarcel{
478240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the "
479240116Smarcel                      "atf_process_stream_init_inherit function");
480240116Smarcel}
481240116SmarcelATF_TC_BODY(stream_init_inherit, tc)
482240116Smarcel{
483240116Smarcel    atf_process_stream_t sb;
484240116Smarcel
485240116Smarcel    RE(atf_process_stream_init_inherit(&sb));
486240116Smarcel
487240116Smarcel    ATF_CHECK_EQ(atf_process_stream_type(&sb),
488240116Smarcel                 atf_process_stream_type_inherit);
489240116Smarcel
490240116Smarcel    atf_process_stream_fini(&sb);
491240116Smarcel}
492240116Smarcel
493240116SmarcelATF_TC(stream_init_redirect_fd);
494240116SmarcelATF_TC_HEAD(stream_init_redirect_fd, tc)
495240116Smarcel{
496240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the "
497240116Smarcel                      "atf_process_stream_init_redirect_fd function");
498240116Smarcel}
499240116SmarcelATF_TC_BODY(stream_init_redirect_fd, tc)
500240116Smarcel{
501240116Smarcel    atf_process_stream_t sb;
502240116Smarcel
503240116Smarcel    RE(atf_process_stream_init_redirect_fd(&sb, 1));
504240116Smarcel
505240116Smarcel    ATF_CHECK_EQ(atf_process_stream_type(&sb),
506240116Smarcel                 atf_process_stream_type_redirect_fd);
507240116Smarcel
508240116Smarcel    atf_process_stream_fini(&sb);
509240116Smarcel}
510240116Smarcel
511240116SmarcelATF_TC(stream_init_redirect_path);
512240116SmarcelATF_TC_HEAD(stream_init_redirect_path, tc)
513240116Smarcel{
514240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the "
515240116Smarcel                      "atf_process_stream_init_redirect_path function");
516240116Smarcel}
517240116SmarcelATF_TC_BODY(stream_init_redirect_path, tc)
518240116Smarcel{
519240116Smarcel    atf_process_stream_t sb;
520240116Smarcel    atf_fs_path_t path;
521240116Smarcel
522240116Smarcel    RE(atf_fs_path_init_fmt(&path, "foo"));
523240116Smarcel    RE(atf_process_stream_init_redirect_path(&sb, &path));
524240116Smarcel
525240116Smarcel    ATF_CHECK_EQ(atf_process_stream_type(&sb),
526240116Smarcel                 atf_process_stream_type_redirect_path);
527240116Smarcel
528240116Smarcel    atf_process_stream_fini(&sb);
529240116Smarcel    atf_fs_path_fini(&path);
530240116Smarcel}
531240116Smarcel
532240116Smarcel/* ---------------------------------------------------------------------
533240116Smarcel * Test cases for the "status" type.
534240116Smarcel * --------------------------------------------------------------------- */
535240116Smarcel
536240116Smarcelstatic void child_exit_success(void) ATF_DEFS_ATTRIBUTE_NORETURN;
537240116Smarcelstatic void child_exit_failure(void) ATF_DEFS_ATTRIBUTE_NORETURN;
538240116Smarcelstatic void child_sigkill(void) ATF_DEFS_ATTRIBUTE_NORETURN;
539240116Smarcelstatic void child_sigquit(void) ATF_DEFS_ATTRIBUTE_NORETURN;
540240116Smarcelstatic void child_sigterm(void) ATF_DEFS_ATTRIBUTE_NORETURN;
541240116Smarcel
542240116Smarcelvoid
543240116Smarcelchild_exit_success(void)
544240116Smarcel{
545240116Smarcel    exit(EXIT_SUCCESS);
546240116Smarcel}
547240116Smarcel
548240116Smarcelvoid
549240116Smarcelchild_exit_failure(void)
550240116Smarcel{
551240116Smarcel    exit(EXIT_FAILURE);
552240116Smarcel}
553240116Smarcel
554240116Smarcelvoid
555240116Smarcelchild_sigkill(void)
556240116Smarcel{
557240116Smarcel    kill(getpid(), SIGKILL);
558240116Smarcel    abort();
559240116Smarcel}
560240116Smarcel
561240116Smarcelvoid
562240116Smarcelchild_sigquit(void)
563240116Smarcel{
564240116Smarcel    kill(getpid(), SIGQUIT);
565240116Smarcel    abort();
566240116Smarcel}
567240116Smarcel
568240116Smarcelvoid
569240116Smarcelchild_sigterm(void)
570240116Smarcel{
571240116Smarcel    kill(getpid(), SIGTERM);
572240116Smarcel    abort();
573240116Smarcel}
574240116Smarcel
575240116Smarcelstatic
576240116Smarcelint
577240116Smarcelfork_and_wait_child(void (*child_func)(void))
578240116Smarcel{
579240116Smarcel    pid_t pid;
580240116Smarcel    int status;
581240116Smarcel
582240116Smarcel    pid = fork();
583240116Smarcel    ATF_REQUIRE(pid != -1);
584240116Smarcel    if (pid == 0) {
585240116Smarcel        status = 0; /* Silence compiler warnings */
586240116Smarcel        child_func();
587240116Smarcel        UNREACHABLE;
588240116Smarcel    } else {
589240116Smarcel        ATF_REQUIRE(waitpid(pid, &status, 0) != 0);
590240116Smarcel    }
591240116Smarcel
592240116Smarcel    return status;
593240116Smarcel}
594240116Smarcel
595240116SmarcelATF_TC(status_exited);
596240116SmarcelATF_TC_HEAD(status_exited, tc)
597240116Smarcel{
598240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
599240116Smarcel                      "that exit cleanly");
600240116Smarcel}
601240116SmarcelATF_TC_BODY(status_exited, tc)
602240116Smarcel{
603240116Smarcel    {
604240116Smarcel        const int rawstatus = fork_and_wait_child(child_exit_success);
605240116Smarcel        atf_process_status_t s;
606240116Smarcel        RE(atf_process_status_init(&s, rawstatus));
607240116Smarcel        ATF_CHECK(atf_process_status_exited(&s));
608240116Smarcel        ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_SUCCESS);
609240116Smarcel        ATF_CHECK(!atf_process_status_signaled(&s));
610240116Smarcel        atf_process_status_fini(&s);
611240116Smarcel    }
612240116Smarcel
613240116Smarcel    {
614240116Smarcel        const int rawstatus = fork_and_wait_child(child_exit_failure);
615240116Smarcel        atf_process_status_t s;
616240116Smarcel        RE(atf_process_status_init(&s, rawstatus));
617240116Smarcel        ATF_CHECK(atf_process_status_exited(&s));
618240116Smarcel        ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_FAILURE);
619240116Smarcel        ATF_CHECK(!atf_process_status_signaled(&s));
620240116Smarcel        atf_process_status_fini(&s);
621240116Smarcel    }
622240116Smarcel}
623240116Smarcel
624240116SmarcelATF_TC(status_signaled);
625240116SmarcelATF_TC_HEAD(status_signaled, tc)
626240116Smarcel{
627240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
628240116Smarcel                      "that end due to a signal");
629240116Smarcel}
630240116SmarcelATF_TC_BODY(status_signaled, tc)
631240116Smarcel{
632240116Smarcel    {
633240116Smarcel        const int rawstatus = fork_and_wait_child(child_sigkill);
634240116Smarcel        atf_process_status_t s;
635240116Smarcel        RE(atf_process_status_init(&s, rawstatus));
636240116Smarcel        ATF_CHECK(!atf_process_status_exited(&s));
637240116Smarcel        ATF_CHECK(atf_process_status_signaled(&s));
638240116Smarcel        ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGKILL);
639240116Smarcel        ATF_CHECK(!atf_process_status_coredump(&s));
640240116Smarcel        atf_process_status_fini(&s);
641240116Smarcel    }
642240116Smarcel
643240116Smarcel    {
644240116Smarcel        const int rawstatus = fork_and_wait_child(child_sigterm);
645240116Smarcel        atf_process_status_t s;
646240116Smarcel        RE(atf_process_status_init(&s, rawstatus));
647240116Smarcel        ATF_CHECK(!atf_process_status_exited(&s));
648240116Smarcel        ATF_CHECK(atf_process_status_signaled(&s));
649240116Smarcel        ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGTERM);
650240116Smarcel        ATF_CHECK(!atf_process_status_coredump(&s));
651240116Smarcel        atf_process_status_fini(&s);
652240116Smarcel    }
653240116Smarcel}
654240116Smarcel
655240116SmarcelATF_TC(status_coredump);
656240116SmarcelATF_TC_HEAD(status_coredump, tc)
657240116Smarcel{
658240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
659240116Smarcel                      "that crash");
660240116Smarcel}
661240116SmarcelATF_TC_BODY(status_coredump, tc)
662240116Smarcel{
663240116Smarcel    struct rlimit rl;
664240116Smarcel    rl.rlim_cur = RLIM_INFINITY;
665240116Smarcel    rl.rlim_max = RLIM_INFINITY;
666240116Smarcel    if (setrlimit(RLIMIT_CORE, &rl) == -1)
667240116Smarcel        atf_tc_skip("Cannot unlimit the core file size; check limits "
668240116Smarcel                    "manually");
669240116Smarcel
670240116Smarcel    const int rawstatus = fork_and_wait_child(child_sigquit);
671240116Smarcel    atf_process_status_t s;
672240116Smarcel    RE(atf_process_status_init(&s, rawstatus));
673240116Smarcel    ATF_CHECK(!atf_process_status_exited(&s));
674240116Smarcel    ATF_CHECK(atf_process_status_signaled(&s));
675240116Smarcel    ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGQUIT);
676240116Smarcel    ATF_CHECK(atf_process_status_coredump(&s));
677240116Smarcel    atf_process_status_fini(&s);
678240116Smarcel}
679240116Smarcel
680240116Smarcel/* ---------------------------------------------------------------------
681240116Smarcel * Test cases for the "child" type.
682240116Smarcel * --------------------------------------------------------------------- */
683240116Smarcel
684240116Smarcelstatic void child_report_pid(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
685240116Smarcel
686240116Smarcelstatic
687240116Smarcelvoid
688240116Smarcelchild_report_pid(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
689240116Smarcel{
690240116Smarcel    const pid_t pid = getpid();
691240116Smarcel    if (write(STDOUT_FILENO, &pid, sizeof(pid)) != sizeof(pid))
692240116Smarcel        abort();
693240116Smarcel    fprintf(stderr, "Reporting %d to parent\n", (int)getpid());
694240116Smarcel    exit(EXIT_SUCCESS);
695240116Smarcel}
696240116Smarcel
697240116SmarcelATF_TC(child_pid);
698240116SmarcelATF_TC_HEAD(child_pid, tc)
699240116Smarcel{
700240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the correctness of the pid "
701240116Smarcel                      "stored in the child type");
702240116Smarcel}
703240116SmarcelATF_TC_BODY(child_pid, tc)
704240116Smarcel{
705240116Smarcel    atf_process_stream_t outsb, errsb;
706240116Smarcel    atf_process_child_t child;
707240116Smarcel    atf_process_status_t status;
708240116Smarcel    pid_t pid;
709240116Smarcel
710240116Smarcel    RE(atf_process_stream_init_capture(&outsb));
711240116Smarcel    RE(atf_process_stream_init_inherit(&errsb));
712240116Smarcel
713240116Smarcel    RE(atf_process_fork(&child, child_report_pid, &outsb, &errsb, NULL));
714240116Smarcel    ATF_CHECK_EQ(read(atf_process_child_stdout(&child), &pid, sizeof(pid)),
715240116Smarcel                 sizeof(pid));
716240116Smarcel    printf("Expected PID: %d\n", (int)atf_process_child_pid(&child));
717240116Smarcel    printf("Actual PID: %d\n", (int)pid);
718240116Smarcel    ATF_CHECK_EQ(atf_process_child_pid(&child), pid);
719240116Smarcel
720240116Smarcel    RE(atf_process_child_wait(&child, &status));
721240116Smarcel    atf_process_status_fini(&status);
722240116Smarcel
723240116Smarcel    atf_process_stream_fini(&outsb);
724240116Smarcel    atf_process_stream_fini(&errsb);
725240116Smarcel}
726240116Smarcel
727240116Smarcelstatic
728240116Smarcelvoid
729240116Smarcelchild_loop(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
730240116Smarcel{
731240116Smarcel    for (;;)
732240116Smarcel        sleep(1);
733240116Smarcel}
734240116Smarcel
735240116Smarcelstatic
736240116Smarcelvoid
737240116Smarcelnop_signal(int sig ATF_DEFS_ATTRIBUTE_UNUSED)
738240116Smarcel{
739240116Smarcel}
740240116Smarcel
741240116Smarcelstatic
742240116Smarcelvoid
743240116Smarcelchild_spawn_loop_and_wait_eintr(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
744240116Smarcel{
745240116Smarcel    atf_process_child_t child;
746240116Smarcel    atf_process_status_t status;
747240116Smarcel    struct sigaction sighup, old_sighup;
748240116Smarcel
749240116Smarcel#define RE_ABORT(expr) \
750240116Smarcel    do { \
751240116Smarcel        atf_error_t _aux_err = expr; \
752240116Smarcel        if (atf_is_error(_aux_err)) { \
753240116Smarcel            atf_error_free(_aux_err); \
754240116Smarcel            abort(); \
755240116Smarcel        } \
756240116Smarcel    } while (0)
757240116Smarcel
758240116Smarcel    {
759240116Smarcel        atf_process_stream_t outsb, errsb;
760240116Smarcel
761240116Smarcel        RE_ABORT(atf_process_stream_init_capture(&outsb));
762240116Smarcel        RE_ABORT(atf_process_stream_init_inherit(&errsb));
763240116Smarcel        RE_ABORT(atf_process_fork(&child, child_loop, &outsb, &errsb, NULL));
764240116Smarcel        atf_process_stream_fini(&outsb);
765240116Smarcel        atf_process_stream_fini(&errsb);
766240116Smarcel    }
767240116Smarcel
768240116Smarcel    sighup.sa_handler = nop_signal;
769240116Smarcel    sigemptyset(&sighup.sa_mask);
770240116Smarcel    sighup.sa_flags = 0;
771240116Smarcel    if (sigaction(SIGHUP, &sighup, &old_sighup) == -1)
772240116Smarcel        abort();
773240116Smarcel
774240116Smarcel    printf("waiting\n");
775240116Smarcel    fflush(stdout);
776240116Smarcel
777240116Smarcel    fprintf(stderr, "Child entering wait(2)\n");
778240116Smarcel    atf_error_t err = atf_process_child_wait(&child, &status);
779240116Smarcel    fprintf(stderr, "Child's wait(2) terminated\n");
780240116Smarcel    if (!atf_is_error(err)) {
781240116Smarcel        fprintf(stderr, "wait completed successfully (not interrupted)\n");
782240116Smarcel        abort();
783240116Smarcel    }
784240116Smarcel    if (!atf_error_is(err, "libc")) {
785240116Smarcel        fprintf(stderr, "wait did not raise libc_error\n");
786240116Smarcel        abort();
787240116Smarcel    }
788240116Smarcel    if (atf_libc_error_code(err) != EINTR) {
789240116Smarcel        fprintf(stderr, "libc_error is not EINTR\n");
790240116Smarcel        abort();
791240116Smarcel    }
792240116Smarcel    atf_error_free(err);
793240116Smarcel
794240116Smarcel    sigaction(SIGHUP, &old_sighup, NULL);
795240116Smarcel
796240116Smarcel    fprintf(stderr, "Child is killing subchild\n");
797240116Smarcel    kill(atf_process_child_pid(&child), SIGTERM);
798240116Smarcel
799240116Smarcel    RE_ABORT(atf_process_child_wait(&child, &status));
800240116Smarcel    atf_process_status_fini(&status);
801240116Smarcel
802240116Smarcel#undef RE_ABORT
803240116Smarcel
804240116Smarcel    exit(EXIT_SUCCESS);
805240116Smarcel}
806240116Smarcel
807240116SmarcelATF_TC(child_wait_eintr);
808240116SmarcelATF_TC_HEAD(child_wait_eintr, tc)
809240116Smarcel{
810240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests the interruption of the wait "
811240116Smarcel                      "method by an external signal, and the return of "
812240116Smarcel                      "an EINTR error");
813240116Smarcel    atf_tc_set_md_var(tc, "timeout", "30");
814240116Smarcel}
815240116SmarcelATF_TC_BODY(child_wait_eintr, tc)
816240116Smarcel{
817240116Smarcel    atf_process_child_t child;
818240116Smarcel    atf_process_status_t status;
819240116Smarcel
820240116Smarcel    {
821240116Smarcel        atf_process_stream_t outsb, errsb;
822240116Smarcel
823240116Smarcel        RE(atf_process_stream_init_capture(&outsb));
824240116Smarcel        RE(atf_process_stream_init_inherit(&errsb));
825240116Smarcel        RE(atf_process_fork(&child, child_spawn_loop_and_wait_eintr,
826240116Smarcel                            &outsb, &errsb, NULL));
827240116Smarcel        atf_process_stream_fini(&outsb);
828240116Smarcel        atf_process_stream_fini(&errsb);
829240116Smarcel    }
830240116Smarcel
831240116Smarcel    {
832240116Smarcel        /* Wait until the child process performs the wait call.  This is
833240116Smarcel         * racy, because the message we get from it is sent *before*
834240116Smarcel         * doing the real system call... but I can't figure any other way
835240116Smarcel         * to do this. */
836240116Smarcel        char buf[16];
837240116Smarcel        printf("Waiting for child to issue wait(2)\n");
838240116Smarcel        ATF_REQUIRE(read(atf_process_child_stdout(&child), buf,
839240116Smarcel                         sizeof(buf)) > 0);
840240116Smarcel        sleep(1);
841240116Smarcel    }
842240116Smarcel
843240116Smarcel    printf("Interrupting child's wait(2) call\n");
844240116Smarcel    kill(atf_process_child_pid(&child), SIGHUP);
845240116Smarcel
846240116Smarcel    printf("Waiting for child's completion\n");
847240116Smarcel    RE(atf_process_child_wait(&child, &status));
848240116Smarcel    ATF_REQUIRE(atf_process_status_exited(&status));
849240116Smarcel    ATF_REQUIRE_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);
850240116Smarcel    atf_process_status_fini(&status);
851240116Smarcel}
852240116Smarcel
853240116Smarcel/* ---------------------------------------------------------------------
854240116Smarcel * Tests cases for the free functions.
855240116Smarcel * --------------------------------------------------------------------- */
856240116Smarcel
857240116Smarcelstatic
858240116Smarcelvoid
859240116Smarceldo_exec(const atf_tc_t *tc, const char *helper_name, atf_process_status_t *s,
860240116Smarcel        void (*prehook)(void))
861240116Smarcel{
862240116Smarcel    atf_fs_path_t process_helpers;
863240116Smarcel    const char *argv[3];
864240116Smarcel
865240116Smarcel    get_process_helpers_path(tc, true, &process_helpers);
866240116Smarcel
867240116Smarcel    argv[0] = atf_fs_path_cstring(&process_helpers);
868240116Smarcel    argv[1] = helper_name;
869240116Smarcel    argv[2] = NULL;
870240116Smarcel    printf("Executing %s %s\n", argv[0], argv[1]);
871240116Smarcel
872240116Smarcel    RE(atf_process_exec_array(s, &process_helpers, argv, NULL, NULL, prehook));
873240116Smarcel    atf_fs_path_fini(&process_helpers);
874240116Smarcel}
875240116Smarcel
876240116Smarcelstatic
877240116Smarcelvoid
878240116Smarcelcheck_line(int fd, const char *exp)
879240116Smarcel{
880258289Sjmmv    char *line = atf_utils_readline(fd);
881258289Sjmmv    ATF_CHECK(line != NULL);
882258289Sjmmv    ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp);
883258289Sjmmv    free(line);
884240116Smarcel}
885240116Smarcel
886240116SmarcelATF_TC(exec_failure);
887240116SmarcelATF_TC_HEAD(exec_failure, tc)
888240116Smarcel{
889240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests execing a command");
890240116Smarcel}
891240116SmarcelATF_TC_BODY(exec_failure, tc)
892240116Smarcel{
893240116Smarcel    atf_process_status_t status;
894240116Smarcel
895240116Smarcel    do_exec(tc, "exit-failure", &status, NULL);
896240116Smarcel    ATF_CHECK(atf_process_status_exited(&status));
897240116Smarcel    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_FAILURE);
898240116Smarcel    atf_process_status_fini(&status);
899240116Smarcel}
900240116Smarcel
901240116SmarcelATF_TC(exec_list);
902240116SmarcelATF_TC_HEAD(exec_list, tc)
903240116Smarcel{
904240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests execing a command");
905240116Smarcel}
906240116SmarcelATF_TC_BODY(exec_list, tc)
907240116Smarcel{
908240116Smarcel    atf_fs_path_t process_helpers;
909240116Smarcel    atf_list_t argv;
910240116Smarcel    atf_process_status_t status;
911240116Smarcel
912240116Smarcel    RE(atf_list_init(&argv));
913240116Smarcel
914240116Smarcel    get_process_helpers_path(tc, true, &process_helpers);
915240116Smarcel    atf_list_append(&argv, strdup(atf_fs_path_cstring(&process_helpers)), true);
916240116Smarcel    atf_list_append(&argv, strdup("echo"), true);
917240116Smarcel    atf_list_append(&argv, strdup("test-message"), true);
918240116Smarcel    {
919240116Smarcel        atf_fs_path_t outpath;
920240116Smarcel        atf_process_stream_t outsb;
921240116Smarcel
922240116Smarcel        RE(atf_fs_path_init_fmt(&outpath, "stdout"));
923240116Smarcel        RE(atf_process_stream_init_redirect_path(&outsb, &outpath));
924240116Smarcel        RE(atf_process_exec_list(&status, &process_helpers, &argv, &outsb,
925240116Smarcel                                 NULL, NULL));
926240116Smarcel        atf_process_stream_fini(&outsb);
927240116Smarcel        atf_fs_path_fini(&outpath);
928240116Smarcel    }
929240116Smarcel    atf_list_fini(&argv);
930240116Smarcel
931240116Smarcel    ATF_CHECK(atf_process_status_exited(&status));
932240116Smarcel    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);
933240116Smarcel
934240116Smarcel    {
935240116Smarcel        int fd = open("stdout", O_RDONLY);
936240116Smarcel        ATF_CHECK(fd != -1);
937240116Smarcel        check_line(fd, "test-message");
938240116Smarcel        close(fd);
939240116Smarcel    }
940240116Smarcel
941240116Smarcel    atf_process_status_fini(&status);
942240116Smarcel    atf_fs_path_fini(&process_helpers);
943240116Smarcel}
944240116Smarcel
945240116Smarcelstatic void
946240116Smarcelexit_early(void)
947240116Smarcel{
948240116Smarcel    exit(80);
949240116Smarcel}
950240116Smarcel
951240116SmarcelATF_TC(exec_prehook);
952240116SmarcelATF_TC_HEAD(exec_prehook, tc)
953240116Smarcel{
954240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests execing a command with a prehook");
955240116Smarcel}
956240116SmarcelATF_TC_BODY(exec_prehook, tc)
957240116Smarcel{
958240116Smarcel    atf_process_status_t status;
959240116Smarcel
960240116Smarcel    do_exec(tc, "exit-success", &status, exit_early);
961240116Smarcel    ATF_CHECK(atf_process_status_exited(&status));
962240116Smarcel    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), 80);
963240116Smarcel    atf_process_status_fini(&status);
964240116Smarcel}
965240116Smarcel
966240116SmarcelATF_TC(exec_success);
967240116SmarcelATF_TC_HEAD(exec_success, tc)
968240116Smarcel{
969240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests execing a command");
970240116Smarcel}
971240116SmarcelATF_TC_BODY(exec_success, tc)
972240116Smarcel{
973240116Smarcel    atf_process_status_t status;
974240116Smarcel
975240116Smarcel    do_exec(tc, "exit-success", &status, NULL);
976240116Smarcel    ATF_CHECK(atf_process_status_exited(&status));
977240116Smarcel    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);
978240116Smarcel    atf_process_status_fini(&status);
979240116Smarcel}
980240116Smarcel
981240116Smarcelstatic const int exit_v_null = 1;
982240116Smarcelstatic const int exit_v_notnull = 2;
983240116Smarcel
984240116Smarcelstatic
985240116Smarcelvoid
986240116Smarcelchild_cookie(void *v)
987240116Smarcel{
988240116Smarcel    if (v == NULL)
989240116Smarcel        exit(exit_v_null);
990240116Smarcel    else
991240116Smarcel        exit(exit_v_notnull);
992240116Smarcel
993240116Smarcel    UNREACHABLE;
994240116Smarcel}
995240116Smarcel
996240116SmarcelATF_TC(fork_cookie);
997240116SmarcelATF_TC_HEAD(fork_cookie, tc)
998240116Smarcel{
999240116Smarcel    atf_tc_set_md_var(tc, "descr", "Tests forking a child, with "
1000240116Smarcel                      "a null and non-null data cookie");
1001240116Smarcel}
1002240116SmarcelATF_TC_BODY(fork_cookie, tc)
1003240116Smarcel{
1004240116Smarcel    atf_process_stream_t outsb, errsb;
1005240116Smarcel
1006240116Smarcel    RE(atf_process_stream_init_inherit(&outsb));
1007240116Smarcel    RE(atf_process_stream_init_inherit(&errsb));
1008240116Smarcel
1009240116Smarcel    {
1010240116Smarcel        atf_process_child_t child;
1011240116Smarcel        atf_process_status_t status;
1012240116Smarcel
1013240116Smarcel        RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, NULL));
1014240116Smarcel        RE(atf_process_child_wait(&child, &status));
1015240116Smarcel
1016240116Smarcel        ATF_CHECK(atf_process_status_exited(&status));
1017240116Smarcel        ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_null);
1018240116Smarcel
1019240116Smarcel        atf_process_status_fini(&status);
1020240116Smarcel    }
1021240116Smarcel
1022240116Smarcel    {
1023240116Smarcel        atf_process_child_t child;
1024240116Smarcel        atf_process_status_t status;
1025240116Smarcel        int dummy_int;
1026240116Smarcel
1027240116Smarcel        RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, &dummy_int));
1028240116Smarcel        RE(atf_process_child_wait(&child, &status));
1029240116Smarcel
1030240116Smarcel        ATF_CHECK(atf_process_status_exited(&status));
1031240116Smarcel        ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_notnull);
1032240116Smarcel
1033240116Smarcel        atf_process_status_fini(&status);
1034240116Smarcel    }
1035240116Smarcel
1036240116Smarcel    atf_process_stream_fini(&errsb);
1037240116Smarcel    atf_process_stream_fini(&outsb);
1038240116Smarcel}
1039240116Smarcel
1040240116Smarcel#define TC_FORK_STREAMS(outlc, outuc, errlc, erruc) \
1041240116Smarcel    ATF_TC(fork_out_ ## outlc ## _err_ ## errlc); \
1042240116Smarcel    ATF_TC_HEAD(fork_out_ ## outlc ## _err_ ## errlc, tc) \
1043240116Smarcel    { \
1044240116Smarcel        atf_tc_set_md_var(tc, "descr", "Tests forking a child, with " \
1045240116Smarcel                          "stdout " #outlc " and stderr " #errlc); \
1046240116Smarcel    } \
1047240116Smarcel    ATF_TC_BODY(fork_out_ ## outlc ## _err_ ## errlc, tc) \
1048240116Smarcel    { \
1049240116Smarcel        struct outlc ## _stream out = outuc ## _STREAM(stdout_type); \
1050240116Smarcel        struct errlc ## _stream err = erruc ## _STREAM(stderr_type); \
1051240116Smarcel        do_fork(&out.m_base, &out, &err.m_base, &err); \
1052240116Smarcel    }
1053240116Smarcel
1054240116SmarcelTC_FORK_STREAMS(capture, CAPTURE, capture, CAPTURE);
1055240116SmarcelTC_FORK_STREAMS(capture, CAPTURE, connect, CONNECT);
1056240116SmarcelTC_FORK_STREAMS(capture, CAPTURE, default, DEFAULT);
1057240116SmarcelTC_FORK_STREAMS(capture, CAPTURE, inherit, INHERIT);
1058240116SmarcelTC_FORK_STREAMS(capture, CAPTURE, redirect_fd, REDIRECT_FD);
1059240116SmarcelTC_FORK_STREAMS(capture, CAPTURE, redirect_path, REDIRECT_PATH);
1060240116SmarcelTC_FORK_STREAMS(connect, CONNECT, capture, CAPTURE);
1061240116SmarcelTC_FORK_STREAMS(connect, CONNECT, connect, CONNECT);
1062240116SmarcelTC_FORK_STREAMS(connect, CONNECT, default, DEFAULT);
1063240116SmarcelTC_FORK_STREAMS(connect, CONNECT, inherit, INHERIT);
1064240116SmarcelTC_FORK_STREAMS(connect, CONNECT, redirect_fd, REDIRECT_FD);
1065240116SmarcelTC_FORK_STREAMS(connect, CONNECT, redirect_path, REDIRECT_PATH);
1066240116SmarcelTC_FORK_STREAMS(default, DEFAULT, capture, CAPTURE);
1067240116SmarcelTC_FORK_STREAMS(default, DEFAULT, connect, CONNECT);
1068240116SmarcelTC_FORK_STREAMS(default, DEFAULT, default, DEFAULT);
1069240116SmarcelTC_FORK_STREAMS(default, DEFAULT, inherit, INHERIT);
1070240116SmarcelTC_FORK_STREAMS(default, DEFAULT, redirect_fd, REDIRECT_FD);
1071240116SmarcelTC_FORK_STREAMS(default, DEFAULT, redirect_path, REDIRECT_PATH);
1072240116SmarcelTC_FORK_STREAMS(inherit, INHERIT, capture, CAPTURE);
1073240116SmarcelTC_FORK_STREAMS(inherit, INHERIT, connect, CONNECT);
1074240116SmarcelTC_FORK_STREAMS(inherit, INHERIT, default, DEFAULT);
1075240116SmarcelTC_FORK_STREAMS(inherit, INHERIT, inherit, INHERIT);
1076240116SmarcelTC_FORK_STREAMS(inherit, INHERIT, redirect_fd, REDIRECT_FD);
1077240116SmarcelTC_FORK_STREAMS(inherit, INHERIT, redirect_path, REDIRECT_PATH);
1078240116SmarcelTC_FORK_STREAMS(redirect_fd, REDIRECT_FD, capture, CAPTURE);
1079240116SmarcelTC_FORK_STREAMS(redirect_fd, REDIRECT_FD, connect, CONNECT);
1080240116SmarcelTC_FORK_STREAMS(redirect_fd, REDIRECT_FD, default, DEFAULT);
1081240116SmarcelTC_FORK_STREAMS(redirect_fd, REDIRECT_FD, inherit, INHERIT);
1082240116SmarcelTC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_fd, REDIRECT_FD);
1083240116SmarcelTC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_path, REDIRECT_PATH);
1084240116SmarcelTC_FORK_STREAMS(redirect_path, REDIRECT_PATH, capture, CAPTURE);
1085240116SmarcelTC_FORK_STREAMS(redirect_path, REDIRECT_PATH, connect, CONNECT);
1086240116SmarcelTC_FORK_STREAMS(redirect_path, REDIRECT_PATH, default, DEFAULT);
1087240116SmarcelTC_FORK_STREAMS(redirect_path, REDIRECT_PATH, inherit, INHERIT);
1088240116SmarcelTC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_fd, REDIRECT_FD);
1089240116SmarcelTC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_path, REDIRECT_PATH);
1090240116Smarcel
1091240116Smarcel#undef TC_FORK_STREAMS
1092240116Smarcel
1093240116Smarcel/* ---------------------------------------------------------------------
1094240116Smarcel * Main.
1095240116Smarcel * --------------------------------------------------------------------- */
1096240116Smarcel
1097240116SmarcelATF_TP_ADD_TCS(tp)
1098240116Smarcel{
1099240116Smarcel    /* Add the tests for the "stream" type. */
1100240116Smarcel    ATF_TP_ADD_TC(tp, stream_init_capture);
1101240116Smarcel    ATF_TP_ADD_TC(tp, stream_init_connect);
1102240116Smarcel    ATF_TP_ADD_TC(tp, stream_init_inherit);
1103240116Smarcel    ATF_TP_ADD_TC(tp, stream_init_redirect_fd);
1104240116Smarcel    ATF_TP_ADD_TC(tp, stream_init_redirect_path);
1105240116Smarcel
1106240116Smarcel    /* Add the tests for the "status" type. */
1107240116Smarcel    ATF_TP_ADD_TC(tp, status_exited);
1108240116Smarcel    ATF_TP_ADD_TC(tp, status_signaled);
1109240116Smarcel    ATF_TP_ADD_TC(tp, status_coredump);
1110240116Smarcel
1111240116Smarcel    /* Add the tests for the "child" type. */
1112240116Smarcel    ATF_TP_ADD_TC(tp, child_pid);
1113240116Smarcel    ATF_TP_ADD_TC(tp, child_wait_eintr);
1114240116Smarcel
1115240116Smarcel    /* Add the tests for the free functions. */
1116240116Smarcel    ATF_TP_ADD_TC(tp, exec_failure);
1117240116Smarcel    ATF_TP_ADD_TC(tp, exec_list);
1118240116Smarcel    ATF_TP_ADD_TC(tp, exec_prehook);
1119240116Smarcel    ATF_TP_ADD_TC(tp, exec_success);
1120240116Smarcel    ATF_TP_ADD_TC(tp, fork_cookie);
1121240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_capture_err_capture);
1122240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_capture_err_connect);
1123240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_capture_err_default);
1124240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_capture_err_inherit);
1125240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_fd);
1126240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_path);
1127240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_connect_err_capture);
1128240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_connect_err_connect);
1129240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_connect_err_default);
1130240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_connect_err_inherit);
1131240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_fd);
1132240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_path);
1133240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_default_err_capture);
1134240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_default_err_connect);
1135240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_default_err_default);
1136240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_default_err_inherit);
1137240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_fd);
1138240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_path);
1139240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_inherit_err_capture);
1140240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_inherit_err_connect);
1141240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_inherit_err_default);
1142240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_inherit_err_inherit);
1143240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_fd);
1144240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_path);
1145240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_capture);
1146240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_connect);
1147240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_default);
1148240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_inherit);
1149240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_fd);
1150240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_path);
1151240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_capture);
1152240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_connect);
1153240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_default);
1154240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_inherit);
1155240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_fd);
1156240116Smarcel    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_path);
1157240116Smarcel
1158240116Smarcel    return atf_no_error();
1159240116Smarcel}
1160