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. */
48atf_error_t atf_process_status_init(atf_process_status_t *, int);
49
50/* ---------------------------------------------------------------------
51 * The "stream_prepare" auxiliary type.
52 * --------------------------------------------------------------------- */
53
54struct stream_prepare {
55    const atf_process_stream_t *m_sb;
56
57    bool m_pipefds_ok;
58    int m_pipefds[2];
59};
60typedef struct stream_prepare stream_prepare_t;
61
62static
63atf_error_t
64stream_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
86static
87void
88stream_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
100const int atf_process_stream_type_capture = 1;
101const int atf_process_stream_type_connect = 2;
102const int atf_process_stream_type_inherit = 3;
103const int atf_process_stream_type_redirect_fd = 4;
104const int atf_process_stream_type_redirect_path = 5;
105
106static
107bool
108stream_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
117atf_error_t
118atf_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
126atf_error_t
127atf_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
142atf_error_t
143atf_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
151atf_error_t
152atf_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
162atf_error_t
163atf_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
173void
174atf_process_stream_fini(atf_process_stream_t *sb)
175{
176    PRE(stream_is_valid(sb));
177}
178
179int
180atf_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
191atf_error_t
192atf_process_status_init(atf_process_status_t *s, int status)
193{
194    s->m_status = status;
195
196    return atf_no_error();
197}
198
199void
200atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
201{
202}
203
204bool
205atf_process_status_exited(const atf_process_status_t *s)
206{
207    int mutable_status = s->m_status;
208    return WIFEXITED(mutable_status);
209}
210
211int
212atf_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
219bool
220atf_process_status_signaled(const atf_process_status_t *s)
221{
222    int mutable_status = s->m_status;
223    return WIFSIGNALED(mutable_status);
224}
225
226int
227atf_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
234bool
235atf_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
250static
251atf_error_t
252atf_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
261static
262void
263atf_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
271atf_error_t
272atf_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
288pid_t
289atf_process_child_pid(const atf_process_child_t *c)
290{
291    return c->m_pid;
292}
293
294int
295atf_process_child_stdout(atf_process_child_t *c)
296{
297    PRE(c->m_stdout != -1);
298    return c->m_stdout;
299}
300
301int
302atf_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
312static
313atf_error_t
314safe_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
331static
332atf_error_t
333child_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
370static
371void
372parent_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
392static
393atf_error_t
394do_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
410out:
411    return err;
412}
413
414static
415void
416do_child(void (*)(void *),
417         void *,
418         const stream_prepare_t *,
419         const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
420
421static
422void
423do_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
441out:
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
454static
455atf_error_t
456fork_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
494err_errpipe:
495    stream_prepare_fini(&errsp);
496err_outpipe:
497    stream_prepare_fini(&outsp);
498
499out:
500    return err;
501}
502
503static
504atf_error_t
505init_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
523atf_error_t
524atf_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);
548out_out:
549    if (outsb == NULL)
550        atf_process_stream_fini(&inherit_outsb);
551out:
552    return err;
553}
554
555static
556int
557const_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
564static
565atf_error_t
566list_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
592struct exec_args {
593    const atf_fs_path_t *m_prog;
594    const char *const *m_argv;
595    void (*m_prehook)(void);
596};
597
598static
599void
600do_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
615atf_error_t
616atf_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
636again:
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
644out:
645    return err;
646}
647
648atf_error_t
649atf_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);
672out:
673    return err;
674}
675