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