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