Home | History | Annotate | Line # | Download | only in detail
      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
     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
     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
    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
    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
    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
    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
    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
    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
    174 atf_process_stream_fini(atf_process_stream_t *sb)
    175 {
    176     PRE(stream_is_valid(sb));
    177 }
    178 
    179 int
    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
    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
    200 atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED)
    201 {
    202 }
    203 
    204 bool
    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
    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
    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
    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
    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
    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
    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
    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
    289 atf_process_child_pid(const atf_process_child_t *c)
    290 {
    291     return c->m_pid;
    292 }
    293 
    294 int
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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