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