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