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