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