1263320Sdim/*	$NetBSD$	*/
2263320Sdim
3263320Sdim/*
4269012Semaste * Automated Testing Framework (atf)
5263320Sdim *
6263320Sdim * Copyright (c) 2007, 2008, 2009, 2010 The NetBSD Foundation, Inc.
7263320Sdim * All rights reserved.
8263320Sdim *
9263320Sdim * Redistribution and use in source and binary forms, with or without
10263320Sdim * modification, are permitted provided that the following conditions
11263320Sdim * are met:
12263320Sdim * 1. Redistributions of source code must retain the above copyright
13263320Sdim *    notice, this list of conditions and the following disclaimer.
14263320Sdim * 2. Redistributions in binary form must reproduce the above copyright
15263320Sdim *    notice, this list of conditions and the following disclaimer in the
16263320Sdim *    documentation and/or other materials provided with the distribution.
17263320Sdim *
18263320Sdim * 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. */
50atf_error_t atf_process_status_init(atf_process_status_t *, int);
51
52/* ---------------------------------------------------------------------
53 * The "stream_prepare" auxiliary type.
54 * --------------------------------------------------------------------- */
55
56struct stream_prepare {
57    const atf_process_stream_t *m_sb;
58
59    bool m_pipefds_ok;
60    int m_pipefds[2];
61};
62typedef struct stream_prepare stream_prepare_t;
63
64static
65atf_error_t
66stream_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
88static
89void
90stream_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
102const int atf_process_stream_type_capture = 1;
103const int atf_process_stream_type_connect = 2;
104const int atf_process_stream_type_inherit = 3;
105const int atf_process_stream_type_redirect_fd = 4;
106const int atf_process_stream_type_redirect_path = 5;
107
108static
109bool
110stream_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
119atf_error_t
120atf_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
128atf_error_t
129atf_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
144atf_error_t
145atf_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
153atf_error_t
154atf_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
164atf_error_t
165atf_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
175void
176atf_process_stream_fini(atf_process_stream_t *sb)
177{
178    PRE(stream_is_valid(sb));
179}
180
181int
182atf_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
193atf_error_t
194atf_process_status_init(atf_process_status_t *s, int status)
195{
196    s->m_status = status;
197
198    return atf_no_error();
199}
200
201void
202atf_process_status_fini(atf_process_status_t *s)
203{
204}
205
206bool
207atf_process_status_exited(const atf_process_status_t *s)
208{
209    int mutable_status = s->m_status;
210    return WIFEXITED(mutable_status);
211}
212
213int
214atf_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
221bool
222atf_process_status_signaled(const atf_process_status_t *s)
223{
224    int mutable_status = s->m_status;
225    return WIFSIGNALED(mutable_status);
226}
227
228int
229atf_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
236bool
237atf_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
252static
253atf_error_t
254atf_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
263static
264void
265atf_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
273atf_error_t
274atf_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
290pid_t
291atf_process_child_pid(const atf_process_child_t *c)
292{
293    return c->m_pid;
294}
295
296int
297atf_process_child_stdout(atf_process_child_t *c)
298{
299    PRE(c->m_stdout != -1);
300    return c->m_stdout;
301}
302
303int
304atf_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
314static
315atf_error_t
316safe_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
333static
334atf_error_t
335child_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
372static
373void
374parent_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
394static
395atf_error_t
396do_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
412out:
413    return err;
414}
415
416static
417void
418do_child(void (*)(void *),
419         void *,
420         const stream_prepare_t *,
421         const stream_prepare_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
422
423static
424void
425do_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
443out:
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
456static
457atf_error_t
458fork_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
496err_errpipe:
497    stream_prepare_fini(&errsp);
498err_outpipe:
499    stream_prepare_fini(&outsp);
500
501out:
502    return err;
503}
504
505static
506atf_error_t
507init_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
525atf_error_t
526atf_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);
550out_out:
551    if (outsb == NULL)
552        atf_process_stream_fini(&inherit_outsb);
553out:
554    return err;
555}
556
557static
558int
559const_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
566static
567atf_error_t
568list_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
594struct exec_args {
595    const atf_fs_path_t *m_prog;
596    const char *const *m_argv;
597};
598
599static
600void
601do_exec(void *v)
602{
603    struct exec_args *ea = v;
604
605    const int ret = const_execvp(atf_fs_path_cstring(ea->m_prog), ea->m_argv);
606    const int errnocopy = errno;
607    INV(ret == -1);
608    fprintf(stderr, "exec(%s) failed: %s\n",
609            atf_fs_path_cstring(ea->m_prog), strerror(errnocopy));
610    exit(EXIT_FAILURE);
611}
612
613atf_error_t
614atf_process_exec_array(atf_process_status_t *s,
615                       const atf_fs_path_t *prog,
616                       const char *const *argv,
617                       const atf_process_stream_t *outsb,
618                       const atf_process_stream_t *errsb)
619{
620    atf_error_t err;
621    atf_process_child_t c;
622    struct exec_args ea = { prog, argv };
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
633again:
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
641out:
642    return err;
643}
644
645atf_error_t
646atf_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{
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);
666
667    free(argv2);
668out:
669    return err;
670}
671