process_test.c revision 275988
1/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25
26#include "atf-c/detail/process.h"
27
28#include <sys/types.h>
29#include <sys/time.h>
30#include <sys/resource.h>
31#include <sys/wait.h>
32
33#include <errno.h>
34#include <fcntl.h>
35#include <signal.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#include <atf-c.h>
42
43#include "atf-c/defs.h"
44#include "atf-c/detail/sanity.h"
45#include "atf-c/detail/test_helpers.h"
46
47atf_error_t atf_process_status_init(atf_process_status_t *, int);
48
49/* ---------------------------------------------------------------------
50 * Auxiliary functions for testing of 'atf_process_fork'.
51 * --------------------------------------------------------------------- */
52
53/*
54 * Testing of atf_process_fork is quite messy.  We want to be able to test
55 * all the possible combinations of stdout and stderr behavior to ensure
56 * that the streams are manipulated correctly.
57 *
58 * To do this, the do_fork function is a wrapper for atf_process_fork that
59 * issues stream-specific hooks before fork, while the child is running and
60 * after the child terminates.  We then provide test cases that just call
61 * do_fork with different hooks.
62 *
63 * The hooks are described by base_stream, and we then have one *_stream
64 * type for ever possible stream behavior.
65 */
66
67enum out_type { stdout_type, stderr_type };
68
69struct base_stream {
70    void (*init)(void *);
71    void (*process)(void *, atf_process_child_t *);
72    void (*fini)(void *);
73
74    /* m_sb is initialized by subclasses that need it, but all consumers
75     * must use m_sb_ptr, which may or may not point to m_sb.  This allows
76     * us to test the interface with a NULL value, which triggers a
77     * default behavior. */
78    atf_process_stream_t m_sb;
79    atf_process_stream_t *m_sb_ptr;
80    enum out_type m_type;
81};
82#define BASE_STREAM(ihook, phook, fhook, type) \
83    { .init = ihook, \
84      .process = phook, \
85      .fini = fhook, \
86      .m_type = type }
87
88static
89void
90check_file(const enum out_type type)
91{
92    switch (type) {
93    case stdout_type:
94        ATF_CHECK(atf_utils_grep_file("stdout: msg", "stdout"));
95        ATF_CHECK(!atf_utils_grep_file("stderr: msg", "stdout"));
96        break;
97    case stderr_type:
98        ATF_CHECK(atf_utils_grep_file("stderr: msg", "stderr"));
99        ATF_CHECK(!atf_utils_grep_file("stdout: msg", "stderr"));
100        break;
101    default:
102        UNREACHABLE;
103    }
104}
105
106struct capture_stream {
107    struct base_stream m_base;
108
109    char *m_msg;
110};
111#define CAPTURE_STREAM(type) \
112    { .m_base = BASE_STREAM(capture_stream_init, \
113                            capture_stream_process, \
114                            capture_stream_fini, \
115                            type) }
116
117static
118void
119capture_stream_init(void *v)
120{
121    struct capture_stream *s = v;
122
123    s->m_base.m_sb_ptr = &s->m_base.m_sb;
124    RE(atf_process_stream_init_capture(&s->m_base.m_sb));
125    s->m_msg = NULL;
126}
127
128static
129void
130capture_stream_process(void *v, atf_process_child_t *c)
131{
132    struct capture_stream *s = v;
133
134    switch (s->m_base.m_type) {
135    case stdout_type:
136        s->m_msg = atf_utils_readline(atf_process_child_stdout(c));
137        break;
138    case stderr_type:
139        s->m_msg = atf_utils_readline(atf_process_child_stderr(c));
140        break;
141    default:
142        UNREACHABLE;
143    }
144}
145
146static
147void
148capture_stream_fini(void *v)
149{
150    struct capture_stream *s = v;
151
152    switch (s->m_base.m_type) {
153    case stdout_type:
154        ATF_CHECK(atf_utils_grep_string("stdout: msg", s->m_msg));
155        ATF_CHECK(!atf_utils_grep_string("stderr: msg", s->m_msg));
156        break;
157    case stderr_type:
158        ATF_CHECK(!atf_utils_grep_string("stdout: msg", s->m_msg));
159        ATF_CHECK(atf_utils_grep_string("stderr: msg", s->m_msg));
160        break;
161    default:
162        UNREACHABLE;
163    }
164
165    free(s->m_msg);
166    atf_process_stream_fini(&s->m_base.m_sb);
167}
168
169struct connect_stream {
170    struct base_stream m_base;
171
172    int m_fd;
173};
174#define CONNECT_STREAM(type) \
175    { .m_base = BASE_STREAM(connect_stream_init, \
176                            NULL, \
177                            connect_stream_fini, \
178                            type) }
179
180static
181void
182connect_stream_init(void *v)
183{
184    struct connect_stream *s = v;
185    int src_fd;
186
187    switch (s->m_base.m_type) {
188    case stdout_type:
189        src_fd = STDOUT_FILENO;
190        s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644);
191        break;
192    case stderr_type:
193        src_fd = STDERR_FILENO;
194        s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644);
195        break;
196    default:
197        UNREACHABLE;
198        src_fd = -1;
199    }
200    ATF_REQUIRE(s->m_fd != -1);
201
202    s->m_base.m_sb_ptr = &s->m_base.m_sb;
203    RE(atf_process_stream_init_connect(&s->m_base.m_sb, src_fd, s->m_fd));
204}
205
206static
207void
208connect_stream_fini(void *v)
209{
210    struct connect_stream *s = v;
211
212    ATF_REQUIRE(close(s->m_fd) != -1);
213
214    atf_process_stream_fini(&s->m_base.m_sb);
215
216    check_file(s->m_base.m_type);
217}
218
219struct inherit_stream {
220    struct base_stream m_base;
221    int m_fd;
222
223    int m_old_fd;
224};
225#define INHERIT_STREAM(type) \
226    { .m_base = BASE_STREAM(inherit_stream_init, \
227                            NULL, \
228                            inherit_stream_fini, \
229                            type) }
230
231static
232void
233inherit_stream_init(void *v)
234{
235    struct inherit_stream *s = v;
236    const char *name;
237
238    s->m_base.m_sb_ptr = &s->m_base.m_sb;
239    RE(atf_process_stream_init_inherit(&s->m_base.m_sb));
240
241    switch (s->m_base.m_type) {
242    case stdout_type:
243        s->m_fd = STDOUT_FILENO;
244        name = "stdout";
245        break;
246    case stderr_type:
247        s->m_fd = STDERR_FILENO;
248        name = "stderr";
249        break;
250    default:
251        UNREACHABLE;
252        name = NULL;
253    }
254
255    s->m_old_fd = dup(s->m_fd);
256    ATF_REQUIRE(s->m_old_fd != -1);
257    ATF_REQUIRE(close(s->m_fd) != -1);
258    ATF_REQUIRE_EQ(open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644),
259                   s->m_fd);
260}
261
262static
263void
264inherit_stream_fini(void *v)
265{
266    struct inherit_stream *s = v;
267
268    ATF_REQUIRE(dup2(s->m_old_fd, s->m_fd) != -1);
269    ATF_REQUIRE(close(s->m_old_fd) != -1);
270
271    atf_process_stream_fini(&s->m_base.m_sb);
272
273    check_file(s->m_base.m_type);
274}
275
276#define default_stream inherit_stream
277#define DEFAULT_STREAM(type) \
278    { .m_base = BASE_STREAM(default_stream_init, \
279                            NULL, \
280                            default_stream_fini, \
281                            type) }
282
283static
284void
285default_stream_init(void *v)
286{
287    struct inherit_stream *s = v;
288
289    inherit_stream_init(v);
290    s->m_base.m_sb_ptr = NULL;
291}
292
293static
294void
295default_stream_fini(void *v)
296{
297    inherit_stream_fini(v);
298}
299
300struct redirect_fd_stream {
301    struct base_stream m_base;
302
303    int m_fd;
304};
305#define REDIRECT_FD_STREAM(type) \
306    { .m_base = BASE_STREAM(redirect_fd_stream_init, \
307                            NULL, \
308                            redirect_fd_stream_fini, \
309                            type) }
310
311static
312void
313redirect_fd_stream_init(void *v)
314{
315    struct redirect_fd_stream *s = v;
316
317    switch (s->m_base.m_type) {
318    case stdout_type:
319        s->m_fd = open("stdout", O_WRONLY | O_CREAT | O_TRUNC, 0644);
320        break;
321    case stderr_type:
322        s->m_fd = open("stderr", O_WRONLY | O_CREAT | O_TRUNC, 0644);
323        break;
324    default:
325        UNREACHABLE;
326    }
327    ATF_REQUIRE(s->m_fd != -1);
328
329    s->m_base.m_sb_ptr = &s->m_base.m_sb;
330    RE(atf_process_stream_init_redirect_fd(&s->m_base.m_sb, s->m_fd));
331}
332
333static
334void
335redirect_fd_stream_fini(void *v)
336{
337    struct redirect_fd_stream *s = v;
338
339    ATF_REQUIRE(close(s->m_fd) != -1);
340
341    atf_process_stream_fini(&s->m_base.m_sb);
342
343    check_file(s->m_base.m_type);
344}
345
346struct redirect_path_stream {
347    struct base_stream m_base;
348
349    atf_fs_path_t m_path;
350};
351#define REDIRECT_PATH_STREAM(type) \
352    { .m_base = BASE_STREAM(redirect_path_stream_init, \
353                            NULL, \
354                            redirect_path_stream_fini, \
355                            type) }
356
357static
358void
359redirect_path_stream_init(void *v)
360{
361    struct redirect_path_stream *s = v;
362
363    switch (s->m_base.m_type) {
364    case stdout_type:
365        RE(atf_fs_path_init_fmt(&s->m_path, "stdout"));
366        break;
367    case stderr_type:
368        RE(atf_fs_path_init_fmt(&s->m_path, "stderr"));
369        break;
370    default:
371        UNREACHABLE;
372    }
373
374    s->m_base.m_sb_ptr = &s->m_base.m_sb;
375    RE(atf_process_stream_init_redirect_path(&s->m_base.m_sb, &s->m_path));
376}
377
378static
379void
380redirect_path_stream_fini(void *v)
381{
382    struct redirect_path_stream *s = v;
383
384    atf_process_stream_fini(&s->m_base.m_sb);
385
386    atf_fs_path_fini(&s->m_path);
387
388    check_file(s->m_base.m_type);
389}
390
391static void child_print(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
392
393struct child_print_data {
394    const char *m_msg;
395};
396
397static
398void
399child_print(void *v)
400{
401    struct child_print_data *cpd = v;
402
403    fprintf(stdout, "stdout: %s\n", cpd->m_msg);
404    fprintf(stderr, "stderr: %s\n", cpd->m_msg);
405
406    exit(EXIT_SUCCESS);
407}
408
409static
410void
411do_fork(const struct base_stream *outfs, void *out,
412        const struct base_stream *errfs, void *err)
413{
414    atf_process_child_t child;
415    atf_process_status_t status;
416    struct child_print_data cpd = { "msg" };
417
418    outfs->init(out);
419    errfs->init(err);
420
421    RE(atf_process_fork(&child, child_print, outfs->m_sb_ptr,
422                        errfs->m_sb_ptr, &cpd));
423    if (outfs->process != NULL)
424        outfs->process(out, &child);
425    if (errfs->process != NULL)
426        errfs->process(err, &child);
427    RE(atf_process_child_wait(&child, &status));
428
429    outfs->fini(out);
430    errfs->fini(err);
431
432    atf_process_status_fini(&status);
433}
434
435/* ---------------------------------------------------------------------
436 * Test cases for the "stream" type.
437 * --------------------------------------------------------------------- */
438
439ATF_TC(stream_init_capture);
440ATF_TC_HEAD(stream_init_capture, tc)
441{
442    atf_tc_set_md_var(tc, "descr", "Tests the "
443                      "atf_process_stream_init_capture function");
444}
445ATF_TC_BODY(stream_init_capture, tc)
446{
447    atf_process_stream_t sb;
448
449    RE(atf_process_stream_init_capture(&sb));
450
451    ATF_CHECK_EQ(atf_process_stream_type(&sb),
452                 atf_process_stream_type_capture);
453
454    atf_process_stream_fini(&sb);
455}
456
457ATF_TC(stream_init_connect);
458ATF_TC_HEAD(stream_init_connect, tc)
459{
460    atf_tc_set_md_var(tc, "descr", "Tests the "
461                      "atf_process_stream_init_connect function");
462}
463ATF_TC_BODY(stream_init_connect, tc)
464{
465    atf_process_stream_t sb;
466
467    RE(atf_process_stream_init_connect(&sb, 1, 2));
468
469    ATF_CHECK_EQ(atf_process_stream_type(&sb),
470                 atf_process_stream_type_connect);
471
472    atf_process_stream_fini(&sb);
473}
474
475ATF_TC(stream_init_inherit);
476ATF_TC_HEAD(stream_init_inherit, tc)
477{
478    atf_tc_set_md_var(tc, "descr", "Tests the "
479                      "atf_process_stream_init_inherit function");
480}
481ATF_TC_BODY(stream_init_inherit, tc)
482{
483    atf_process_stream_t sb;
484
485    RE(atf_process_stream_init_inherit(&sb));
486
487    ATF_CHECK_EQ(atf_process_stream_type(&sb),
488                 atf_process_stream_type_inherit);
489
490    atf_process_stream_fini(&sb);
491}
492
493ATF_TC(stream_init_redirect_fd);
494ATF_TC_HEAD(stream_init_redirect_fd, tc)
495{
496    atf_tc_set_md_var(tc, "descr", "Tests the "
497                      "atf_process_stream_init_redirect_fd function");
498}
499ATF_TC_BODY(stream_init_redirect_fd, tc)
500{
501    atf_process_stream_t sb;
502
503    RE(atf_process_stream_init_redirect_fd(&sb, 1));
504
505    ATF_CHECK_EQ(atf_process_stream_type(&sb),
506                 atf_process_stream_type_redirect_fd);
507
508    atf_process_stream_fini(&sb);
509}
510
511ATF_TC(stream_init_redirect_path);
512ATF_TC_HEAD(stream_init_redirect_path, tc)
513{
514    atf_tc_set_md_var(tc, "descr", "Tests the "
515                      "atf_process_stream_init_redirect_path function");
516}
517ATF_TC_BODY(stream_init_redirect_path, tc)
518{
519    atf_process_stream_t sb;
520    atf_fs_path_t path;
521
522    RE(atf_fs_path_init_fmt(&path, "foo"));
523    RE(atf_process_stream_init_redirect_path(&sb, &path));
524
525    ATF_CHECK_EQ(atf_process_stream_type(&sb),
526                 atf_process_stream_type_redirect_path);
527
528    atf_process_stream_fini(&sb);
529    atf_fs_path_fini(&path);
530}
531
532/* ---------------------------------------------------------------------
533 * Test cases for the "status" type.
534 * --------------------------------------------------------------------- */
535
536static void child_exit_success(void) ATF_DEFS_ATTRIBUTE_NORETURN;
537static void child_exit_failure(void) ATF_DEFS_ATTRIBUTE_NORETURN;
538static void child_sigkill(void) ATF_DEFS_ATTRIBUTE_NORETURN;
539static void child_sigquit(void) ATF_DEFS_ATTRIBUTE_NORETURN;
540static void child_sigterm(void) ATF_DEFS_ATTRIBUTE_NORETURN;
541
542void
543child_exit_success(void)
544{
545    exit(EXIT_SUCCESS);
546}
547
548void
549child_exit_failure(void)
550{
551    exit(EXIT_FAILURE);
552}
553
554void
555child_sigkill(void)
556{
557    kill(getpid(), SIGKILL);
558    abort();
559}
560
561void
562child_sigquit(void)
563{
564    kill(getpid(), SIGQUIT);
565    abort();
566}
567
568void
569child_sigterm(void)
570{
571    kill(getpid(), SIGTERM);
572    abort();
573}
574
575static
576int
577fork_and_wait_child(void (*child_func)(void))
578{
579    pid_t pid;
580    int status;
581
582    pid = fork();
583    ATF_REQUIRE(pid != -1);
584    if (pid == 0) {
585        status = 0; /* Silence compiler warnings */
586        child_func();
587        UNREACHABLE;
588    } else {
589        ATF_REQUIRE(waitpid(pid, &status, 0) != 0);
590    }
591
592    return status;
593}
594
595ATF_TC(status_exited);
596ATF_TC_HEAD(status_exited, tc)
597{
598    atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
599                      "that exit cleanly");
600}
601ATF_TC_BODY(status_exited, tc)
602{
603    {
604        const int rawstatus = fork_and_wait_child(child_exit_success);
605        atf_process_status_t s;
606        RE(atf_process_status_init(&s, rawstatus));
607        ATF_CHECK(atf_process_status_exited(&s));
608        ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_SUCCESS);
609        ATF_CHECK(!atf_process_status_signaled(&s));
610        atf_process_status_fini(&s);
611    }
612
613    {
614        const int rawstatus = fork_and_wait_child(child_exit_failure);
615        atf_process_status_t s;
616        RE(atf_process_status_init(&s, rawstatus));
617        ATF_CHECK(atf_process_status_exited(&s));
618        ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_FAILURE);
619        ATF_CHECK(!atf_process_status_signaled(&s));
620        atf_process_status_fini(&s);
621    }
622}
623
624ATF_TC(status_signaled);
625ATF_TC_HEAD(status_signaled, tc)
626{
627    atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
628                      "that end due to a signal");
629}
630ATF_TC_BODY(status_signaled, tc)
631{
632    {
633        const int rawstatus = fork_and_wait_child(child_sigkill);
634        atf_process_status_t s;
635        RE(atf_process_status_init(&s, rawstatus));
636        ATF_CHECK(!atf_process_status_exited(&s));
637        ATF_CHECK(atf_process_status_signaled(&s));
638        ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGKILL);
639        ATF_CHECK(!atf_process_status_coredump(&s));
640        atf_process_status_fini(&s);
641    }
642
643    {
644        const int rawstatus = fork_and_wait_child(child_sigterm);
645        atf_process_status_t s;
646        RE(atf_process_status_init(&s, rawstatus));
647        ATF_CHECK(!atf_process_status_exited(&s));
648        ATF_CHECK(atf_process_status_signaled(&s));
649        ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGTERM);
650        ATF_CHECK(!atf_process_status_coredump(&s));
651        atf_process_status_fini(&s);
652    }
653}
654
655ATF_TC(status_coredump);
656ATF_TC_HEAD(status_coredump, tc)
657{
658    atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
659                      "that crash");
660}
661ATF_TC_BODY(status_coredump, tc)
662{
663    struct rlimit rl;
664    rl.rlim_cur = RLIM_INFINITY;
665    rl.rlim_max = RLIM_INFINITY;
666    if (setrlimit(RLIMIT_CORE, &rl) == -1)
667        atf_tc_skip("Cannot unlimit the core file size; check limits "
668                    "manually");
669
670    const int rawstatus = fork_and_wait_child(child_sigquit);
671    atf_process_status_t s;
672    RE(atf_process_status_init(&s, rawstatus));
673    ATF_CHECK(!atf_process_status_exited(&s));
674    ATF_CHECK(atf_process_status_signaled(&s));
675    ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGQUIT);
676    ATF_CHECK(atf_process_status_coredump(&s));
677    atf_process_status_fini(&s);
678}
679
680/* ---------------------------------------------------------------------
681 * Test cases for the "child" type.
682 * --------------------------------------------------------------------- */
683
684static void child_report_pid(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
685
686static
687void
688child_report_pid(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
689{
690    const pid_t pid = getpid();
691    if (write(STDOUT_FILENO, &pid, sizeof(pid)) != sizeof(pid))
692        abort();
693    fprintf(stderr, "Reporting %d to parent\n", (int)getpid());
694    exit(EXIT_SUCCESS);
695}
696
697ATF_TC(child_pid);
698ATF_TC_HEAD(child_pid, tc)
699{
700    atf_tc_set_md_var(tc, "descr", "Tests the correctness of the pid "
701                      "stored in the child type");
702}
703ATF_TC_BODY(child_pid, tc)
704{
705    atf_process_stream_t outsb, errsb;
706    atf_process_child_t child;
707    atf_process_status_t status;
708    pid_t pid;
709
710    RE(atf_process_stream_init_capture(&outsb));
711    RE(atf_process_stream_init_inherit(&errsb));
712
713    RE(atf_process_fork(&child, child_report_pid, &outsb, &errsb, NULL));
714    ATF_CHECK_EQ(read(atf_process_child_stdout(&child), &pid, sizeof(pid)),
715                 sizeof(pid));
716    printf("Expected PID: %d\n", (int)atf_process_child_pid(&child));
717    printf("Actual PID: %d\n", (int)pid);
718    ATF_CHECK_EQ(atf_process_child_pid(&child), pid);
719
720    RE(atf_process_child_wait(&child, &status));
721    atf_process_status_fini(&status);
722
723    atf_process_stream_fini(&outsb);
724    atf_process_stream_fini(&errsb);
725}
726
727static
728void
729child_loop(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
730{
731    for (;;)
732        sleep(1);
733}
734
735static
736void
737nop_signal(int sig ATF_DEFS_ATTRIBUTE_UNUSED)
738{
739}
740
741static
742void
743child_spawn_loop_and_wait_eintr(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
744{
745    atf_process_child_t child;
746    atf_process_status_t status;
747    struct sigaction sighup, old_sighup;
748
749#define RE_ABORT(expr) \
750    do { \
751        atf_error_t _aux_err = expr; \
752        if (atf_is_error(_aux_err)) { \
753            atf_error_free(_aux_err); \
754            abort(); \
755        } \
756    } while (0)
757
758    {
759        atf_process_stream_t outsb, errsb;
760
761        RE_ABORT(atf_process_stream_init_capture(&outsb));
762        RE_ABORT(atf_process_stream_init_inherit(&errsb));
763        RE_ABORT(atf_process_fork(&child, child_loop, &outsb, &errsb, NULL));
764        atf_process_stream_fini(&outsb);
765        atf_process_stream_fini(&errsb);
766    }
767
768    sighup.sa_handler = nop_signal;
769    sigemptyset(&sighup.sa_mask);
770    sighup.sa_flags = 0;
771    if (sigaction(SIGHUP, &sighup, &old_sighup) == -1)
772        abort();
773
774    printf("waiting\n");
775    fflush(stdout);
776
777    fprintf(stderr, "Child entering wait(2)\n");
778    atf_error_t err = atf_process_child_wait(&child, &status);
779    fprintf(stderr, "Child's wait(2) terminated\n");
780    if (!atf_is_error(err)) {
781        fprintf(stderr, "wait completed successfully (not interrupted)\n");
782        abort();
783    }
784    if (!atf_error_is(err, "libc")) {
785        fprintf(stderr, "wait did not raise libc_error\n");
786        abort();
787    }
788    if (atf_libc_error_code(err) != EINTR) {
789        fprintf(stderr, "libc_error is not EINTR\n");
790        abort();
791    }
792    atf_error_free(err);
793
794    sigaction(SIGHUP, &old_sighup, NULL);
795
796    fprintf(stderr, "Child is killing subchild\n");
797    kill(atf_process_child_pid(&child), SIGTERM);
798
799    RE_ABORT(atf_process_child_wait(&child, &status));
800    atf_process_status_fini(&status);
801
802#undef RE_ABORT
803
804    exit(EXIT_SUCCESS);
805}
806
807ATF_TC(child_wait_eintr);
808ATF_TC_HEAD(child_wait_eintr, tc)
809{
810    atf_tc_set_md_var(tc, "descr", "Tests the interruption of the wait "
811                      "method by an external signal, and the return of "
812                      "an EINTR error");
813    atf_tc_set_md_var(tc, "timeout", "30");
814}
815ATF_TC_BODY(child_wait_eintr, tc)
816{
817    atf_process_child_t child;
818    atf_process_status_t status;
819
820    {
821        atf_process_stream_t outsb, errsb;
822
823        RE(atf_process_stream_init_capture(&outsb));
824        RE(atf_process_stream_init_inherit(&errsb));
825        RE(atf_process_fork(&child, child_spawn_loop_and_wait_eintr,
826                            &outsb, &errsb, NULL));
827        atf_process_stream_fini(&outsb);
828        atf_process_stream_fini(&errsb);
829    }
830
831    {
832        /* Wait until the child process performs the wait call.  This is
833         * racy, because the message we get from it is sent *before*
834         * doing the real system call... but I can't figure any other way
835         * to do this. */
836        char buf[16];
837        printf("Waiting for child to issue wait(2)\n");
838        ATF_REQUIRE(read(atf_process_child_stdout(&child), buf,
839                         sizeof(buf)) > 0);
840        sleep(1);
841    }
842
843    printf("Interrupting child's wait(2) call\n");
844    kill(atf_process_child_pid(&child), SIGHUP);
845
846    printf("Waiting for child's completion\n");
847    RE(atf_process_child_wait(&child, &status));
848    ATF_REQUIRE(atf_process_status_exited(&status));
849    ATF_REQUIRE_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);
850    atf_process_status_fini(&status);
851}
852
853/* ---------------------------------------------------------------------
854 * Tests cases for the free functions.
855 * --------------------------------------------------------------------- */
856
857static
858void
859do_exec(const atf_tc_t *tc, const char *helper_name, atf_process_status_t *s,
860        void (*prehook)(void))
861{
862    atf_fs_path_t process_helpers;
863    const char *argv[3];
864
865    get_process_helpers_path(tc, true, &process_helpers);
866
867    argv[0] = atf_fs_path_cstring(&process_helpers);
868    argv[1] = helper_name;
869    argv[2] = NULL;
870    printf("Executing %s %s\n", argv[0], argv[1]);
871
872    RE(atf_process_exec_array(s, &process_helpers, argv, NULL, NULL, prehook));
873    atf_fs_path_fini(&process_helpers);
874}
875
876static
877void
878check_line(int fd, const char *exp)
879{
880    char *line = atf_utils_readline(fd);
881    ATF_CHECK(line != NULL);
882    ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp);
883    free(line);
884}
885
886ATF_TC(exec_failure);
887ATF_TC_HEAD(exec_failure, tc)
888{
889    atf_tc_set_md_var(tc, "descr", "Tests execing a command");
890}
891ATF_TC_BODY(exec_failure, tc)
892{
893    atf_process_status_t status;
894
895    do_exec(tc, "exit-failure", &status, NULL);
896    ATF_CHECK(atf_process_status_exited(&status));
897    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_FAILURE);
898    atf_process_status_fini(&status);
899}
900
901ATF_TC(exec_list);
902ATF_TC_HEAD(exec_list, tc)
903{
904    atf_tc_set_md_var(tc, "descr", "Tests execing a command");
905}
906ATF_TC_BODY(exec_list, tc)
907{
908    atf_fs_path_t process_helpers;
909    atf_list_t argv;
910    atf_process_status_t status;
911
912    RE(atf_list_init(&argv));
913
914    get_process_helpers_path(tc, true, &process_helpers);
915    atf_list_append(&argv, strdup(atf_fs_path_cstring(&process_helpers)), true);
916    atf_list_append(&argv, strdup("echo"), true);
917    atf_list_append(&argv, strdup("test-message"), true);
918    {
919        atf_fs_path_t outpath;
920        atf_process_stream_t outsb;
921
922        RE(atf_fs_path_init_fmt(&outpath, "stdout"));
923        RE(atf_process_stream_init_redirect_path(&outsb, &outpath));
924        RE(atf_process_exec_list(&status, &process_helpers, &argv, &outsb,
925                                 NULL, NULL));
926        atf_process_stream_fini(&outsb);
927        atf_fs_path_fini(&outpath);
928    }
929    atf_list_fini(&argv);
930
931    ATF_CHECK(atf_process_status_exited(&status));
932    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);
933
934    {
935        int fd = open("stdout", O_RDONLY);
936        ATF_CHECK(fd != -1);
937        check_line(fd, "test-message");
938        close(fd);
939    }
940
941    atf_process_status_fini(&status);
942    atf_fs_path_fini(&process_helpers);
943}
944
945static void
946exit_early(void)
947{
948    exit(80);
949}
950
951ATF_TC(exec_prehook);
952ATF_TC_HEAD(exec_prehook, tc)
953{
954    atf_tc_set_md_var(tc, "descr", "Tests execing a command with a prehook");
955}
956ATF_TC_BODY(exec_prehook, tc)
957{
958    atf_process_status_t status;
959
960    do_exec(tc, "exit-success", &status, exit_early);
961    ATF_CHECK(atf_process_status_exited(&status));
962    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), 80);
963    atf_process_status_fini(&status);
964}
965
966ATF_TC(exec_success);
967ATF_TC_HEAD(exec_success, tc)
968{
969    atf_tc_set_md_var(tc, "descr", "Tests execing a command");
970}
971ATF_TC_BODY(exec_success, tc)
972{
973    atf_process_status_t status;
974
975    do_exec(tc, "exit-success", &status, NULL);
976    ATF_CHECK(atf_process_status_exited(&status));
977    ATF_CHECK_EQ(atf_process_status_exitstatus(&status), EXIT_SUCCESS);
978    atf_process_status_fini(&status);
979}
980
981static const int exit_v_null = 1;
982static const int exit_v_notnull = 2;
983
984static
985void
986child_cookie(void *v)
987{
988    if (v == NULL)
989        exit(exit_v_null);
990    else
991        exit(exit_v_notnull);
992
993    UNREACHABLE;
994}
995
996ATF_TC(fork_cookie);
997ATF_TC_HEAD(fork_cookie, tc)
998{
999    atf_tc_set_md_var(tc, "descr", "Tests forking a child, with "
1000                      "a null and non-null data cookie");
1001}
1002ATF_TC_BODY(fork_cookie, tc)
1003{
1004    atf_process_stream_t outsb, errsb;
1005
1006    RE(atf_process_stream_init_inherit(&outsb));
1007    RE(atf_process_stream_init_inherit(&errsb));
1008
1009    {
1010        atf_process_child_t child;
1011        atf_process_status_t status;
1012
1013        RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, NULL));
1014        RE(atf_process_child_wait(&child, &status));
1015
1016        ATF_CHECK(atf_process_status_exited(&status));
1017        ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_null);
1018
1019        atf_process_status_fini(&status);
1020    }
1021
1022    {
1023        atf_process_child_t child;
1024        atf_process_status_t status;
1025        int dummy_int;
1026
1027        RE(atf_process_fork(&child, child_cookie, &outsb, &errsb, &dummy_int));
1028        RE(atf_process_child_wait(&child, &status));
1029
1030        ATF_CHECK(atf_process_status_exited(&status));
1031        ATF_CHECK_EQ(atf_process_status_exitstatus(&status), exit_v_notnull);
1032
1033        atf_process_status_fini(&status);
1034    }
1035
1036    atf_process_stream_fini(&errsb);
1037    atf_process_stream_fini(&outsb);
1038}
1039
1040#define TC_FORK_STREAMS(outlc, outuc, errlc, erruc) \
1041    ATF_TC(fork_out_ ## outlc ## _err_ ## errlc); \
1042    ATF_TC_HEAD(fork_out_ ## outlc ## _err_ ## errlc, tc) \
1043    { \
1044        atf_tc_set_md_var(tc, "descr", "Tests forking a child, with " \
1045                          "stdout " #outlc " and stderr " #errlc); \
1046    } \
1047    ATF_TC_BODY(fork_out_ ## outlc ## _err_ ## errlc, tc) \
1048    { \
1049        struct outlc ## _stream out = outuc ## _STREAM(stdout_type); \
1050        struct errlc ## _stream err = erruc ## _STREAM(stderr_type); \
1051        do_fork(&out.m_base, &out, &err.m_base, &err); \
1052    }
1053
1054TC_FORK_STREAMS(capture, CAPTURE, capture, CAPTURE);
1055TC_FORK_STREAMS(capture, CAPTURE, connect, CONNECT);
1056TC_FORK_STREAMS(capture, CAPTURE, default, DEFAULT);
1057TC_FORK_STREAMS(capture, CAPTURE, inherit, INHERIT);
1058TC_FORK_STREAMS(capture, CAPTURE, redirect_fd, REDIRECT_FD);
1059TC_FORK_STREAMS(capture, CAPTURE, redirect_path, REDIRECT_PATH);
1060TC_FORK_STREAMS(connect, CONNECT, capture, CAPTURE);
1061TC_FORK_STREAMS(connect, CONNECT, connect, CONNECT);
1062TC_FORK_STREAMS(connect, CONNECT, default, DEFAULT);
1063TC_FORK_STREAMS(connect, CONNECT, inherit, INHERIT);
1064TC_FORK_STREAMS(connect, CONNECT, redirect_fd, REDIRECT_FD);
1065TC_FORK_STREAMS(connect, CONNECT, redirect_path, REDIRECT_PATH);
1066TC_FORK_STREAMS(default, DEFAULT, capture, CAPTURE);
1067TC_FORK_STREAMS(default, DEFAULT, connect, CONNECT);
1068TC_FORK_STREAMS(default, DEFAULT, default, DEFAULT);
1069TC_FORK_STREAMS(default, DEFAULT, inherit, INHERIT);
1070TC_FORK_STREAMS(default, DEFAULT, redirect_fd, REDIRECT_FD);
1071TC_FORK_STREAMS(default, DEFAULT, redirect_path, REDIRECT_PATH);
1072TC_FORK_STREAMS(inherit, INHERIT, capture, CAPTURE);
1073TC_FORK_STREAMS(inherit, INHERIT, connect, CONNECT);
1074TC_FORK_STREAMS(inherit, INHERIT, default, DEFAULT);
1075TC_FORK_STREAMS(inherit, INHERIT, inherit, INHERIT);
1076TC_FORK_STREAMS(inherit, INHERIT, redirect_fd, REDIRECT_FD);
1077TC_FORK_STREAMS(inherit, INHERIT, redirect_path, REDIRECT_PATH);
1078TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, capture, CAPTURE);
1079TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, connect, CONNECT);
1080TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, default, DEFAULT);
1081TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, inherit, INHERIT);
1082TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_fd, REDIRECT_FD);
1083TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_path, REDIRECT_PATH);
1084TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, capture, CAPTURE);
1085TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, connect, CONNECT);
1086TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, default, DEFAULT);
1087TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, inherit, INHERIT);
1088TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_fd, REDIRECT_FD);
1089TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_path, REDIRECT_PATH);
1090
1091#undef TC_FORK_STREAMS
1092
1093/* ---------------------------------------------------------------------
1094 * Main.
1095 * --------------------------------------------------------------------- */
1096
1097ATF_TP_ADD_TCS(tp)
1098{
1099    /* Add the tests for the "stream" type. */
1100    ATF_TP_ADD_TC(tp, stream_init_capture);
1101    ATF_TP_ADD_TC(tp, stream_init_connect);
1102    ATF_TP_ADD_TC(tp, stream_init_inherit);
1103    ATF_TP_ADD_TC(tp, stream_init_redirect_fd);
1104    ATF_TP_ADD_TC(tp, stream_init_redirect_path);
1105
1106    /* Add the tests for the "status" type. */
1107    ATF_TP_ADD_TC(tp, status_exited);
1108    ATF_TP_ADD_TC(tp, status_signaled);
1109    ATF_TP_ADD_TC(tp, status_coredump);
1110
1111    /* Add the tests for the "child" type. */
1112    ATF_TP_ADD_TC(tp, child_pid);
1113    ATF_TP_ADD_TC(tp, child_wait_eintr);
1114
1115    /* Add the tests for the free functions. */
1116    ATF_TP_ADD_TC(tp, exec_failure);
1117    ATF_TP_ADD_TC(tp, exec_list);
1118    ATF_TP_ADD_TC(tp, exec_prehook);
1119    ATF_TP_ADD_TC(tp, exec_success);
1120    ATF_TP_ADD_TC(tp, fork_cookie);
1121    ATF_TP_ADD_TC(tp, fork_out_capture_err_capture);
1122    ATF_TP_ADD_TC(tp, fork_out_capture_err_connect);
1123    ATF_TP_ADD_TC(tp, fork_out_capture_err_default);
1124    ATF_TP_ADD_TC(tp, fork_out_capture_err_inherit);
1125    ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_fd);
1126    ATF_TP_ADD_TC(tp, fork_out_capture_err_redirect_path);
1127    ATF_TP_ADD_TC(tp, fork_out_connect_err_capture);
1128    ATF_TP_ADD_TC(tp, fork_out_connect_err_connect);
1129    ATF_TP_ADD_TC(tp, fork_out_connect_err_default);
1130    ATF_TP_ADD_TC(tp, fork_out_connect_err_inherit);
1131    ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_fd);
1132    ATF_TP_ADD_TC(tp, fork_out_connect_err_redirect_path);
1133    ATF_TP_ADD_TC(tp, fork_out_default_err_capture);
1134    ATF_TP_ADD_TC(tp, fork_out_default_err_connect);
1135    ATF_TP_ADD_TC(tp, fork_out_default_err_default);
1136    ATF_TP_ADD_TC(tp, fork_out_default_err_inherit);
1137    ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_fd);
1138    ATF_TP_ADD_TC(tp, fork_out_default_err_redirect_path);
1139    ATF_TP_ADD_TC(tp, fork_out_inherit_err_capture);
1140    ATF_TP_ADD_TC(tp, fork_out_inherit_err_connect);
1141    ATF_TP_ADD_TC(tp, fork_out_inherit_err_default);
1142    ATF_TP_ADD_TC(tp, fork_out_inherit_err_inherit);
1143    ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_fd);
1144    ATF_TP_ADD_TC(tp, fork_out_inherit_err_redirect_path);
1145    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_capture);
1146    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_connect);
1147    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_default);
1148    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_inherit);
1149    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_fd);
1150    ATF_TP_ADD_TC(tp, fork_out_redirect_fd_err_redirect_path);
1151    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_capture);
1152    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_connect);
1153    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_default);
1154    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_inherit);
1155    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_fd);
1156    ATF_TP_ADD_TC(tp, fork_out_redirect_path_err_redirect_path);
1157
1158    return atf_no_error();
1159}
1160