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