xref: /freebsd/contrib/atf/atf-c/detail/process_test.c (revision ff0ba87247820afbdfdc1b307c803f7923d0e4d3)
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 
47 atf_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 
67 enum out_type { stdout_type, stderr_type };
68 
69 struct 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 
88 static
89 void
90 check_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 
106 struct 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 
117 static
118 void
119 capture_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 
128 static
129 void
130 capture_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 
146 static
147 void
148 capture_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 
169 struct 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 
180 static
181 void
182 connect_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 
206 static
207 void
208 connect_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 
219 struct 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 
231 static
232 void
233 inherit_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 
262 static
263 void
264 inherit_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 
283 static
284 void
285 default_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 
293 static
294 void
295 default_stream_fini(void *v)
296 {
297     inherit_stream_fini(v);
298 }
299 
300 struct 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 
311 static
312 void
313 redirect_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 
333 static
334 void
335 redirect_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 
346 struct 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 
357 static
358 void
359 redirect_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 
378 static
379 void
380 redirect_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 
391 static void child_print(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
392 
393 struct child_print_data {
394     const char *m_msg;
395 };
396 
397 static
398 void
399 child_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 
409 static
410 void
411 do_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 
439 ATF_TC(stream_init_capture);
440 ATF_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 }
445 ATF_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 
457 ATF_TC(stream_init_connect);
458 ATF_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 }
463 ATF_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 
475 ATF_TC(stream_init_inherit);
476 ATF_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 }
481 ATF_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 
493 ATF_TC(stream_init_redirect_fd);
494 ATF_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 }
499 ATF_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 
511 ATF_TC(stream_init_redirect_path);
512 ATF_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 }
517 ATF_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 
536 static void child_exit_success(void) ATF_DEFS_ATTRIBUTE_NORETURN;
537 static void child_exit_failure(void) ATF_DEFS_ATTRIBUTE_NORETURN;
538 static void child_sigkill(void) ATF_DEFS_ATTRIBUTE_NORETURN;
539 static void child_sigquit(void) ATF_DEFS_ATTRIBUTE_NORETURN;
540 static void child_sigterm(void) ATF_DEFS_ATTRIBUTE_NORETURN;
541 
542 void
543 child_exit_success(void)
544 {
545     exit(EXIT_SUCCESS);
546 }
547 
548 void
549 child_exit_failure(void)
550 {
551     exit(EXIT_FAILURE);
552 }
553 
554 void
555 child_sigkill(void)
556 {
557     kill(getpid(), SIGKILL);
558     abort();
559 }
560 
561 void
562 child_sigquit(void)
563 {
564     kill(getpid(), SIGQUIT);
565     abort();
566 }
567 
568 void
569 child_sigterm(void)
570 {
571     kill(getpid(), SIGTERM);
572     abort();
573 }
574 
575 static
576 int
577 fork_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 
595 ATF_TC(status_exited);
596 ATF_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 }
601 ATF_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 
624 ATF_TC(status_signaled);
625 ATF_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 }
630 ATF_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 
655 ATF_TC(status_coredump);
656 ATF_TC_HEAD(status_coredump, tc)
657 {
658     atf_tc_set_md_var(tc, "descr", "Tests the status type for processes "
659                       "that crash");
660 }
661 ATF_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 
684 static void child_report_pid(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
685 
686 static
687 void
688 child_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 
697 ATF_TC(child_pid);
698 ATF_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 }
703 ATF_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 
727 static
728 void
729 child_loop(void *v ATF_DEFS_ATTRIBUTE_UNUSED)
730 {
731     for (;;)
732         sleep(1);
733 }
734 
735 static
736 void
737 nop_signal(int sig ATF_DEFS_ATTRIBUTE_UNUSED)
738 {
739 }
740 
741 static
742 void
743 child_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 
807 ATF_TC(child_wait_eintr);
808 ATF_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 }
815 ATF_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 
857 static
858 void
859 do_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 
876 static
877 void
878 check_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 
886 ATF_TC(exec_failure);
887 ATF_TC_HEAD(exec_failure, tc)
888 {
889     atf_tc_set_md_var(tc, "descr", "Tests execing a command");
890 }
891 ATF_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 
901 ATF_TC(exec_list);
902 ATF_TC_HEAD(exec_list, tc)
903 {
904     atf_tc_set_md_var(tc, "descr", "Tests execing a command");
905 }
906 ATF_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 
945 static void
946 exit_early(void)
947 {
948     exit(80);
949 }
950 
951 ATF_TC(exec_prehook);
952 ATF_TC_HEAD(exec_prehook, tc)
953 {
954     atf_tc_set_md_var(tc, "descr", "Tests execing a command with a prehook");
955 }
956 ATF_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 
966 ATF_TC(exec_success);
967 ATF_TC_HEAD(exec_success, tc)
968 {
969     atf_tc_set_md_var(tc, "descr", "Tests execing a command");
970 }
971 ATF_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 
981 static const int exit_v_null = 1;
982 static const int exit_v_notnull = 2;
983 
984 static
985 void
986 child_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 
996 ATF_TC(fork_cookie);
997 ATF_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 }
1002 ATF_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 
1054 TC_FORK_STREAMS(capture, CAPTURE, capture, CAPTURE);
1055 TC_FORK_STREAMS(capture, CAPTURE, connect, CONNECT);
1056 TC_FORK_STREAMS(capture, CAPTURE, default, DEFAULT);
1057 TC_FORK_STREAMS(capture, CAPTURE, inherit, INHERIT);
1058 TC_FORK_STREAMS(capture, CAPTURE, redirect_fd, REDIRECT_FD);
1059 TC_FORK_STREAMS(capture, CAPTURE, redirect_path, REDIRECT_PATH);
1060 TC_FORK_STREAMS(connect, CONNECT, capture, CAPTURE);
1061 TC_FORK_STREAMS(connect, CONNECT, connect, CONNECT);
1062 TC_FORK_STREAMS(connect, CONNECT, default, DEFAULT);
1063 TC_FORK_STREAMS(connect, CONNECT, inherit, INHERIT);
1064 TC_FORK_STREAMS(connect, CONNECT, redirect_fd, REDIRECT_FD);
1065 TC_FORK_STREAMS(connect, CONNECT, redirect_path, REDIRECT_PATH);
1066 TC_FORK_STREAMS(default, DEFAULT, capture, CAPTURE);
1067 TC_FORK_STREAMS(default, DEFAULT, connect, CONNECT);
1068 TC_FORK_STREAMS(default, DEFAULT, default, DEFAULT);
1069 TC_FORK_STREAMS(default, DEFAULT, inherit, INHERIT);
1070 TC_FORK_STREAMS(default, DEFAULT, redirect_fd, REDIRECT_FD);
1071 TC_FORK_STREAMS(default, DEFAULT, redirect_path, REDIRECT_PATH);
1072 TC_FORK_STREAMS(inherit, INHERIT, capture, CAPTURE);
1073 TC_FORK_STREAMS(inherit, INHERIT, connect, CONNECT);
1074 TC_FORK_STREAMS(inherit, INHERIT, default, DEFAULT);
1075 TC_FORK_STREAMS(inherit, INHERIT, inherit, INHERIT);
1076 TC_FORK_STREAMS(inherit, INHERIT, redirect_fd, REDIRECT_FD);
1077 TC_FORK_STREAMS(inherit, INHERIT, redirect_path, REDIRECT_PATH);
1078 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, capture, CAPTURE);
1079 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, connect, CONNECT);
1080 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, default, DEFAULT);
1081 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, inherit, INHERIT);
1082 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_fd, REDIRECT_FD);
1083 TC_FORK_STREAMS(redirect_fd, REDIRECT_FD, redirect_path, REDIRECT_PATH);
1084 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, capture, CAPTURE);
1085 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, connect, CONNECT);
1086 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, default, DEFAULT);
1087 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, inherit, INHERIT);
1088 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_fd, REDIRECT_FD);
1089 TC_FORK_STREAMS(redirect_path, REDIRECT_PATH, redirect_path, REDIRECT_PATH);
1090 
1091 #undef TC_FORK_STREAMS
1092 
1093 /* ---------------------------------------------------------------------
1094  * Main.
1095  * --------------------------------------------------------------------- */
1096 
1097 ATF_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