Home | History | Annotate | Line # | Download | only in atf-c
tc.c revision 1.1.1.2
      1      1.1  jmmv /*
      2      1.1  jmmv  * Automated Testing Framework (atf)
      3      1.1  jmmv  *
      4  1.1.1.2  jmmv  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
      5      1.1  jmmv  * All rights reserved.
      6      1.1  jmmv  *
      7      1.1  jmmv  * Redistribution and use in source and binary forms, with or without
      8      1.1  jmmv  * modification, are permitted provided that the following conditions
      9      1.1  jmmv  * are met:
     10      1.1  jmmv  * 1. Redistributions of source code must retain the above copyright
     11      1.1  jmmv  *    notice, this list of conditions and the following disclaimer.
     12      1.1  jmmv  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1  jmmv  *    notice, this list of conditions and the following disclaimer in the
     14      1.1  jmmv  *    documentation and/or other materials provided with the distribution.
     15      1.1  jmmv  *
     16      1.1  jmmv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
     17      1.1  jmmv  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     18      1.1  jmmv  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19      1.1  jmmv  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20      1.1  jmmv  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
     21      1.1  jmmv  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22      1.1  jmmv  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     23      1.1  jmmv  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24      1.1  jmmv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
     25      1.1  jmmv  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     26      1.1  jmmv  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27      1.1  jmmv  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28      1.1  jmmv  */
     29      1.1  jmmv 
     30      1.1  jmmv #include <sys/types.h>
     31      1.1  jmmv #include <sys/time.h>
     32      1.1  jmmv #include <sys/stat.h>
     33      1.1  jmmv #include <sys/wait.h>
     34      1.1  jmmv 
     35      1.1  jmmv #include <errno.h>
     36      1.1  jmmv #include <fcntl.h>
     37      1.1  jmmv #include <limits.h>
     38      1.1  jmmv #include <stdarg.h>
     39      1.1  jmmv #include <stdbool.h>
     40      1.1  jmmv #include <stdio.h>
     41      1.1  jmmv #include <stdlib.h>
     42      1.1  jmmv #include <string.h>
     43      1.1  jmmv #include <unistd.h>
     44      1.1  jmmv 
     45      1.1  jmmv #include "atf-c/config.h"
     46  1.1.1.2  jmmv #include "atf-c/defs.h"
     47      1.1  jmmv #include "atf-c/env.h"
     48      1.1  jmmv #include "atf-c/error.h"
     49      1.1  jmmv #include "atf-c/fs.h"
     50      1.1  jmmv #include "atf-c/process.h"
     51      1.1  jmmv #include "atf-c/sanity.h"
     52      1.1  jmmv #include "atf-c/signals.h"
     53      1.1  jmmv #include "atf-c/tc.h"
     54      1.1  jmmv #include "atf-c/tcr.h"
     55      1.1  jmmv #include "atf-c/text.h"
     56      1.1  jmmv #include "atf-c/user.h"
     57      1.1  jmmv 
     58      1.1  jmmv /* ---------------------------------------------------------------------
     59      1.1  jmmv  * Auxiliary types and functions.
     60      1.1  jmmv  * --------------------------------------------------------------------- */
     61      1.1  jmmv 
     62  1.1.1.2  jmmv struct child_data {
     63  1.1.1.2  jmmv     const atf_tc_t *tc;
     64  1.1.1.2  jmmv     const atf_fs_path_t *workdir;
     65  1.1.1.2  jmmv };
     66  1.1.1.2  jmmv 
     67      1.1  jmmv /* Parent-only stuff. */
     68      1.1  jmmv struct timeout_data;
     69      1.1  jmmv static atf_error_t body_parent(const atf_tc_t *, const atf_fs_path_t *,
     70  1.1.1.2  jmmv                                atf_process_child_t *, atf_tcr_t *);
     71  1.1.1.2  jmmv static atf_error_t cleanup_parent(const atf_tc_t *, atf_process_child_t *);
     72  1.1.1.2  jmmv static atf_error_t fork_body(const atf_tc_t *, int, int,
     73  1.1.1.2  jmmv                              const atf_fs_path_t *, atf_tcr_t *);
     74  1.1.1.2  jmmv static atf_error_t fork_cleanup(const atf_tc_t *, int, int,
     75  1.1.1.2  jmmv                                 const atf_fs_path_t *);
     76      1.1  jmmv static atf_error_t get_tc_result(const atf_fs_path_t *, atf_tcr_t *);
     77  1.1.1.2  jmmv static atf_error_t program_timeout(const atf_process_child_t *,
     78  1.1.1.2  jmmv                                    const atf_tc_t *, struct timeout_data *);
     79      1.1  jmmv static void unprogram_timeout(struct timeout_data *);
     80      1.1  jmmv static void sigalrm_handler(int);
     81      1.1  jmmv 
     82      1.1  jmmv /* Child-only stuff. */
     83  1.1.1.2  jmmv static void body_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
     84      1.1  jmmv static atf_error_t check_arch(const char *, void *);
     85      1.1  jmmv static atf_error_t check_config(const char *, void *);
     86      1.1  jmmv static atf_error_t check_machine(const char *, void *);
     87      1.1  jmmv static atf_error_t check_prog(const char *, void *);
     88      1.1  jmmv static atf_error_t check_prog_in_dir(const char *, void *);
     89      1.1  jmmv static atf_error_t check_requirements(const atf_tc_t *);
     90  1.1.1.2  jmmv static void cleanup_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
     91      1.1  jmmv static void fail_internal(const char *, int, const char *, const char *,
     92      1.1  jmmv                           const char *, va_list,
     93  1.1.1.2  jmmv                           void (*)(atf_dynstr_t *),
     94      1.1  jmmv                           void (*)(const char *, ...));
     95      1.1  jmmv static void fatal_atf_error(const char *, atf_error_t)
     96      1.1  jmmv             ATF_DEFS_ATTRIBUTE_NORETURN;
     97      1.1  jmmv static void fatal_libc_error(const char *, int)
     98      1.1  jmmv             ATF_DEFS_ATTRIBUTE_NORETURN;
     99  1.1.1.2  jmmv static atf_error_t prepare_child(const struct child_data *);
    100  1.1.1.2  jmmv static void tc_fail(atf_dynstr_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
    101  1.1.1.2  jmmv static void tc_fail_nonfatal(atf_dynstr_t *);
    102      1.1  jmmv static void write_tcr(const atf_tcr_t *);
    103      1.1  jmmv 
    104      1.1  jmmv /* ---------------------------------------------------------------------
    105      1.1  jmmv  * The "atf_tc" type.
    106      1.1  jmmv  * --------------------------------------------------------------------- */
    107      1.1  jmmv 
    108      1.1  jmmv /*
    109      1.1  jmmv  * Constructors/destructors.
    110      1.1  jmmv  */
    111      1.1  jmmv 
    112      1.1  jmmv atf_error_t
    113      1.1  jmmv atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
    114      1.1  jmmv             atf_tc_body_t body, atf_tc_cleanup_t cleanup,
    115      1.1  jmmv             const atf_map_t *config)
    116      1.1  jmmv {
    117      1.1  jmmv     atf_error_t err;
    118      1.1  jmmv 
    119      1.1  jmmv     atf_object_init(&tc->m_object);
    120      1.1  jmmv 
    121      1.1  jmmv     tc->m_ident = ident;
    122      1.1  jmmv     tc->m_head = head;
    123      1.1  jmmv     tc->m_body = body;
    124      1.1  jmmv     tc->m_cleanup = cleanup;
    125      1.1  jmmv     tc->m_config = config;
    126      1.1  jmmv 
    127      1.1  jmmv     err = atf_map_init(&tc->m_vars);
    128      1.1  jmmv     if (atf_is_error(err))
    129      1.1  jmmv         goto err_object;
    130      1.1  jmmv 
    131      1.1  jmmv     err = atf_tc_set_md_var(tc, "ident", ident);
    132      1.1  jmmv     if (atf_is_error(err))
    133      1.1  jmmv         goto err_map;
    134      1.1  jmmv 
    135      1.1  jmmv     err = atf_tc_set_md_var(tc, "timeout", "300");
    136      1.1  jmmv     if (atf_is_error(err))
    137      1.1  jmmv         goto err_map;
    138      1.1  jmmv 
    139      1.1  jmmv     /* XXX Should the head be able to return error codes? */
    140      1.1  jmmv     tc->m_head(tc);
    141      1.1  jmmv 
    142      1.1  jmmv     if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0)
    143      1.1  jmmv         atf_tc_fail("Test case head modified the read-only 'ident' "
    144      1.1  jmmv                     "property");
    145      1.1  jmmv 
    146      1.1  jmmv     INV(!atf_is_error(err));
    147      1.1  jmmv     return err;
    148      1.1  jmmv 
    149      1.1  jmmv err_map:
    150      1.1  jmmv     atf_map_fini(&tc->m_vars);
    151      1.1  jmmv err_object:
    152      1.1  jmmv     atf_object_fini(&tc->m_object);
    153      1.1  jmmv 
    154      1.1  jmmv     return err;
    155      1.1  jmmv }
    156      1.1  jmmv 
    157      1.1  jmmv atf_error_t
    158      1.1  jmmv atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
    159      1.1  jmmv                  const atf_map_t *config)
    160      1.1  jmmv {
    161      1.1  jmmv     return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
    162      1.1  jmmv                        pack->m_cleanup, config);
    163      1.1  jmmv }
    164      1.1  jmmv 
    165      1.1  jmmv void
    166      1.1  jmmv atf_tc_fini(atf_tc_t *tc)
    167      1.1  jmmv {
    168      1.1  jmmv     atf_map_fini(&tc->m_vars);
    169      1.1  jmmv 
    170      1.1  jmmv     atf_object_fini(&tc->m_object);
    171      1.1  jmmv }
    172      1.1  jmmv 
    173      1.1  jmmv /*
    174      1.1  jmmv  * Getters.
    175      1.1  jmmv  */
    176      1.1  jmmv 
    177      1.1  jmmv const char *
    178      1.1  jmmv atf_tc_get_ident(const atf_tc_t *tc)
    179      1.1  jmmv {
    180      1.1  jmmv     return tc->m_ident;
    181      1.1  jmmv }
    182      1.1  jmmv 
    183      1.1  jmmv const char *
    184      1.1  jmmv atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
    185      1.1  jmmv {
    186      1.1  jmmv     const char *val;
    187      1.1  jmmv     atf_map_citer_t iter;
    188      1.1  jmmv 
    189      1.1  jmmv     PRE(atf_tc_has_config_var(tc, name));
    190      1.1  jmmv     iter = atf_map_find_c(tc->m_config, name);
    191      1.1  jmmv     val = atf_map_citer_data(iter);
    192      1.1  jmmv     INV(val != NULL);
    193      1.1  jmmv 
    194      1.1  jmmv     return val;
    195      1.1  jmmv }
    196      1.1  jmmv 
    197      1.1  jmmv const char *
    198      1.1  jmmv atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
    199      1.1  jmmv                          const char *defval)
    200      1.1  jmmv {
    201      1.1  jmmv     const char *val;
    202      1.1  jmmv 
    203      1.1  jmmv     if (!atf_tc_has_config_var(tc, name))
    204      1.1  jmmv         val = defval;
    205      1.1  jmmv     else
    206      1.1  jmmv         val = atf_tc_get_config_var(tc, name);
    207      1.1  jmmv 
    208      1.1  jmmv     return val;
    209      1.1  jmmv }
    210      1.1  jmmv 
    211      1.1  jmmv const char *
    212      1.1  jmmv atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
    213      1.1  jmmv {
    214      1.1  jmmv     const char *val;
    215      1.1  jmmv     atf_map_citer_t iter;
    216      1.1  jmmv 
    217      1.1  jmmv     PRE(atf_tc_has_md_var(tc, name));
    218      1.1  jmmv     iter = atf_map_find_c(&tc->m_vars, name);
    219      1.1  jmmv     val = atf_map_citer_data(iter);
    220      1.1  jmmv     INV(val != NULL);
    221      1.1  jmmv 
    222      1.1  jmmv     return val;
    223      1.1  jmmv }
    224      1.1  jmmv 
    225      1.1  jmmv bool
    226      1.1  jmmv atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
    227      1.1  jmmv {
    228      1.1  jmmv     bool found;
    229      1.1  jmmv     atf_map_citer_t end, iter;
    230      1.1  jmmv 
    231      1.1  jmmv     if (tc->m_config == NULL)
    232      1.1  jmmv         found = false;
    233      1.1  jmmv     else {
    234      1.1  jmmv         iter = atf_map_find_c(tc->m_config, name);
    235      1.1  jmmv         end = atf_map_end_c(tc->m_config);
    236      1.1  jmmv         found = !atf_equal_map_citer_map_citer(iter, end);
    237      1.1  jmmv     }
    238      1.1  jmmv 
    239      1.1  jmmv     return found;
    240      1.1  jmmv }
    241      1.1  jmmv 
    242      1.1  jmmv bool
    243      1.1  jmmv atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
    244      1.1  jmmv {
    245      1.1  jmmv     atf_map_citer_t end, iter;
    246      1.1  jmmv 
    247      1.1  jmmv     iter = atf_map_find_c(&tc->m_vars, name);
    248      1.1  jmmv     end = atf_map_end_c(&tc->m_vars);
    249      1.1  jmmv     return !atf_equal_map_citer_map_citer(iter, end);
    250      1.1  jmmv }
    251      1.1  jmmv 
    252      1.1  jmmv /*
    253      1.1  jmmv  * Modifiers.
    254      1.1  jmmv  */
    255      1.1  jmmv 
    256      1.1  jmmv atf_error_t
    257      1.1  jmmv atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
    258      1.1  jmmv {
    259      1.1  jmmv     atf_error_t err;
    260      1.1  jmmv     char *value;
    261      1.1  jmmv     va_list ap;
    262      1.1  jmmv 
    263      1.1  jmmv     va_start(ap, fmt);
    264      1.1  jmmv     err = atf_text_format_ap(&value, fmt, ap);
    265      1.1  jmmv     va_end(ap);
    266      1.1  jmmv 
    267      1.1  jmmv     if (!atf_is_error(err))
    268      1.1  jmmv         err = atf_map_insert(&tc->m_vars, name, value, true);
    269      1.1  jmmv     else
    270      1.1  jmmv         free(value);
    271      1.1  jmmv 
    272      1.1  jmmv     return err;
    273      1.1  jmmv }
    274      1.1  jmmv 
    275      1.1  jmmv /* ---------------------------------------------------------------------
    276      1.1  jmmv  * Free functions.
    277      1.1  jmmv  * --------------------------------------------------------------------- */
    278      1.1  jmmv 
    279      1.1  jmmv atf_error_t
    280  1.1.1.2  jmmv atf_tc_run(const atf_tc_t *tc, atf_tcr_t *tcr, int fdout, int fderr,
    281      1.1  jmmv            const atf_fs_path_t *workdirbase)
    282      1.1  jmmv {
    283      1.1  jmmv     atf_error_t err, cleanuperr;
    284      1.1  jmmv     atf_fs_path_t workdir;
    285      1.1  jmmv 
    286      1.1  jmmv     err = atf_fs_path_copy(&workdir, workdirbase);
    287      1.1  jmmv     if (atf_is_error(err))
    288      1.1  jmmv         goto out;
    289      1.1  jmmv 
    290      1.1  jmmv     err = atf_fs_path_append_fmt(&workdir, "atf.XXXXXX");
    291      1.1  jmmv     if (atf_is_error(err))
    292      1.1  jmmv         goto out_workdir;
    293      1.1  jmmv 
    294      1.1  jmmv     err = atf_fs_mkdtemp(&workdir);
    295      1.1  jmmv     if (atf_is_error(err))
    296      1.1  jmmv         goto out_workdir;
    297      1.1  jmmv 
    298  1.1.1.2  jmmv     err = fork_body(tc, fdout, fderr, &workdir, tcr);
    299  1.1.1.2  jmmv     cleanuperr = fork_cleanup(tc, fdout, fderr, &workdir);
    300      1.1  jmmv     if (!atf_is_error(cleanuperr))
    301      1.1  jmmv         (void)atf_fs_cleanup(&workdir);
    302      1.1  jmmv     if (!atf_is_error(err))
    303      1.1  jmmv         err = cleanuperr;
    304      1.1  jmmv     else if (atf_is_error(cleanuperr))
    305      1.1  jmmv         atf_error_free(cleanuperr);
    306      1.1  jmmv 
    307      1.1  jmmv out_workdir:
    308      1.1  jmmv     atf_fs_path_fini(&workdir);
    309      1.1  jmmv out:
    310      1.1  jmmv     return err;
    311      1.1  jmmv }
    312      1.1  jmmv 
    313      1.1  jmmv /*
    314      1.1  jmmv  * Parent-only stuff.
    315      1.1  jmmv  */
    316      1.1  jmmv 
    317      1.1  jmmv static bool sigalrm_killed = false;
    318      1.1  jmmv static pid_t sigalrm_pid = -1;
    319      1.1  jmmv 
    320      1.1  jmmv static
    321      1.1  jmmv void
    322      1.1  jmmv sigalrm_handler(int signo)
    323      1.1  jmmv {
    324      1.1  jmmv     INV(signo == SIGALRM);
    325      1.1  jmmv 
    326      1.1  jmmv     if (sigalrm_pid != -1) {
    327      1.1  jmmv         killpg(sigalrm_pid, SIGTERM);
    328      1.1  jmmv         sigalrm_killed = true;
    329      1.1  jmmv     }
    330      1.1  jmmv }
    331      1.1  jmmv 
    332      1.1  jmmv struct timeout_data {
    333      1.1  jmmv     bool m_programmed;
    334      1.1  jmmv     atf_signal_programmer_t m_sigalrm;
    335      1.1  jmmv };
    336      1.1  jmmv 
    337      1.1  jmmv static
    338      1.1  jmmv atf_error_t
    339  1.1.1.2  jmmv program_timeout(const atf_process_child_t *child, const atf_tc_t *tc,
    340  1.1.1.2  jmmv                 struct timeout_data *td)
    341      1.1  jmmv {
    342      1.1  jmmv     atf_error_t err;
    343      1.1  jmmv     long timeout;
    344      1.1  jmmv 
    345      1.1  jmmv     err = atf_text_to_long(atf_tc_get_md_var(tc, "timeout"), &timeout);
    346      1.1  jmmv     if (atf_is_error(err))
    347      1.1  jmmv         goto out;
    348      1.1  jmmv 
    349      1.1  jmmv     if (timeout != 0) {
    350  1.1.1.2  jmmv         sigalrm_pid = atf_process_child_pid(child);
    351      1.1  jmmv         sigalrm_killed = false;
    352      1.1  jmmv 
    353      1.1  jmmv         err = atf_signal_programmer_init(&td->m_sigalrm, SIGALRM,
    354      1.1  jmmv                                          sigalrm_handler);
    355      1.1  jmmv         if (atf_is_error(err))
    356      1.1  jmmv             goto out;
    357      1.1  jmmv 
    358      1.1  jmmv         struct itimerval itv;
    359      1.1  jmmv         timerclear(&itv.it_interval);
    360      1.1  jmmv         timerclear(&itv.it_value);
    361      1.1  jmmv         itv.it_value.tv_sec = timeout;
    362      1.1  jmmv         if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
    363      1.1  jmmv             atf_signal_programmer_fini(&td->m_sigalrm);
    364      1.1  jmmv             err = atf_libc_error(errno, "Failed to program timeout "
    365      1.1  jmmv                                  "with %ld seconds", timeout);
    366      1.1  jmmv         }
    367      1.1  jmmv 
    368      1.1  jmmv         td->m_programmed = !atf_is_error(err);
    369      1.1  jmmv     } else
    370      1.1  jmmv         td->m_programmed = false;
    371      1.1  jmmv 
    372      1.1  jmmv out:
    373      1.1  jmmv     return err;
    374      1.1  jmmv }
    375      1.1  jmmv 
    376      1.1  jmmv static
    377      1.1  jmmv void
    378      1.1  jmmv unprogram_timeout(struct timeout_data *td)
    379      1.1  jmmv {
    380      1.1  jmmv     if (td->m_programmed) {
    381      1.1  jmmv         atf_signal_programmer_fini(&td->m_sigalrm);
    382      1.1  jmmv         sigalrm_pid = -1;
    383      1.1  jmmv         sigalrm_killed = false;
    384      1.1  jmmv     }
    385      1.1  jmmv }
    386      1.1  jmmv 
    387      1.1  jmmv static
    388      1.1  jmmv atf_error_t
    389  1.1.1.2  jmmv body_parent(const atf_tc_t *tc, const atf_fs_path_t *workdir,
    390  1.1.1.2  jmmv             atf_process_child_t *child, atf_tcr_t *tcr)
    391      1.1  jmmv {
    392      1.1  jmmv     atf_error_t err;
    393  1.1.1.2  jmmv     atf_process_status_t status;
    394      1.1  jmmv     struct timeout_data td;
    395      1.1  jmmv 
    396  1.1.1.2  jmmv     err = program_timeout(child, tc, &td);
    397      1.1  jmmv     if (atf_is_error(err)) {
    398      1.1  jmmv         char buf[4096];
    399      1.1  jmmv 
    400      1.1  jmmv         atf_error_format(err, buf, sizeof(buf));
    401      1.1  jmmv         fprintf(stderr, "Error programming test case's timeout: %s", buf);
    402      1.1  jmmv         atf_error_free(err);
    403  1.1.1.2  jmmv         killpg(atf_process_child_pid(child), SIGKILL);
    404      1.1  jmmv     }
    405      1.1  jmmv 
    406  1.1.1.2  jmmv again:
    407  1.1.1.2  jmmv     err = atf_process_child_wait(child, &status);
    408  1.1.1.2  jmmv     if (atf_is_error(err)) {
    409  1.1.1.2  jmmv         if (atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR) {
    410  1.1.1.2  jmmv             atf_error_free(err);
    411  1.1.1.2  jmmv             goto again;
    412  1.1.1.2  jmmv         } else {
    413  1.1.1.2  jmmv             /* Propagate err */
    414  1.1.1.2  jmmv         }
    415  1.1.1.2  jmmv     } else {
    416  1.1.1.2  jmmv         if (sigalrm_killed)
    417      1.1  jmmv             err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
    418      1.1  jmmv                                           "Test case timed out after %s "
    419      1.1  jmmv                                           "seconds",
    420      1.1  jmmv                                           atf_tc_get_md_var(tc, "timeout"));
    421  1.1.1.2  jmmv         else {
    422  1.1.1.2  jmmv             if (atf_process_status_exited(&status)) {
    423  1.1.1.2  jmmv                 const int exitstatus = atf_process_status_exitstatus(&status);
    424  1.1.1.2  jmmv                 if (exitstatus == EXIT_SUCCESS)
    425  1.1.1.2  jmmv                     err = get_tc_result(workdir, tcr);
    426  1.1.1.2  jmmv                 else
    427  1.1.1.2  jmmv                     err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
    428  1.1.1.2  jmmv                                                   "Test case exited with "
    429  1.1.1.2  jmmv                                                   "status %d", exitstatus);
    430  1.1.1.2  jmmv             } else if (atf_process_status_signaled(&status)) {
    431  1.1.1.2  jmmv                 const int sig = atf_process_status_termsig(&status);
    432  1.1.1.2  jmmv                 const bool wcore = atf_process_status_coredump(&status);
    433  1.1.1.2  jmmv                 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
    434  1.1.1.2  jmmv                                               "Test case was signaled by "
    435  1.1.1.2  jmmv                                               "signal %d%s", sig,
    436  1.1.1.2  jmmv                                               wcore ? " (core dumped)" : "");
    437  1.1.1.2  jmmv             } else {
    438  1.1.1.2  jmmv                 err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
    439  1.1.1.2  jmmv                                               "Test case exited due to an "
    440  1.1.1.2  jmmv                                               "unexpected condition");
    441  1.1.1.2  jmmv             }
    442  1.1.1.2  jmmv         }
    443  1.1.1.2  jmmv 
    444  1.1.1.2  jmmv         atf_process_status_fini(&status);
    445      1.1  jmmv     }
    446      1.1  jmmv 
    447      1.1  jmmv     unprogram_timeout(&td);
    448      1.1  jmmv 
    449      1.1  jmmv     return err;
    450      1.1  jmmv }
    451      1.1  jmmv 
    452      1.1  jmmv static
    453      1.1  jmmv atf_error_t
    454  1.1.1.2  jmmv cleanup_parent(const atf_tc_t *tc, atf_process_child_t *child)
    455      1.1  jmmv {
    456      1.1  jmmv     atf_error_t err;
    457  1.1.1.2  jmmv     atf_process_status_t status;
    458      1.1  jmmv 
    459  1.1.1.2  jmmv     err = atf_process_child_wait(child, &status);
    460  1.1.1.2  jmmv     if (atf_is_error(err))
    461      1.1  jmmv         goto out;
    462      1.1  jmmv 
    463  1.1.1.2  jmmv     if (!atf_process_status_exited(&status) ||
    464  1.1.1.2  jmmv         atf_process_status_exitstatus(&status) != EXIT_SUCCESS) {
    465      1.1  jmmv         /* XXX Not really a libc error. */
    466      1.1  jmmv         err = atf_libc_error(EINVAL, "Child process did not exit cleanly");
    467  1.1.1.2  jmmv     } else
    468      1.1  jmmv         err = atf_no_error();
    469      1.1  jmmv 
    470  1.1.1.2  jmmv     atf_process_status_fini(&status);
    471      1.1  jmmv out:
    472      1.1  jmmv     return err;
    473      1.1  jmmv }
    474      1.1  jmmv 
    475      1.1  jmmv static
    476      1.1  jmmv atf_error_t
    477  1.1.1.2  jmmv fork_body(const atf_tc_t *tc, int fdout, int fderr,
    478  1.1.1.2  jmmv           const atf_fs_path_t *workdir, atf_tcr_t *tcr)
    479      1.1  jmmv {
    480      1.1  jmmv     atf_error_t err;
    481  1.1.1.2  jmmv     atf_process_stream_t outsb, errsb;
    482  1.1.1.2  jmmv     atf_process_child_t child;
    483  1.1.1.2  jmmv     struct child_data data = {
    484  1.1.1.2  jmmv         tc,
    485  1.1.1.2  jmmv         workdir,
    486  1.1.1.2  jmmv     };
    487      1.1  jmmv 
    488  1.1.1.2  jmmv     err = atf_process_stream_init_redirect_fd(&outsb, fdout);
    489      1.1  jmmv     if (atf_is_error(err))
    490      1.1  jmmv         goto out;
    491      1.1  jmmv 
    492  1.1.1.2  jmmv     err = atf_process_stream_init_redirect_fd(&errsb, fderr);
    493  1.1.1.2  jmmv     if (atf_is_error(err))
    494  1.1.1.2  jmmv         goto out_outsb;
    495  1.1.1.2  jmmv 
    496  1.1.1.2  jmmv     err = atf_process_fork(&child, body_child, &outsb, &errsb, &data);
    497  1.1.1.2  jmmv     if (atf_is_error(err))
    498  1.1.1.2  jmmv         goto out_errsb;
    499      1.1  jmmv 
    500  1.1.1.2  jmmv     err = body_parent(tc, workdir, &child, tcr);
    501  1.1.1.2  jmmv 
    502  1.1.1.2  jmmv out_errsb:
    503  1.1.1.2  jmmv     atf_process_stream_fini(&errsb);
    504  1.1.1.2  jmmv out_outsb:
    505  1.1.1.2  jmmv     atf_process_stream_fini(&outsb);
    506      1.1  jmmv out:
    507      1.1  jmmv     return err;
    508      1.1  jmmv }
    509      1.1  jmmv 
    510      1.1  jmmv static
    511      1.1  jmmv atf_error_t
    512  1.1.1.2  jmmv fork_cleanup(const atf_tc_t *tc, int fdout, int fderr,
    513  1.1.1.2  jmmv              const atf_fs_path_t *workdir)
    514      1.1  jmmv {
    515      1.1  jmmv     atf_error_t err;
    516      1.1  jmmv 
    517      1.1  jmmv     if (tc->m_cleanup == NULL)
    518      1.1  jmmv         err = atf_no_error();
    519      1.1  jmmv     else {
    520  1.1.1.2  jmmv         atf_process_stream_t outsb, errsb;
    521  1.1.1.2  jmmv         atf_process_child_t child;
    522  1.1.1.2  jmmv         struct child_data data = {
    523  1.1.1.2  jmmv             tc,
    524  1.1.1.2  jmmv             workdir,
    525  1.1.1.2  jmmv         };
    526  1.1.1.2  jmmv 
    527  1.1.1.2  jmmv         err = atf_process_stream_init_redirect_fd(&outsb, fdout);
    528      1.1  jmmv         if (atf_is_error(err))
    529      1.1  jmmv             goto out;
    530      1.1  jmmv 
    531  1.1.1.2  jmmv         err = atf_process_stream_init_redirect_fd(&errsb, fderr);
    532  1.1.1.2  jmmv         if (atf_is_error(err))
    533  1.1.1.2  jmmv             goto out_outsb;
    534  1.1.1.2  jmmv 
    535  1.1.1.2  jmmv         err = atf_process_fork(&child, cleanup_child, &outsb, &errsb, &data);
    536  1.1.1.2  jmmv         if (atf_is_error(err))
    537  1.1.1.2  jmmv             goto out_errsb;
    538  1.1.1.2  jmmv 
    539  1.1.1.2  jmmv         err = cleanup_parent(tc, &child);
    540  1.1.1.2  jmmv 
    541  1.1.1.2  jmmv out_errsb:
    542  1.1.1.2  jmmv         atf_process_stream_fini(&errsb);
    543  1.1.1.2  jmmv out_outsb:
    544  1.1.1.2  jmmv         atf_process_stream_fini(&outsb);
    545      1.1  jmmv     }
    546      1.1  jmmv 
    547      1.1  jmmv out:
    548      1.1  jmmv     return err;
    549      1.1  jmmv }
    550      1.1  jmmv 
    551      1.1  jmmv static
    552      1.1  jmmv atf_error_t
    553      1.1  jmmv get_tc_result(const atf_fs_path_t *workdir, atf_tcr_t *tcr)
    554      1.1  jmmv {
    555      1.1  jmmv     atf_error_t err;
    556      1.1  jmmv     int fd;
    557      1.1  jmmv     atf_fs_path_t tcrfile;
    558      1.1  jmmv 
    559      1.1  jmmv     err = atf_fs_path_copy(&tcrfile, workdir);
    560      1.1  jmmv     if (atf_is_error(err))
    561      1.1  jmmv         goto out;
    562      1.1  jmmv 
    563      1.1  jmmv     err = atf_fs_path_append_fmt(&tcrfile, "tc-result");
    564      1.1  jmmv     if (atf_is_error(err))
    565      1.1  jmmv         goto out_tcrfile;
    566      1.1  jmmv 
    567      1.1  jmmv     fd = open(atf_fs_path_cstring(&tcrfile), O_RDONLY);
    568      1.1  jmmv     if (fd == -1) {
    569      1.1  jmmv         err = atf_libc_error(errno, "Cannot retrieve test case result");
    570      1.1  jmmv         goto out_tcrfile;
    571      1.1  jmmv     }
    572      1.1  jmmv 
    573      1.1  jmmv     err = atf_tcr_deserialize(tcr, fd);
    574      1.1  jmmv 
    575      1.1  jmmv     close(fd);
    576      1.1  jmmv out_tcrfile:
    577      1.1  jmmv     atf_fs_path_fini(&tcrfile);
    578      1.1  jmmv out:
    579      1.1  jmmv     return err;
    580      1.1  jmmv }
    581      1.1  jmmv 
    582      1.1  jmmv /*
    583      1.1  jmmv  * Child-only stuff.
    584      1.1  jmmv  */
    585      1.1  jmmv 
    586      1.1  jmmv static const atf_tc_t *current_tc = NULL;
    587      1.1  jmmv static const atf_fs_path_t *current_workdir = NULL;
    588      1.1  jmmv static size_t current_tc_fail_count = 0;
    589      1.1  jmmv 
    590      1.1  jmmv static
    591      1.1  jmmv atf_error_t
    592  1.1.1.2  jmmv prepare_child(const struct child_data *cd)
    593      1.1  jmmv {
    594      1.1  jmmv     atf_error_t err;
    595      1.1  jmmv     int i, ret;
    596      1.1  jmmv 
    597  1.1.1.2  jmmv     current_tc = cd->tc;
    598  1.1.1.2  jmmv     current_workdir = cd->workdir;
    599      1.1  jmmv     current_tc_fail_count = 0;
    600      1.1  jmmv 
    601      1.1  jmmv     ret = setpgid(getpid(), 0);
    602      1.1  jmmv     INV(ret != -1);
    603      1.1  jmmv 
    604      1.1  jmmv     umask(S_IWGRP | S_IWOTH);
    605      1.1  jmmv 
    606      1.1  jmmv     for (i = 1; i <= atf_signals_last_signo; i++)
    607      1.1  jmmv         atf_signal_reset(i);
    608      1.1  jmmv 
    609  1.1.1.2  jmmv     err = atf_env_set("HOME", atf_fs_path_cstring(cd->workdir));
    610      1.1  jmmv     if (atf_is_error(err))
    611      1.1  jmmv         goto out;
    612      1.1  jmmv 
    613      1.1  jmmv     err = atf_env_unset("LANG");
    614      1.1  jmmv     if (atf_is_error(err))
    615      1.1  jmmv         goto out;
    616      1.1  jmmv 
    617      1.1  jmmv     err = atf_env_unset("LC_ALL");
    618      1.1  jmmv     if (atf_is_error(err))
    619      1.1  jmmv         goto out;
    620      1.1  jmmv 
    621      1.1  jmmv     err = atf_env_unset("LC_COLLATE");
    622      1.1  jmmv     if (atf_is_error(err))
    623      1.1  jmmv         goto out;
    624      1.1  jmmv 
    625      1.1  jmmv     err = atf_env_unset("LC_CTYPE");
    626      1.1  jmmv     if (atf_is_error(err))
    627      1.1  jmmv         goto out;
    628      1.1  jmmv 
    629      1.1  jmmv     err = atf_env_unset("LC_MESSAGES");
    630      1.1  jmmv     if (atf_is_error(err))
    631      1.1  jmmv         goto out;
    632      1.1  jmmv 
    633      1.1  jmmv     err = atf_env_unset("LC_MONETARY");
    634      1.1  jmmv     if (atf_is_error(err))
    635      1.1  jmmv         goto out;
    636      1.1  jmmv 
    637      1.1  jmmv     err = atf_env_unset("LC_NUMERIC");
    638      1.1  jmmv     if (atf_is_error(err))
    639      1.1  jmmv         goto out;
    640      1.1  jmmv 
    641      1.1  jmmv     err = atf_env_unset("LC_TIME");
    642      1.1  jmmv     if (atf_is_error(err))
    643      1.1  jmmv         goto out;
    644      1.1  jmmv 
    645      1.1  jmmv     err = atf_env_unset("TZ");
    646      1.1  jmmv     if (atf_is_error(err))
    647      1.1  jmmv         goto out;
    648      1.1  jmmv 
    649  1.1.1.2  jmmv     if (chdir(atf_fs_path_cstring(cd->workdir)) == -1) {
    650      1.1  jmmv         err = atf_libc_error(errno, "Cannot enter work directory '%s'",
    651  1.1.1.2  jmmv                              atf_fs_path_cstring(cd->workdir));
    652      1.1  jmmv         goto out;
    653      1.1  jmmv     }
    654      1.1  jmmv 
    655      1.1  jmmv     err = atf_no_error();
    656      1.1  jmmv 
    657      1.1  jmmv out:
    658      1.1  jmmv     return err;
    659      1.1  jmmv }
    660      1.1  jmmv 
    661      1.1  jmmv static
    662      1.1  jmmv void
    663  1.1.1.2  jmmv body_child(void *v)
    664      1.1  jmmv {
    665  1.1.1.2  jmmv     const struct child_data *cd = v;
    666      1.1  jmmv     atf_error_t err;
    667      1.1  jmmv 
    668  1.1.1.2  jmmv     atf_reset_exit_checks();
    669      1.1  jmmv 
    670  1.1.1.2  jmmv     err = prepare_child(cd);
    671      1.1  jmmv     if (atf_is_error(err))
    672      1.1  jmmv         goto print_err;
    673  1.1.1.2  jmmv     err = check_requirements(cd->tc);
    674      1.1  jmmv     if (atf_is_error(err))
    675      1.1  jmmv         goto print_err;
    676  1.1.1.2  jmmv 
    677  1.1.1.2  jmmv     cd->tc->m_body(cd->tc);
    678      1.1  jmmv 
    679      1.1  jmmv     if (current_tc_fail_count == 0)
    680      1.1  jmmv         atf_tc_pass();
    681      1.1  jmmv     else
    682      1.1  jmmv         atf_tc_fail("%d checks failed; see output for more details",
    683      1.1  jmmv                     current_tc_fail_count);
    684      1.1  jmmv 
    685      1.1  jmmv     UNREACHABLE;
    686      1.1  jmmv 
    687      1.1  jmmv print_err:
    688      1.1  jmmv     INV(atf_is_error(err));
    689      1.1  jmmv     {
    690      1.1  jmmv         char buf[4096];
    691      1.1  jmmv 
    692      1.1  jmmv         atf_error_format(err, buf, sizeof(buf));
    693      1.1  jmmv         atf_error_free(err);
    694      1.1  jmmv 
    695      1.1  jmmv         atf_tc_fail("Error while preparing child process: %s", buf);
    696      1.1  jmmv     }
    697      1.1  jmmv 
    698      1.1  jmmv     UNREACHABLE;
    699      1.1  jmmv }
    700      1.1  jmmv 
    701      1.1  jmmv static
    702      1.1  jmmv atf_error_t
    703      1.1  jmmv check_arch(const char *arch, void *data)
    704      1.1  jmmv {
    705      1.1  jmmv     bool *found = data;
    706      1.1  jmmv 
    707      1.1  jmmv     if (strcmp(arch, atf_config_get("atf_arch")) == 0)
    708      1.1  jmmv         *found = true;
    709      1.1  jmmv 
    710      1.1  jmmv     return atf_no_error();
    711      1.1  jmmv }
    712      1.1  jmmv 
    713      1.1  jmmv static
    714      1.1  jmmv atf_error_t
    715      1.1  jmmv check_config(const char *var, void *data)
    716      1.1  jmmv {
    717      1.1  jmmv     if (!atf_tc_has_config_var(current_tc, var))
    718      1.1  jmmv         atf_tc_skip("Required configuration variable %s not defined", var);
    719      1.1  jmmv 
    720      1.1  jmmv     return atf_no_error();
    721      1.1  jmmv }
    722      1.1  jmmv 
    723      1.1  jmmv static
    724      1.1  jmmv atf_error_t
    725      1.1  jmmv check_machine(const char *machine, void *data)
    726      1.1  jmmv {
    727      1.1  jmmv     bool *found = data;
    728      1.1  jmmv 
    729      1.1  jmmv     if (strcmp(machine, atf_config_get("atf_machine")) == 0)
    730      1.1  jmmv         *found = true;
    731      1.1  jmmv 
    732      1.1  jmmv     return atf_no_error();
    733      1.1  jmmv }
    734      1.1  jmmv 
    735      1.1  jmmv struct prog_found_pair {
    736      1.1  jmmv     const char *prog;
    737      1.1  jmmv     bool found;
    738      1.1  jmmv };
    739      1.1  jmmv 
    740      1.1  jmmv static
    741      1.1  jmmv atf_error_t
    742      1.1  jmmv check_prog(const char *prog, void *data)
    743      1.1  jmmv {
    744      1.1  jmmv     atf_error_t err;
    745      1.1  jmmv     atf_fs_path_t p;
    746      1.1  jmmv 
    747      1.1  jmmv     err = atf_fs_path_init_fmt(&p, "%s", prog);
    748      1.1  jmmv     if (atf_is_error(err))
    749      1.1  jmmv         goto out;
    750      1.1  jmmv 
    751      1.1  jmmv     if (atf_fs_path_is_absolute(&p)) {
    752  1.1.1.2  jmmv         err = atf_fs_eaccess(&p, atf_fs_access_x);
    753  1.1.1.2  jmmv         if (atf_is_error(err)) {
    754  1.1.1.2  jmmv             atf_error_free(err);
    755  1.1.1.2  jmmv             atf_fs_path_fini(&p);
    756      1.1  jmmv             atf_tc_skip("The required program %s could not be found", prog);
    757  1.1.1.2  jmmv         }
    758      1.1  jmmv     } else {
    759      1.1  jmmv         const char *path = atf_env_get("PATH");
    760      1.1  jmmv         struct prog_found_pair pf;
    761      1.1  jmmv         atf_fs_path_t bp;
    762      1.1  jmmv 
    763      1.1  jmmv         err = atf_fs_path_branch_path(&p, &bp);
    764      1.1  jmmv         if (atf_is_error(err))
    765      1.1  jmmv             goto out_p;
    766      1.1  jmmv 
    767  1.1.1.2  jmmv         if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
    768  1.1.1.2  jmmv             atf_fs_path_fini(&bp);
    769  1.1.1.2  jmmv             atf_fs_path_fini(&p);
    770      1.1  jmmv             atf_tc_fail("Relative paths are not allowed when searching for "
    771      1.1  jmmv                         "a program (%s)", prog);
    772  1.1.1.2  jmmv         }
    773      1.1  jmmv 
    774      1.1  jmmv         pf.prog = prog;
    775      1.1  jmmv         pf.found = false;
    776      1.1  jmmv         err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
    777      1.1  jmmv         if (atf_is_error(err))
    778      1.1  jmmv             goto out_bp;
    779      1.1  jmmv 
    780  1.1.1.2  jmmv         if (!pf.found) {
    781  1.1.1.2  jmmv             atf_fs_path_fini(&bp);
    782  1.1.1.2  jmmv             atf_fs_path_fini(&p);
    783      1.1  jmmv             atf_tc_skip("The required program %s could not be found in "
    784      1.1  jmmv                         "the PATH", prog);
    785  1.1.1.2  jmmv         }
    786      1.1  jmmv 
    787      1.1  jmmv out_bp:
    788      1.1  jmmv         atf_fs_path_fini(&bp);
    789      1.1  jmmv     }
    790      1.1  jmmv 
    791      1.1  jmmv out_p:
    792      1.1  jmmv     atf_fs_path_fini(&p);
    793      1.1  jmmv out:
    794      1.1  jmmv     return err;
    795      1.1  jmmv }
    796      1.1  jmmv 
    797      1.1  jmmv static
    798      1.1  jmmv atf_error_t
    799      1.1  jmmv check_prog_in_dir(const char *dir, void *data)
    800      1.1  jmmv {
    801      1.1  jmmv     struct prog_found_pair *pf = data;
    802      1.1  jmmv     atf_error_t err;
    803      1.1  jmmv 
    804      1.1  jmmv     if (pf->found)
    805      1.1  jmmv         err = atf_no_error();
    806      1.1  jmmv     else {
    807      1.1  jmmv         atf_fs_path_t p;
    808      1.1  jmmv 
    809      1.1  jmmv         err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
    810      1.1  jmmv         if (atf_is_error(err))
    811      1.1  jmmv             goto out_p;
    812      1.1  jmmv 
    813  1.1.1.2  jmmv         err = atf_fs_eaccess(&p, atf_fs_access_x);
    814  1.1.1.2  jmmv         if (!atf_is_error(err))
    815      1.1  jmmv             pf->found = true;
    816  1.1.1.2  jmmv         else {
    817  1.1.1.2  jmmv             atf_error_free(err);
    818  1.1.1.2  jmmv             INV(!pf->found);
    819  1.1.1.2  jmmv             err = atf_no_error();
    820  1.1.1.2  jmmv         }
    821      1.1  jmmv 
    822      1.1  jmmv out_p:
    823      1.1  jmmv         atf_fs_path_fini(&p);
    824      1.1  jmmv     }
    825      1.1  jmmv 
    826      1.1  jmmv     return err;
    827      1.1  jmmv }
    828      1.1  jmmv 
    829      1.1  jmmv static
    830      1.1  jmmv atf_error_t
    831      1.1  jmmv check_requirements(const atf_tc_t *tc)
    832      1.1  jmmv {
    833      1.1  jmmv     atf_error_t err;
    834      1.1  jmmv 
    835      1.1  jmmv     err = atf_no_error();
    836      1.1  jmmv 
    837      1.1  jmmv     if (atf_tc_has_md_var(tc, "require.arch")) {
    838      1.1  jmmv         const char *arches = atf_tc_get_md_var(tc, "require.arch");
    839      1.1  jmmv         bool found = false;
    840      1.1  jmmv 
    841      1.1  jmmv         if (strlen(arches) == 0)
    842      1.1  jmmv             atf_tc_fail("Invalid value in the require.arch property");
    843      1.1  jmmv         else {
    844      1.1  jmmv             err = atf_text_for_each_word(arches, " ", check_arch, &found);
    845      1.1  jmmv             if (atf_is_error(err))
    846      1.1  jmmv                 goto out;
    847      1.1  jmmv 
    848      1.1  jmmv             if (!found)
    849      1.1  jmmv                 atf_tc_skip("Requires one of the '%s' architectures",
    850      1.1  jmmv                             arches);
    851      1.1  jmmv         }
    852      1.1  jmmv     }
    853      1.1  jmmv 
    854      1.1  jmmv     if (atf_tc_has_md_var(tc, "require.config")) {
    855      1.1  jmmv         const char *vars = atf_tc_get_md_var(tc, "require.config");
    856      1.1  jmmv 
    857      1.1  jmmv         if (strlen(vars) == 0)
    858      1.1  jmmv             atf_tc_fail("Invalid value in the require.config property");
    859      1.1  jmmv         else {
    860      1.1  jmmv             err = atf_text_for_each_word(vars, " ", check_config, NULL);
    861      1.1  jmmv             if (atf_is_error(err))
    862      1.1  jmmv                 goto out;
    863      1.1  jmmv         }
    864      1.1  jmmv     }
    865      1.1  jmmv 
    866      1.1  jmmv     if (atf_tc_has_md_var(tc, "require.machine")) {
    867      1.1  jmmv         const char *machines = atf_tc_get_md_var(tc, "require.machine");
    868      1.1  jmmv         bool found = false;
    869      1.1  jmmv 
    870      1.1  jmmv         if (strlen(machines) == 0)
    871      1.1  jmmv             atf_tc_fail("Invalid value in the require.machine property");
    872      1.1  jmmv         else {
    873      1.1  jmmv             err = atf_text_for_each_word(machines, " ", check_machine,
    874      1.1  jmmv                                          &found);
    875      1.1  jmmv             if (atf_is_error(err))
    876      1.1  jmmv                 goto out;
    877      1.1  jmmv 
    878      1.1  jmmv             if (!found)
    879      1.1  jmmv                 atf_tc_skip("Requires one of the '%s' machine types",
    880      1.1  jmmv                             machines);
    881      1.1  jmmv         }
    882      1.1  jmmv     }
    883      1.1  jmmv 
    884      1.1  jmmv     if (atf_tc_has_md_var(tc, "require.progs")) {
    885      1.1  jmmv         const char *progs = atf_tc_get_md_var(tc, "require.progs");
    886      1.1  jmmv 
    887      1.1  jmmv         if (strlen(progs) == 0)
    888      1.1  jmmv             atf_tc_fail("Invalid value in the require.progs property");
    889      1.1  jmmv         else {
    890      1.1  jmmv             err = atf_text_for_each_word(progs, " ", check_prog, NULL);
    891      1.1  jmmv             if (atf_is_error(err))
    892      1.1  jmmv                 goto out;
    893      1.1  jmmv         }
    894      1.1  jmmv     }
    895      1.1  jmmv 
    896      1.1  jmmv     if (atf_tc_has_md_var(tc, "require.user")) {
    897      1.1  jmmv         const char *u = atf_tc_get_md_var(tc, "require.user");
    898      1.1  jmmv 
    899      1.1  jmmv         if (strcmp(u, "root") == 0) {
    900      1.1  jmmv             if (!atf_user_is_root())
    901      1.1  jmmv                 atf_tc_skip("Requires root privileges");
    902      1.1  jmmv         } else if (strcmp(u, "unprivileged") == 0) {
    903      1.1  jmmv             if (atf_user_is_root())
    904      1.1  jmmv                 atf_tc_skip("Requires an unprivileged user");
    905      1.1  jmmv         } else
    906      1.1  jmmv             atf_tc_fail("Invalid value in the require.user property");
    907      1.1  jmmv     }
    908      1.1  jmmv 
    909      1.1  jmmv     INV(!atf_is_error(err));
    910      1.1  jmmv out:
    911      1.1  jmmv     return err;
    912      1.1  jmmv }
    913      1.1  jmmv 
    914      1.1  jmmv static
    915      1.1  jmmv void
    916  1.1.1.2  jmmv cleanup_child(void *v)
    917      1.1  jmmv {
    918  1.1.1.2  jmmv     const struct child_data *cd = v;
    919      1.1  jmmv     atf_error_t err;
    920      1.1  jmmv 
    921  1.1.1.2  jmmv     err = prepare_child(cd);
    922  1.1.1.2  jmmv     if (atf_is_error(err)) {
    923  1.1.1.2  jmmv         atf_reset_exit_checks();
    924      1.1  jmmv         exit(EXIT_FAILURE);
    925  1.1.1.2  jmmv     } else {
    926  1.1.1.2  jmmv         atf_reset_exit_checks();
    927  1.1.1.2  jmmv         cd->tc->m_cleanup(cd->tc);
    928      1.1  jmmv         exit(EXIT_SUCCESS);
    929      1.1  jmmv     }
    930      1.1  jmmv 
    931      1.1  jmmv     UNREACHABLE;
    932      1.1  jmmv }
    933      1.1  jmmv 
    934      1.1  jmmv static
    935      1.1  jmmv void
    936      1.1  jmmv fatal_atf_error(const char *prefix, atf_error_t err)
    937      1.1  jmmv {
    938      1.1  jmmv     char buf[1024];
    939      1.1  jmmv 
    940      1.1  jmmv     INV(atf_is_error(err));
    941      1.1  jmmv 
    942      1.1  jmmv     atf_error_format(err, buf, sizeof(buf));
    943      1.1  jmmv     atf_error_free(err);
    944      1.1  jmmv 
    945      1.1  jmmv     fprintf(stderr, "%s: %s", prefix, buf);
    946      1.1  jmmv 
    947      1.1  jmmv     abort();
    948      1.1  jmmv }
    949      1.1  jmmv 
    950      1.1  jmmv static
    951      1.1  jmmv void
    952      1.1  jmmv fatal_libc_error(const char *prefix, int err)
    953      1.1  jmmv {
    954      1.1  jmmv     fprintf(stderr, "%s: %s", prefix, strerror(err));
    955      1.1  jmmv 
    956      1.1  jmmv     abort();
    957      1.1  jmmv }
    958      1.1  jmmv 
    959      1.1  jmmv static
    960      1.1  jmmv void
    961      1.1  jmmv write_tcr(const atf_tcr_t *tcr)
    962      1.1  jmmv {
    963      1.1  jmmv     atf_error_t err;
    964      1.1  jmmv     int fd;
    965      1.1  jmmv     atf_fs_path_t tcrfile;
    966      1.1  jmmv 
    967      1.1  jmmv     err = atf_fs_path_copy(&tcrfile, current_workdir);
    968      1.1  jmmv     if (atf_is_error(err))
    969      1.1  jmmv         fatal_atf_error("Cannot write test case results", err);
    970      1.1  jmmv 
    971      1.1  jmmv     err = atf_fs_path_append_fmt(&tcrfile, "tc-result");
    972      1.1  jmmv     if (atf_is_error(err))
    973      1.1  jmmv         fatal_atf_error("Cannot write test case results", err);
    974      1.1  jmmv 
    975      1.1  jmmv     fd = open(atf_fs_path_cstring(&tcrfile),
    976      1.1  jmmv               O_WRONLY | O_CREAT | O_TRUNC, 0755);
    977      1.1  jmmv     if (fd == -1)
    978      1.1  jmmv         fatal_libc_error("Cannot write test case results", errno);
    979      1.1  jmmv 
    980      1.1  jmmv     err = atf_tcr_serialize(tcr, fd);
    981      1.1  jmmv     if (atf_is_error(err))
    982      1.1  jmmv         fatal_atf_error("Cannot write test case results", err);
    983      1.1  jmmv 
    984      1.1  jmmv     close(fd);
    985  1.1.1.2  jmmv     atf_fs_path_fini(&tcrfile);
    986  1.1.1.2  jmmv }
    987  1.1.1.2  jmmv 
    988  1.1.1.2  jmmv static
    989  1.1.1.2  jmmv void
    990  1.1.1.2  jmmv tc_fail(atf_dynstr_t *msg)
    991  1.1.1.2  jmmv {
    992  1.1.1.2  jmmv     atf_tcr_t tcr;
    993  1.1.1.2  jmmv     atf_error_t err;
    994  1.1.1.2  jmmv 
    995  1.1.1.2  jmmv     PRE(current_tc != NULL);
    996  1.1.1.2  jmmv 
    997  1.1.1.2  jmmv     err = atf_tcr_init_reason_fmt(&tcr, atf_tcr_failed_state, "%s",
    998  1.1.1.2  jmmv                                   atf_dynstr_cstring(msg));
    999  1.1.1.2  jmmv     if (atf_is_error(err))
   1000  1.1.1.2  jmmv         abort();
   1001  1.1.1.2  jmmv 
   1002  1.1.1.2  jmmv     write_tcr(&tcr);
   1003  1.1.1.2  jmmv 
   1004  1.1.1.2  jmmv     atf_tcr_fini(&tcr);
   1005  1.1.1.2  jmmv     atf_dynstr_fini(msg);
   1006  1.1.1.2  jmmv 
   1007  1.1.1.2  jmmv     exit(EXIT_SUCCESS);
   1008  1.1.1.2  jmmv }
   1009  1.1.1.2  jmmv 
   1010  1.1.1.2  jmmv static
   1011  1.1.1.2  jmmv void
   1012  1.1.1.2  jmmv tc_fail_nonfatal(atf_dynstr_t *msg)
   1013  1.1.1.2  jmmv {
   1014  1.1.1.2  jmmv     fprintf(stderr, "%s\n", atf_dynstr_cstring(msg));
   1015  1.1.1.2  jmmv     atf_dynstr_fini(msg);
   1016  1.1.1.2  jmmv 
   1017  1.1.1.2  jmmv     current_tc_fail_count++;
   1018      1.1  jmmv }
   1019      1.1  jmmv 
   1020      1.1  jmmv void
   1021      1.1  jmmv atf_tc_fail(const char *fmt, ...)
   1022      1.1  jmmv {
   1023      1.1  jmmv     va_list ap;
   1024      1.1  jmmv     atf_tcr_t tcr;
   1025      1.1  jmmv     atf_error_t err;
   1026      1.1  jmmv 
   1027      1.1  jmmv     PRE(current_tc != NULL);
   1028      1.1  jmmv 
   1029      1.1  jmmv     va_start(ap, fmt);
   1030      1.1  jmmv     err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap);
   1031      1.1  jmmv     va_end(ap);
   1032      1.1  jmmv     if (atf_is_error(err))
   1033      1.1  jmmv         abort();
   1034      1.1  jmmv 
   1035      1.1  jmmv     write_tcr(&tcr);
   1036      1.1  jmmv 
   1037      1.1  jmmv     atf_tcr_fini(&tcr);
   1038      1.1  jmmv 
   1039      1.1  jmmv     exit(EXIT_SUCCESS);
   1040      1.1  jmmv }
   1041      1.1  jmmv 
   1042      1.1  jmmv void
   1043      1.1  jmmv atf_tc_fail_nonfatal(const char *fmt, ...)
   1044      1.1  jmmv {
   1045      1.1  jmmv     va_list ap;
   1046      1.1  jmmv 
   1047      1.1  jmmv     va_start(ap, fmt);
   1048      1.1  jmmv     vfprintf(stderr, fmt, ap);
   1049      1.1  jmmv     va_end(ap);
   1050      1.1  jmmv     fprintf(stderr, "\n");
   1051      1.1  jmmv 
   1052      1.1  jmmv     current_tc_fail_count++;
   1053      1.1  jmmv }
   1054      1.1  jmmv 
   1055      1.1  jmmv void
   1056      1.1  jmmv atf_tc_fail_check(const char *file, int line, const char *fmt, ...)
   1057      1.1  jmmv {
   1058      1.1  jmmv     va_list ap;
   1059      1.1  jmmv 
   1060      1.1  jmmv     va_start(ap, fmt);
   1061      1.1  jmmv     fail_internal(file, line, "Check failed", "*** ", fmt, ap,
   1062  1.1.1.2  jmmv                   tc_fail_nonfatal, atf_tc_fail_nonfatal);
   1063      1.1  jmmv     va_end(ap);
   1064      1.1  jmmv }
   1065      1.1  jmmv 
   1066      1.1  jmmv void
   1067      1.1  jmmv atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...)
   1068      1.1  jmmv {
   1069      1.1  jmmv     va_list ap;
   1070      1.1  jmmv 
   1071  1.1.1.2  jmmv     atf_reset_exit_checks();
   1072  1.1.1.2  jmmv 
   1073      1.1  jmmv     va_start(ap, fmt);
   1074      1.1  jmmv     fail_internal(file, line, "Requirement failed", "", fmt, ap,
   1075  1.1.1.2  jmmv                   tc_fail, atf_tc_fail);
   1076      1.1  jmmv     va_end(ap);
   1077      1.1  jmmv 
   1078      1.1  jmmv     UNREACHABLE;
   1079      1.1  jmmv     abort();
   1080      1.1  jmmv }
   1081      1.1  jmmv 
   1082      1.1  jmmv static
   1083      1.1  jmmv void
   1084      1.1  jmmv fail_internal(const char *file, int line, const char *reason,
   1085      1.1  jmmv               const char *prefix, const char *fmt, va_list ap,
   1086  1.1.1.2  jmmv               void (*failfunc)(atf_dynstr_t *),
   1087  1.1.1.2  jmmv               void (*backupfunc)(const char *, ...))
   1088      1.1  jmmv {
   1089      1.1  jmmv     va_list ap2;
   1090      1.1  jmmv     atf_error_t err;
   1091      1.1  jmmv     atf_dynstr_t msg;
   1092      1.1  jmmv 
   1093      1.1  jmmv     err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line,
   1094      1.1  jmmv                               reason);
   1095      1.1  jmmv     if (atf_is_error(err))
   1096      1.1  jmmv         goto backup;
   1097      1.1  jmmv 
   1098      1.1  jmmv     va_copy(ap2, ap);
   1099      1.1  jmmv     err = atf_dynstr_append_ap(&msg, fmt, ap2);
   1100      1.1  jmmv     va_end(ap2);
   1101      1.1  jmmv     if (atf_is_error(err)) {
   1102      1.1  jmmv         atf_dynstr_fini(&msg);
   1103      1.1  jmmv         goto backup;
   1104      1.1  jmmv     }
   1105      1.1  jmmv 
   1106      1.1  jmmv     va_copy(ap2, ap);
   1107  1.1.1.2  jmmv     failfunc(&msg);
   1108      1.1  jmmv     return;
   1109      1.1  jmmv 
   1110      1.1  jmmv backup:
   1111  1.1.1.2  jmmv     atf_error_free(err);
   1112      1.1  jmmv     va_copy(ap2, ap);
   1113  1.1.1.2  jmmv     backupfunc(fmt, ap2);
   1114      1.1  jmmv     va_end(ap2);
   1115      1.1  jmmv }
   1116      1.1  jmmv 
   1117      1.1  jmmv void
   1118      1.1  jmmv atf_tc_pass(void)
   1119      1.1  jmmv {
   1120      1.1  jmmv     atf_tcr_t tcr;
   1121      1.1  jmmv     atf_error_t err;
   1122      1.1  jmmv 
   1123      1.1  jmmv     PRE(current_tc != NULL);
   1124      1.1  jmmv 
   1125      1.1  jmmv     err = atf_tcr_init(&tcr, atf_tcr_passed_state);
   1126      1.1  jmmv     if (atf_is_error(err))
   1127      1.1  jmmv         abort();
   1128      1.1  jmmv 
   1129      1.1  jmmv     write_tcr(&tcr);
   1130      1.1  jmmv 
   1131      1.1  jmmv     atf_tcr_fini(&tcr);
   1132      1.1  jmmv 
   1133      1.1  jmmv     exit(EXIT_SUCCESS);
   1134      1.1  jmmv }
   1135      1.1  jmmv 
   1136      1.1  jmmv void
   1137      1.1  jmmv atf_tc_require_prog(const char *prog)
   1138      1.1  jmmv {
   1139      1.1  jmmv     atf_error_t err;
   1140      1.1  jmmv 
   1141      1.1  jmmv     err = check_prog(prog, NULL);
   1142  1.1.1.2  jmmv     if (atf_is_error(err)) {
   1143  1.1.1.2  jmmv         atf_error_free(err);
   1144      1.1  jmmv         atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */
   1145  1.1.1.2  jmmv     }
   1146      1.1  jmmv }
   1147      1.1  jmmv 
   1148      1.1  jmmv void
   1149      1.1  jmmv atf_tc_skip(const char *fmt, ...)
   1150      1.1  jmmv {
   1151      1.1  jmmv     va_list ap;
   1152      1.1  jmmv     atf_tcr_t tcr;
   1153      1.1  jmmv     atf_error_t err;
   1154      1.1  jmmv 
   1155      1.1  jmmv     PRE(current_tc != NULL);
   1156      1.1  jmmv 
   1157      1.1  jmmv     va_start(ap, fmt);
   1158      1.1  jmmv     err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap);
   1159      1.1  jmmv     va_end(ap);
   1160      1.1  jmmv     if (atf_is_error(err))
   1161      1.1  jmmv         abort();
   1162      1.1  jmmv 
   1163      1.1  jmmv     write_tcr(&tcr);
   1164      1.1  jmmv 
   1165      1.1  jmmv     atf_tcr_fini(&tcr);
   1166      1.1  jmmv 
   1167      1.1  jmmv     exit(EXIT_SUCCESS);
   1168      1.1  jmmv }
   1169