1 /*	$NetBSD: process.c,v 1.3 2014/12/10 04:38:03 christos Exp $	*/
2 
3 /*
4  * Automated Testing Framework (atf)
5  *
6  * Copyright (c) 2007 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/wait.h>
34 
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include "atf-c/defs.h"
43 #include "atf-c/error.h"
44 
45 #include "process.h"
46 #include "sanity.h"
47 
48 /* This prototype is not in the header file because this is a private
49  * function; however, we need to access it during testing. */
50 atf_error_t atf_process_status_init(atf_process_status_t *, int);
51 
52 /* ---------------------------------------------------------------------
53  * The "stream_prepare" auxiliary type.
54  * --------------------------------------------------------------------- */
55 
56 struct stream_prepare {
57     const atf_process_stream_t *m_sb;
58 
59     bool m_pipefds_ok;
60     int m_pipefds[2];
61 };
62 typedef struct stream_prepare stream_prepare_t;
63 
64 static
65 atf_error_t
stream_prepare_init(stream_prepare_t * sp,const atf_process_stream_t * sb)66 stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb)
67 {
68     atf_error_t err;
69 
70     const int type = atf_process_stream_type(sb);
71 
72     sp->m_sb = sb;
73     sp->m_pipefds_ok = false;
74 
75     if (type == atf_process_stream_type_capture) {
76         if (pipe(sp->m_pipefds) == -1)
77             err = atf_libc_error(errno, "Failed to create pipe");
78         else {
79             err = atf_no_error();
80             sp->m_pipefds_ok = true;
81         }
82     } else
83         err = atf_no_error();
84 
85     return err;
86 }
87 
88 static
89 void
stream_prepare_fini(stream_prepare_t * sp)90 stream_prepare_fini(stream_prepare_t *sp)
91 {
92     if (sp->m_pipefds_ok) {
93         close(sp->m_pipefds[0]);
94         close(sp->m_pipefds[1]);
95     }
96 }
97 
98 /* ---------------------------------------------------------------------
99  * The "atf_process_stream" type.
100  * --------------------------------------------------------------------- */
101 
102 const int atf_process_stream_type_capture = 1;
103 const int atf_process_stream_type_connect = 2;
104 const int atf_process_stream_type_inherit = 3;
105 const int atf_process_stream_type_redirect_fd = 4;
106 const int atf_process_stream_type_redirect_path = 5;
107 
108 static
109 bool
stream_is_valid(const atf_process_stream_t * sb)110 stream_is_valid(const atf_process_stream_t *sb)
111 {
112     return (sb->m_type == atf_process_stream_type_capture) ||
113            (sb->m_type == atf_process_stream_type_connect) ||
114            (sb->m_type == atf_process_stream_type_inherit) ||
115            (sb->m_type == atf_process_stream_type_redirect_fd) ||
116            (sb->m_type == atf_process_stream_type_redirect_path);
117 }
118 
119 atf_error_t
atf_process_stream_init_capture(atf_process_stream_t * sb)120 atf_process_stream_init_capture(atf_process_stream_t *sb)
121 {
122     sb->m_type = atf_process_stream_type_capture;
123 
124     POST(stream_is_valid(sb));
125     return atf_no_error();
126 }
127 
128 atf_error_t
atf_process_stream_init_connect(atf_process_stream_t * sb,const int src_fd,const int tgt_fd)129 atf_process_stream_init_connect(atf_process_stream_t *sb,
130                                 const int src_fd, const int tgt_fd)
131 {
132     PRE(src_fd >= 0);
133     PRE(tgt_fd >= 0);
134     PRE(src_fd != tgt_fd);
135 
136     sb->m_type = atf_process_stream_type_connect;
137     sb->m_src_fd = src_fd;
138     sb->m_tgt_fd = tgt_fd;
139 
140     POST(stream_is_valid(sb));
141     return atf_no_error();
142 }
143 
144 atf_error_t
atf_process_stream_init_inherit(atf_process_stream_t * sb)145 atf_process_stream_init_inherit(atf_process_stream_t *sb)
146 {
147     sb->m_type = atf_process_stream_type_inherit;
148 
149     POST(stream_is_valid(sb));
150     return atf_no_error();
151 }
152 
153 atf_error_t
atf_process_stream_init_redirect_fd(atf_process_stream_t * sb,const int fd)154 atf_process_stream_init_redirect_fd(atf_process_stream_t *sb,
155                                     const int fd)
156 {
157     sb->m_type = atf_process_stream_type_redirect_fd;
158     sb->m_fd = fd;
159 
160     POST(stream_is_valid(sb));
161     return atf_no_error();
162 }
163 
164 atf_error_t
atf_process_stream_init_redirect_path(atf_process_stream_t * sb,const atf_fs_path_t * path)165 atf_process_stream_init_redirect_path(atf_process_stream_t *sb,
166                                       const atf_fs_path_t *path)
167 {
168     sb->m_type = atf_process_stream_type_redirect_path;
169     sb->m_path = path;
170 
171     POST(stream_is_valid(sb));
172     return atf_no_error();
173 }
174 
175 void
atf_process_stream_fini(atf_process_stream_t * sb)176 atf_process_stream_fini(atf_process_stream_t *sb)
177 {
178     PRE(stream_is_valid(sb));
179 }
180 
181 int
atf_process_stream_type(const atf_process_stream_t * sb)182 atf_process_stream_type(const atf_process_stream_t *sb)
183 {
184     PRE(stream_is_valid(sb));
185 
186     return sb->m_type;
187 }
188 
189 /* ---------------------------------------------------------------------
190  * The "atf_process_status" type.
191  * --------------------------------------------------------------------- */
192 
193 atf_error_t
atf_process_status_init(atf_process_status_t * s,int status)194 atf_process_status_init(atf_process_status_t *s, int status)
195 {
196     s->m_status = status;
197 
198     return atf_no_error();
199 }
200 
201 void
atf_process_status_fini(atf_process_status_t * s ATF_DEFS_ATTRIBUTE_UNUSED)202 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
203 {
204 }
205 
206 bool
atf_process_status_exited(const atf_process_status_t * s)207 atf_process_status_exited(const atf_process_status_t *s)
208 {
209     int mutable_status = s->m_status;
210     return WIFEXITED(mutable_status);
211 }
212 
213 int
atf_process_status_exitstatus(const atf_process_status_t * s)214 atf_process_status_exitstatus(const atf_process_status_t *s)
215 {
216     PRE(atf_process_status_exited(s));
217     int mutable_status = s->m_status;
218     return WEXITSTATUS(mutable_status);
219 }
220 
221 bool
atf_process_status_signaled(const atf_process_status_t * s)222 atf_process_status_signaled(const atf_process_status_t *s)
223 {
224     int mutable_status = s->m_status;
225     return WIFSIGNALED(mutable_status);
226 }
227 
228 int
atf_process_status_termsig(const atf_process_status_t * s)229 atf_process_status_termsig(const atf_process_status_t *s)
230 {
231     PRE(atf_process_status_signaled(s));
232     int mutable_status = s->m_status;
233     return WTERMSIG(mutable_status);
234 }
235 
236 bool
atf_process_status_coredump(const atf_process_status_t * s)237 atf_process_status_coredump(const atf_process_status_t *s)
238 {
239     PRE(atf_process_status_signaled(s));
240 #if defined(WCOREDUMP)
241     int mutable_status = s->m_status;
242     return WCOREDUMP(mutable_status);
243 #else
244     return false;
245 #endif
246 }
247 
248 /* ---------------------------------------------------------------------
249  * The "atf_process_child" type.
250  * --------------------------------------------------------------------- */
251 
252 static
253 atf_error_t
atf_process_child_init(atf_process_child_t * c)254 atf_process_child_init(atf_process_child_t *c)
255 {
256     c->m_pid = 0;
257     c->m_stdout = -1;
258     c->m_stderr = -1;
259 
260     return atf_no_error();
261 }
262 
263 static
264 void
atf_process_child_fini(atf_process_child_t * c)265 atf_process_child_fini(atf_process_child_t *c)
266 {
267     if (c->m_stdout != -1)
268         close(c->m_stdout);
269     if (c->m_stderr != -1)
270         close(c->m_stderr);
271 }
272 
273 atf_error_t
atf_process_child_wait(atf_process_child_t * c,atf_process_status_t * s)274 atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s)
275 {
276     atf_error_t err;
277     int status;
278 
279     if (waitpid(c->m_pid, &status, 0) == -1)
280         err = atf_libc_error(errno, "Failed waiting for process %d",
281                              c->m_pid);
282     else {
283         atf_process_child_fini(c);
284         err = atf_process_status_init(s, status);
285     }
286 
287     return err;
288 }
289 
290 pid_t
atf_process_child_pid(const atf_process_child_t * c)291 atf_process_child_pid(const atf_process_child_t *c)
292 {
293     return c->m_pid;
294 }
295 
296 int
atf_process_child_stdout(atf_process_child_t * c)297 atf_process_child_stdout(atf_process_child_t *c)
298 {
299     PRE(c->m_stdout != -1);
300     return c->m_stdout;
301 }
302 
303 int
atf_process_child_stderr(atf_process_child_t * c)304 atf_process_child_stderr(atf_process_child_t *c)
305 {
306     PRE(c->m_stderr != -1);
307     return c->m_stderr;
308 }
309 
310 /* ---------------------------------------------------------------------
311  * Free functions.
312  * --------------------------------------------------------------------- */
313 
314 static
315 atf_error_t
safe_dup(const int oldfd,const int newfd)316 safe_dup(const int oldfd, const int newfd)
317 {
318     atf_error_t err;
319 
320     if (oldfd != newfd) {
321         if (dup2(oldfd, newfd) == -1) {
322             err = atf_libc_error(errno, "Could not allocate file descriptor");
323         } else {
324             close(oldfd);
325             err = atf_no_error();
326         }
327     } else
328         err = atf_no_error();
329 
330     return err;
331 }
332 
333 static
334 atf_error_t
child_connect(const stream_prepare_t * sp,int procfd)335 child_connect(const stream_prepare_t *sp, int procfd)
336 {
337     atf_error_t err;
338     const int type = atf_process_stream_type(sp->m_sb);
339 
340     if (type == atf_process_stream_type_capture) {
341         close(sp->m_pipefds[0]);
342         err = safe_dup(sp->m_pipefds[1], procfd);
343     } else if (type == atf_process_stream_type_connect) {
344         if (dup2(sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd) == -1)
345             err = atf_libc_error(errno, "Cannot connect descriptor %d to %d",
346                                  sp->m_sb->m_tgt_fd, sp->m_sb->m_src_fd);
347         else
348             err = atf_no_error();
349     } else if (type == atf_process_stream_type_inherit) {
350         err = atf_no_error();
351     } else if (type == atf_process_stream_type_redirect_fd) {
352         err = safe_dup(sp->m_sb->m_fd, procfd);
353     } else if (type == atf_process_stream_type_redirect_path) {
354         int aux = open(atf_fs_path_cstring(sp->m_sb->m_path),
355                        O_WRONLY | O_CREAT | O_TRUNC, 0644);
356         if (aux == -1)
357             err = atf_libc_error(errno, "Could not create %s",
358                                  atf_fs_path_cstring(sp->m_sb->m_path));
359         else {
360             err = safe_dup(aux, procfd);
361             if (atf_is_error(err))
362                 close(aux);
363         }
364     } else {
365         UNREACHABLE;
366         err = atf_no_error();
367     }
368 
369     return err;
370 }
371 
372 static
373 void
parent_connect(const stream_prepare_t * sp,int * fd)374 parent_connect(const stream_prepare_t *sp, int *fd)
375 {
376     const int type = atf_process_stream_type(sp->m_sb);
377 
378     if (type == atf_process_stream_type_capture) {
379         close(sp->m_pipefds[1]);
380         *fd = sp->m_pipefds[0];
381     } else if (type == atf_process_stream_type_connect) {
382         /* Do nothing. */
383     } else if (type == atf_process_stream_type_inherit) {
384         /* Do nothing. */
385     } else if (type == atf_process_stream_type_redirect_fd) {
386         /* Do nothing. */
387     } else if (type == atf_process_stream_type_redirect_path) {
388         /* Do nothing. */
389     } else {
390         UNREACHABLE;
391     }
392 }
393 
394 static
395 atf_error_t
do_parent(atf_process_child_t * c,const pid_t pid,const stream_prepare_t * outsp,const stream_prepare_t * errsp)396 do_parent(atf_process_child_t *c,
397           const pid_t pid,
398           const stream_prepare_t *outsp,
399           const stream_prepare_t *errsp)
400 {
401     atf_error_t err;
402 
403     err = atf_process_child_init(c);
404     if (atf_is_error(err))
405         goto out;
406 
407     c->m_pid = pid;
408 
409     parent_connect(outsp, &c->m_stdout);
410     parent_connect(errsp, &c->m_stderr);
411 
412 out:
413     return err;
414 }
415 
416 static
417 void
418 do_child(void (*)(void *),
419          void *,
420          const stream_prepare_t *,
421          const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
422 
423 static
424 void
do_child(void (* start)(void *),void * v,const stream_prepare_t * outsp,const stream_prepare_t * errsp)425 do_child(void (*start)(void *),
426          void *v,
427          const stream_prepare_t *outsp,
428          const stream_prepare_t *errsp)
429 {
430     atf_error_t err;
431 
432     err = child_connect(outsp, STDOUT_FILENO);
433     if (atf_is_error(err))
434         goto out;
435 
436     err = child_connect(errsp, STDERR_FILENO);
437     if (atf_is_error(err))
438         goto out;
439 
440     start(v);
441     UNREACHABLE;
442 
443 out:
444     if (atf_is_error(err)) {
445         char buf[1024];
446 
447         atf_error_format(err, buf, sizeof(buf));
448         fprintf(stderr, "Unhandled error: %s\n", buf);
449         atf_error_free(err);
450 
451         exit(EXIT_FAILURE);
452     } else
453         exit(EXIT_SUCCESS);
454 }
455 
456 static
457 atf_error_t
fork_with_streams(atf_process_child_t * c,void (* start)(void *),const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void * v)458 fork_with_streams(atf_process_child_t *c,
459                   void (*start)(void *),
460                   const atf_process_stream_t *outsb,
461                   const atf_process_stream_t *errsb,
462                   void *v)
463 {
464     atf_error_t err;
465     stream_prepare_t outsp;
466     stream_prepare_t errsp;
467     pid_t pid;
468 
469     err = stream_prepare_init(&outsp, outsb);
470     if (atf_is_error(err))
471         goto out;
472 
473     err = stream_prepare_init(&errsp, errsb);
474     if (atf_is_error(err))
475         goto err_outpipe;
476 
477     pid = fork();
478     if (pid == -1) {
479         err = atf_libc_error(errno, "Failed to fork");
480         goto err_errpipe;
481     }
482 
483     if (pid == 0) {
484         do_child(start, v, &outsp, &errsp);
485         UNREACHABLE;
486         abort();
487         err = atf_no_error();
488     } else {
489         err = do_parent(c, pid, &outsp, &errsp);
490         if (atf_is_error(err))
491             goto err_errpipe;
492     }
493 
494     goto out;
495 
496 err_errpipe:
497     stream_prepare_fini(&errsp);
498 err_outpipe:
499     stream_prepare_fini(&outsp);
500 
501 out:
502     return err;
503 }
504 
505 static
506 atf_error_t
init_stream_w_default(const atf_process_stream_t * usersb,atf_process_stream_t * inheritsb,const atf_process_stream_t ** realsb)507 init_stream_w_default(const atf_process_stream_t *usersb,
508                       atf_process_stream_t *inheritsb,
509                       const atf_process_stream_t **realsb)
510 {
511     atf_error_t err;
512 
513     if (usersb == NULL) {
514         err = atf_process_stream_init_inherit(inheritsb);
515         if (!atf_is_error(err))
516             *realsb = inheritsb;
517     } else {
518         err = atf_no_error();
519         *realsb = usersb;
520     }
521 
522     return err;
523 }
524 
525 atf_error_t
atf_process_fork(atf_process_child_t * c,void (* start)(void *),const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void * v)526 atf_process_fork(atf_process_child_t *c,
527                  void (*start)(void *),
528                  const atf_process_stream_t *outsb,
529                  const atf_process_stream_t *errsb,
530                  void *v)
531 {
532     atf_error_t err;
533     atf_process_stream_t inherit_outsb, inherit_errsb;
534     const atf_process_stream_t *real_outsb, *real_errsb;
535 
536     real_outsb = NULL;  /* Shut up GCC warning. */
537     err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb);
538     if (atf_is_error(err))
539         goto out;
540 
541     real_errsb = NULL;  /* Shut up GCC warning. */
542     err = init_stream_w_default(errsb, &inherit_errsb, &real_errsb);
543     if (atf_is_error(err))
544         goto out_out;
545 
546     err = fork_with_streams(c, start, real_outsb, real_errsb, v);
547 
548     if (errsb == NULL)
549         atf_process_stream_fini(&inherit_errsb);
550 out_out:
551     if (outsb == NULL)
552         atf_process_stream_fini(&inherit_outsb);
553 out:
554     return err;
555 }
556 
557 static
558 int
const_execvp(const char * file,const char * const * argv)559 const_execvp(const char *file, const char *const *argv)
560 {
561 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
562     return execvp(file, UNCONST(argv));
563 #undef UNCONST
564 }
565 
566 static
567 atf_error_t
list_to_array(const atf_list_t * l,const char *** ap)568 list_to_array(const atf_list_t *l, const char ***ap)
569 {
570     atf_error_t err;
571     const char **a;
572 
573     a = (const char **)malloc((atf_list_size(l) + 1) * sizeof(const char *));
574     if (a == NULL)
575         err = atf_no_memory_error();
576     else {
577         const char **aiter;
578         atf_list_citer_t liter;
579 
580         aiter = a;
581         atf_list_for_each_c(liter, l) {
582             *aiter = (const char *)atf_list_citer_data(liter);
583             aiter++;
584         }
585         *aiter = NULL;
586 
587         err = atf_no_error();
588         *ap = a;
589     }
590 
591     return err;
592 }
593 
594 struct exec_args {
595     const atf_fs_path_t *m_prog;
596     const char *const *m_argv;
597     void (*m_prehook)(void);
598 };
599 
600 static
601 void
do_exec(void * v)602 do_exec(void *v)
603 {
604     struct exec_args *ea = v;
605 
606     if (ea->m_prehook != NULL)
607         ea->m_prehook();
608 
609     const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
610     const int errnocopy = errno;
611     INV(ret == -1);
612     fprintf(stderr, "exec(%s) failed: %s\n",
613             atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
614     exit(EXIT_FAILURE);
615 }
616 
617 atf_error_t
atf_process_exec_array(atf_process_status_t * s,const atf_fs_path_t * prog,const char * const * argv,const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void (* prehook)(void))618 atf_process_exec_array(atf_process_status_t *s,
619                        const atf_fs_path_t *prog,
620                        const char *const *argv,
621                        const atf_process_stream_t *outsb,
622                        const atf_process_stream_t *errsb,
623                        void (*prehook)(void))
624 {
625     atf_error_t err;
626     atf_process_child_t c;
627     struct exec_args ea = { prog, argv, prehook };
628 
629     PRE(outsb == NULL ||
630         atf_process_stream_type(outsb) != atf_process_stream_type_capture);
631     PRE(errsb == NULL ||
632         atf_process_stream_type(errsb) != atf_process_stream_type_capture);
633 
634     err = atf_process_fork(&c, do_exec, outsb, errsb, &ea);
635     if (atf_is_error(err))
636         goto out;
637 
638 again:
639     err = atf_process_child_wait(&c, s);
640     if (atf_is_error(err)) {
641         INV(atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR);
642         atf_error_free(err);
643         goto again;
644     }
645 
646 out:
647     return err;
648 }
649 
650 atf_error_t
atf_process_exec_list(atf_process_status_t * s,const atf_fs_path_t * prog,const atf_list_t * argv,const atf_process_stream_t * outsb,const atf_process_stream_t * errsb,void (* prehook)(void))651 atf_process_exec_list(atf_process_status_t *s,
652                       const atf_fs_path_t *prog,
653                       const atf_list_t *argv,
654                       const atf_process_stream_t *outsb,
655                       const atf_process_stream_t *errsb,
656                       void (*prehook)(void))
657 {
658     atf_error_t err;
659     const char **argv2;
660 
661     PRE(outsb == NULL ||
662         atf_process_stream_type(outsb) != atf_process_stream_type_capture);
663     PRE(errsb == NULL ||
664         atf_process_stream_type(errsb) != atf_process_stream_type_capture);
665 
666     argv2 = NULL; /* Silence GCC warning. */
667     err = list_to_array(argv, &argv2);
668     if (atf_is_error(err))
669         goto out;
670 
671     err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook);
672 
673     free(argv2);
674 out:
675     return err;
676 }
677