1*c243e490SMarcel Moolenaar /* 2*c243e490SMarcel Moolenaar * Automated Testing Framework (atf) 3*c243e490SMarcel Moolenaar * 4*c243e490SMarcel Moolenaar * Copyright (c) 2008 The NetBSD Foundation, Inc. 5*c243e490SMarcel Moolenaar * All rights reserved. 6*c243e490SMarcel Moolenaar * 7*c243e490SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 8*c243e490SMarcel Moolenaar * modification, are permitted provided that the following conditions 9*c243e490SMarcel Moolenaar * are met: 10*c243e490SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 11*c243e490SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 12*c243e490SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 13*c243e490SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 14*c243e490SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 15*c243e490SMarcel Moolenaar * 16*c243e490SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17*c243e490SMarcel Moolenaar * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18*c243e490SMarcel Moolenaar * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19*c243e490SMarcel Moolenaar * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20*c243e490SMarcel Moolenaar * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21*c243e490SMarcel Moolenaar * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*c243e490SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23*c243e490SMarcel Moolenaar * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*c243e490SMarcel Moolenaar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25*c243e490SMarcel Moolenaar * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26*c243e490SMarcel Moolenaar * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27*c243e490SMarcel Moolenaar * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*c243e490SMarcel Moolenaar */ 29*c243e490SMarcel Moolenaar 30*c243e490SMarcel Moolenaar #if defined(HAVE_CONFIG_H) 31*c243e490SMarcel Moolenaar #include "bconfig.h" 32*c243e490SMarcel Moolenaar #endif 33*c243e490SMarcel Moolenaar 34*c243e490SMarcel Moolenaar #include <ctype.h> 35*c243e490SMarcel Moolenaar #include <stdarg.h> 36*c243e490SMarcel Moolenaar #include <stdio.h> 37*c243e490SMarcel Moolenaar #include <stdlib.h> 38*c243e490SMarcel Moolenaar #include <string.h> 39*c243e490SMarcel Moolenaar #include <unistd.h> 40*c243e490SMarcel Moolenaar 41*c243e490SMarcel Moolenaar #include "atf-c/error.h" 42*c243e490SMarcel Moolenaar #include "atf-c/tc.h" 43*c243e490SMarcel Moolenaar #include "atf-c/tp.h" 44*c243e490SMarcel Moolenaar #include "atf-c/utils.h" 45*c243e490SMarcel Moolenaar 46*c243e490SMarcel Moolenaar #include "dynstr.h" 47*c243e490SMarcel Moolenaar #include "env.h" 48*c243e490SMarcel Moolenaar #include "fs.h" 49*c243e490SMarcel Moolenaar #include "map.h" 50*c243e490SMarcel Moolenaar #include "sanity.h" 51*c243e490SMarcel Moolenaar 52*c243e490SMarcel Moolenaar #if defined(HAVE_GNU_GETOPT) 53*c243e490SMarcel Moolenaar # define GETOPT_POSIX "+" 54*c243e490SMarcel Moolenaar #else 55*c243e490SMarcel Moolenaar # define GETOPT_POSIX "" 56*c243e490SMarcel Moolenaar #endif 57*c243e490SMarcel Moolenaar 58*c243e490SMarcel Moolenaar static const char *progname = NULL; 59*c243e490SMarcel Moolenaar 60*c243e490SMarcel Moolenaar /* This prototype is provided by macros.h during instantiation of the test 61*c243e490SMarcel Moolenaar * program, so it can be kept private. Don't know if that's the best idea 62*c243e490SMarcel Moolenaar * though. */ 63*c243e490SMarcel Moolenaar int atf_tp_main(int, char **, atf_error_t (*)(atf_tp_t *)); 64*c243e490SMarcel Moolenaar 65*c243e490SMarcel Moolenaar enum tc_part { 66*c243e490SMarcel Moolenaar BODY, 67*c243e490SMarcel Moolenaar CLEANUP, 68*c243e490SMarcel Moolenaar }; 69*c243e490SMarcel Moolenaar 70*c243e490SMarcel Moolenaar /* --------------------------------------------------------------------- 71*c243e490SMarcel Moolenaar * The "usage" and "user" error types. 72*c243e490SMarcel Moolenaar * --------------------------------------------------------------------- */ 73*c243e490SMarcel Moolenaar 74*c243e490SMarcel Moolenaar #define FREE_FORM_ERROR(name) \ 75*c243e490SMarcel Moolenaar struct name ## _error_data { \ 76*c243e490SMarcel Moolenaar char m_what[2048]; \ 77*c243e490SMarcel Moolenaar }; \ 78*c243e490SMarcel Moolenaar \ 79*c243e490SMarcel Moolenaar static \ 80*c243e490SMarcel Moolenaar void \ 81*c243e490SMarcel Moolenaar name ## _format(const atf_error_t err, char *buf, size_t buflen) \ 82*c243e490SMarcel Moolenaar { \ 83*c243e490SMarcel Moolenaar const struct name ## _error_data *data; \ 84*c243e490SMarcel Moolenaar \ 85*c243e490SMarcel Moolenaar PRE(atf_error_is(err, #name)); \ 86*c243e490SMarcel Moolenaar \ 87*c243e490SMarcel Moolenaar data = atf_error_data(err); \ 88*c243e490SMarcel Moolenaar snprintf(buf, buflen, "%s", data->m_what); \ 89*c243e490SMarcel Moolenaar } \ 90*c243e490SMarcel Moolenaar \ 91*c243e490SMarcel Moolenaar static \ 92*c243e490SMarcel Moolenaar atf_error_t \ 93*c243e490SMarcel Moolenaar name ## _error(const char *fmt, ...) \ 94*c243e490SMarcel Moolenaar { \ 95*c243e490SMarcel Moolenaar atf_error_t err; \ 96*c243e490SMarcel Moolenaar struct name ## _error_data data; \ 97*c243e490SMarcel Moolenaar va_list ap; \ 98*c243e490SMarcel Moolenaar \ 99*c243e490SMarcel Moolenaar va_start(ap, fmt); \ 100*c243e490SMarcel Moolenaar vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap); \ 101*c243e490SMarcel Moolenaar va_end(ap); \ 102*c243e490SMarcel Moolenaar \ 103*c243e490SMarcel Moolenaar err = atf_error_new(#name, &data, sizeof(data), name ## _format); \ 104*c243e490SMarcel Moolenaar \ 105*c243e490SMarcel Moolenaar return err; \ 106*c243e490SMarcel Moolenaar } 107*c243e490SMarcel Moolenaar 108*c243e490SMarcel Moolenaar FREE_FORM_ERROR(usage); 109*c243e490SMarcel Moolenaar FREE_FORM_ERROR(user); 110*c243e490SMarcel Moolenaar 111*c243e490SMarcel Moolenaar /* --------------------------------------------------------------------- 112*c243e490SMarcel Moolenaar * Printing functions. 113*c243e490SMarcel Moolenaar * --------------------------------------------------------------------- */ 114*c243e490SMarcel Moolenaar 115*c243e490SMarcel Moolenaar static 116*c243e490SMarcel Moolenaar void 117*c243e490SMarcel Moolenaar print_error(const atf_error_t err) 118*c243e490SMarcel Moolenaar { 119*c243e490SMarcel Moolenaar char buf[4096]; 120*c243e490SMarcel Moolenaar 121*c243e490SMarcel Moolenaar PRE(atf_is_error(err)); 122*c243e490SMarcel Moolenaar 123*c243e490SMarcel Moolenaar atf_error_format(err, buf, sizeof(buf)); 124*c243e490SMarcel Moolenaar fprintf(stderr, "%s: ERROR: %s\n", progname, buf); 125*c243e490SMarcel Moolenaar 126*c243e490SMarcel Moolenaar if (atf_error_is(err, "usage")) 127*c243e490SMarcel Moolenaar fprintf(stderr, "%s: See atf-test-program(1) for usage details.\n", 128*c243e490SMarcel Moolenaar progname); 129*c243e490SMarcel Moolenaar } 130*c243e490SMarcel Moolenaar 131*c243e490SMarcel Moolenaar static 132*c243e490SMarcel Moolenaar void 133*c243e490SMarcel Moolenaar print_warning(const char *message) 134*c243e490SMarcel Moolenaar { 135*c243e490SMarcel Moolenaar fprintf(stderr, "%s: WARNING: %s\n", progname, message); 136*c243e490SMarcel Moolenaar } 137*c243e490SMarcel Moolenaar 138*c243e490SMarcel Moolenaar /* --------------------------------------------------------------------- 139*c243e490SMarcel Moolenaar * Options handling. 140*c243e490SMarcel Moolenaar * --------------------------------------------------------------------- */ 141*c243e490SMarcel Moolenaar 142*c243e490SMarcel Moolenaar struct params { 143*c243e490SMarcel Moolenaar bool m_do_list; 144*c243e490SMarcel Moolenaar atf_fs_path_t m_srcdir; 145*c243e490SMarcel Moolenaar char *m_tcname; 146*c243e490SMarcel Moolenaar enum tc_part m_tcpart; 147*c243e490SMarcel Moolenaar atf_fs_path_t m_resfile; 148*c243e490SMarcel Moolenaar atf_map_t m_config; 149*c243e490SMarcel Moolenaar }; 150*c243e490SMarcel Moolenaar 151*c243e490SMarcel Moolenaar static 152*c243e490SMarcel Moolenaar atf_error_t 153*c243e490SMarcel Moolenaar argv0_to_dir(const char *argv0, atf_fs_path_t *dir) 154*c243e490SMarcel Moolenaar { 155*c243e490SMarcel Moolenaar atf_error_t err; 156*c243e490SMarcel Moolenaar atf_fs_path_t temp; 157*c243e490SMarcel Moolenaar 158*c243e490SMarcel Moolenaar err = atf_fs_path_init_fmt(&temp, "%s", argv0); 159*c243e490SMarcel Moolenaar if (atf_is_error(err)) 160*c243e490SMarcel Moolenaar goto out; 161*c243e490SMarcel Moolenaar 162*c243e490SMarcel Moolenaar err = atf_fs_path_branch_path(&temp, dir); 163*c243e490SMarcel Moolenaar 164*c243e490SMarcel Moolenaar atf_fs_path_fini(&temp); 165*c243e490SMarcel Moolenaar out: 166*c243e490SMarcel Moolenaar return err; 167*c243e490SMarcel Moolenaar } 168*c243e490SMarcel Moolenaar 169*c243e490SMarcel Moolenaar static 170*c243e490SMarcel Moolenaar atf_error_t 171*c243e490SMarcel Moolenaar params_init(struct params *p, const char *argv0) 172*c243e490SMarcel Moolenaar { 173*c243e490SMarcel Moolenaar atf_error_t err; 174*c243e490SMarcel Moolenaar 175*c243e490SMarcel Moolenaar p->m_do_list = false; 176*c243e490SMarcel Moolenaar p->m_tcname = NULL; 177*c243e490SMarcel Moolenaar p->m_tcpart = BODY; 178*c243e490SMarcel Moolenaar 179*c243e490SMarcel Moolenaar err = argv0_to_dir(argv0, &p->m_srcdir); 180*c243e490SMarcel Moolenaar if (atf_is_error(err)) 181*c243e490SMarcel Moolenaar return err; 182*c243e490SMarcel Moolenaar 183*c243e490SMarcel Moolenaar err = atf_fs_path_init_fmt(&p->m_resfile, "/dev/stdout"); 184*c243e490SMarcel Moolenaar if (atf_is_error(err)) { 185*c243e490SMarcel Moolenaar atf_fs_path_fini(&p->m_srcdir); 186*c243e490SMarcel Moolenaar return err; 187*c243e490SMarcel Moolenaar } 188*c243e490SMarcel Moolenaar 189*c243e490SMarcel Moolenaar err = atf_map_init(&p->m_config); 190*c243e490SMarcel Moolenaar if (atf_is_error(err)) { 191*c243e490SMarcel Moolenaar atf_fs_path_fini(&p->m_resfile); 192*c243e490SMarcel Moolenaar atf_fs_path_fini(&p->m_srcdir); 193*c243e490SMarcel Moolenaar return err; 194*c243e490SMarcel Moolenaar } 195*c243e490SMarcel Moolenaar 196*c243e490SMarcel Moolenaar return err; 197*c243e490SMarcel Moolenaar } 198*c243e490SMarcel Moolenaar 199*c243e490SMarcel Moolenaar static 200*c243e490SMarcel Moolenaar void 201*c243e490SMarcel Moolenaar params_fini(struct params *p) 202*c243e490SMarcel Moolenaar { 203*c243e490SMarcel Moolenaar atf_map_fini(&p->m_config); 204*c243e490SMarcel Moolenaar atf_fs_path_fini(&p->m_resfile); 205*c243e490SMarcel Moolenaar atf_fs_path_fini(&p->m_srcdir); 206*c243e490SMarcel Moolenaar if (p->m_tcname != NULL) 207*c243e490SMarcel Moolenaar free(p->m_tcname); 208*c243e490SMarcel Moolenaar } 209*c243e490SMarcel Moolenaar 210*c243e490SMarcel Moolenaar static 211*c243e490SMarcel Moolenaar atf_error_t 212*c243e490SMarcel Moolenaar parse_vflag(char *arg, atf_map_t *config) 213*c243e490SMarcel Moolenaar { 214*c243e490SMarcel Moolenaar atf_error_t err; 215*c243e490SMarcel Moolenaar char *split; 216*c243e490SMarcel Moolenaar 217*c243e490SMarcel Moolenaar split = strchr(arg, '='); 218*c243e490SMarcel Moolenaar if (split == NULL) { 219*c243e490SMarcel Moolenaar err = usage_error("-v requires an argument of the form var=value"); 220*c243e490SMarcel Moolenaar goto out; 221*c243e490SMarcel Moolenaar } 222*c243e490SMarcel Moolenaar 223*c243e490SMarcel Moolenaar *split = '\0'; 224*c243e490SMarcel Moolenaar split++; 225*c243e490SMarcel Moolenaar 226*c243e490SMarcel Moolenaar err = atf_map_insert(config, arg, split, false); 227*c243e490SMarcel Moolenaar 228*c243e490SMarcel Moolenaar out: 229*c243e490SMarcel Moolenaar return err; 230*c243e490SMarcel Moolenaar } 231*c243e490SMarcel Moolenaar 232*c243e490SMarcel Moolenaar static 233*c243e490SMarcel Moolenaar atf_error_t 234*c243e490SMarcel Moolenaar replace_path_param(atf_fs_path_t *param, const char *value) 235*c243e490SMarcel Moolenaar { 236*c243e490SMarcel Moolenaar atf_error_t err; 237*c243e490SMarcel Moolenaar atf_fs_path_t temp; 238*c243e490SMarcel Moolenaar 239*c243e490SMarcel Moolenaar err = atf_fs_path_init_fmt(&temp, "%s", value); 240*c243e490SMarcel Moolenaar if (!atf_is_error(err)) { 241*c243e490SMarcel Moolenaar atf_fs_path_fini(param); 242*c243e490SMarcel Moolenaar *param = temp; 243*c243e490SMarcel Moolenaar } 244*c243e490SMarcel Moolenaar 245*c243e490SMarcel Moolenaar return err; 246*c243e490SMarcel Moolenaar } 247*c243e490SMarcel Moolenaar 248*c243e490SMarcel Moolenaar /* --------------------------------------------------------------------- 249*c243e490SMarcel Moolenaar * Test case listing. 250*c243e490SMarcel Moolenaar * --------------------------------------------------------------------- */ 251*c243e490SMarcel Moolenaar 252*c243e490SMarcel Moolenaar static 253*c243e490SMarcel Moolenaar void 254*c243e490SMarcel Moolenaar list_tcs(const atf_tp_t *tp) 255*c243e490SMarcel Moolenaar { 256*c243e490SMarcel Moolenaar const atf_tc_t *const *tcs; 257*c243e490SMarcel Moolenaar const atf_tc_t *const *tcsptr; 258*c243e490SMarcel Moolenaar 259*c243e490SMarcel Moolenaar printf("Content-Type: application/X-atf-tp; version=\"1\"\n\n"); 260*c243e490SMarcel Moolenaar 261*c243e490SMarcel Moolenaar tcs = atf_tp_get_tcs(tp); 262*c243e490SMarcel Moolenaar INV(tcs != NULL); /* Should be checked. */ 263*c243e490SMarcel Moolenaar for (tcsptr = tcs; *tcsptr != NULL; tcsptr++) { 264*c243e490SMarcel Moolenaar const atf_tc_t *tc = *tcsptr; 265*c243e490SMarcel Moolenaar char **vars = atf_tc_get_md_vars(tc); 266*c243e490SMarcel Moolenaar char **ptr; 267*c243e490SMarcel Moolenaar 268*c243e490SMarcel Moolenaar INV(vars != NULL); /* Should be checked. */ 269*c243e490SMarcel Moolenaar 270*c243e490SMarcel Moolenaar if (tcsptr != tcs) /* Not first. */ 271*c243e490SMarcel Moolenaar printf("\n"); 272*c243e490SMarcel Moolenaar 273*c243e490SMarcel Moolenaar for (ptr = vars; *ptr != NULL; ptr += 2) { 274*c243e490SMarcel Moolenaar if (strcmp(*ptr, "ident") == 0) { 275*c243e490SMarcel Moolenaar printf("ident: %s\n", *(ptr + 1)); 276*c243e490SMarcel Moolenaar break; 277*c243e490SMarcel Moolenaar } 278*c243e490SMarcel Moolenaar } 279*c243e490SMarcel Moolenaar 280*c243e490SMarcel Moolenaar for (ptr = vars; *ptr != NULL; ptr += 2) { 281*c243e490SMarcel Moolenaar if (strcmp(*ptr, "ident") != 0) { 282*c243e490SMarcel Moolenaar printf("%s: %s\n", *ptr, *(ptr + 1)); 283*c243e490SMarcel Moolenaar } 284*c243e490SMarcel Moolenaar } 285*c243e490SMarcel Moolenaar 286*c243e490SMarcel Moolenaar atf_utils_free_charpp(vars); 287*c243e490SMarcel Moolenaar } 288*c243e490SMarcel Moolenaar } 289*c243e490SMarcel Moolenaar 290*c243e490SMarcel Moolenaar /* --------------------------------------------------------------------- 291*c243e490SMarcel Moolenaar * Main. 292*c243e490SMarcel Moolenaar * --------------------------------------------------------------------- */ 293*c243e490SMarcel Moolenaar 294*c243e490SMarcel Moolenaar static 295*c243e490SMarcel Moolenaar atf_error_t 296*c243e490SMarcel Moolenaar handle_tcarg(const char *tcarg, char **tcname, enum tc_part *tcpart) 297*c243e490SMarcel Moolenaar { 298*c243e490SMarcel Moolenaar atf_error_t err; 299*c243e490SMarcel Moolenaar 300*c243e490SMarcel Moolenaar err = atf_no_error(); 301*c243e490SMarcel Moolenaar 302*c243e490SMarcel Moolenaar *tcname = strdup(tcarg); 303*c243e490SMarcel Moolenaar if (*tcname == NULL) { 304*c243e490SMarcel Moolenaar err = atf_no_memory_error(); 305*c243e490SMarcel Moolenaar goto out; 306*c243e490SMarcel Moolenaar } 307*c243e490SMarcel Moolenaar 308*c243e490SMarcel Moolenaar char *delim = strchr(*tcname, ':'); 309*c243e490SMarcel Moolenaar if (delim != NULL) { 310*c243e490SMarcel Moolenaar *delim = '\0'; 311*c243e490SMarcel Moolenaar 312*c243e490SMarcel Moolenaar delim++; 313*c243e490SMarcel Moolenaar if (strcmp(delim, "body") == 0) { 314*c243e490SMarcel Moolenaar *tcpart = BODY; 315*c243e490SMarcel Moolenaar } else if (strcmp(delim, "cleanup") == 0) { 316*c243e490SMarcel Moolenaar *tcpart = CLEANUP; 317*c243e490SMarcel Moolenaar } else { 318*c243e490SMarcel Moolenaar err = usage_error("Invalid test case part `%s'", delim); 319*c243e490SMarcel Moolenaar goto out; 320*c243e490SMarcel Moolenaar } 321*c243e490SMarcel Moolenaar } 322*c243e490SMarcel Moolenaar 323*c243e490SMarcel Moolenaar out: 324*c243e490SMarcel Moolenaar return err; 325*c243e490SMarcel Moolenaar } 326*c243e490SMarcel Moolenaar 327*c243e490SMarcel Moolenaar static 328*c243e490SMarcel Moolenaar atf_error_t 329*c243e490SMarcel Moolenaar process_params(int argc, char **argv, struct params *p) 330*c243e490SMarcel Moolenaar { 331*c243e490SMarcel Moolenaar atf_error_t err; 332*c243e490SMarcel Moolenaar int ch; 333*c243e490SMarcel Moolenaar int old_opterr; 334*c243e490SMarcel Moolenaar 335*c243e490SMarcel Moolenaar err = params_init(p, argv[0]); 336*c243e490SMarcel Moolenaar if (atf_is_error(err)) 337*c243e490SMarcel Moolenaar goto out; 338*c243e490SMarcel Moolenaar 339*c243e490SMarcel Moolenaar old_opterr = opterr; 340*c243e490SMarcel Moolenaar opterr = 0; 341*c243e490SMarcel Moolenaar while (!atf_is_error(err) && 342*c243e490SMarcel Moolenaar (ch = getopt(argc, argv, GETOPT_POSIX ":lr:s:v:")) != -1) { 343*c243e490SMarcel Moolenaar switch (ch) { 344*c243e490SMarcel Moolenaar case 'l': 345*c243e490SMarcel Moolenaar p->m_do_list = true; 346*c243e490SMarcel Moolenaar break; 347*c243e490SMarcel Moolenaar 348*c243e490SMarcel Moolenaar case 'r': 349*c243e490SMarcel Moolenaar err = replace_path_param(&p->m_resfile, optarg); 350*c243e490SMarcel Moolenaar break; 351*c243e490SMarcel Moolenaar 352*c243e490SMarcel Moolenaar case 's': 353*c243e490SMarcel Moolenaar err = replace_path_param(&p->m_srcdir, optarg); 354*c243e490SMarcel Moolenaar break; 355*c243e490SMarcel Moolenaar 356*c243e490SMarcel Moolenaar case 'v': 357*c243e490SMarcel Moolenaar err = parse_vflag(optarg, &p->m_config); 358*c243e490SMarcel Moolenaar break; 359*c243e490SMarcel Moolenaar 360*c243e490SMarcel Moolenaar case ':': 361*c243e490SMarcel Moolenaar err = usage_error("Option -%c requires an argument.", optopt); 362*c243e490SMarcel Moolenaar break; 363*c243e490SMarcel Moolenaar 364*c243e490SMarcel Moolenaar case '?': 365*c243e490SMarcel Moolenaar default: 366*c243e490SMarcel Moolenaar err = usage_error("Unknown option -%c.", optopt); 367*c243e490SMarcel Moolenaar } 368*c243e490SMarcel Moolenaar } 369*c243e490SMarcel Moolenaar argc -= optind; 370*c243e490SMarcel Moolenaar argv += optind; 371*c243e490SMarcel Moolenaar 372*c243e490SMarcel Moolenaar /* Clear getopt state just in case the test wants to use it. */ 373*c243e490SMarcel Moolenaar opterr = old_opterr; 374*c243e490SMarcel Moolenaar optind = 1; 375*c243e490SMarcel Moolenaar #if defined(HAVE_OPTRESET) 376*c243e490SMarcel Moolenaar optreset = 1; 377*c243e490SMarcel Moolenaar #endif 378*c243e490SMarcel Moolenaar 379*c243e490SMarcel Moolenaar if (!atf_is_error(err)) { 380*c243e490SMarcel Moolenaar if (p->m_do_list) { 381*c243e490SMarcel Moolenaar if (argc > 0) 382*c243e490SMarcel Moolenaar err = usage_error("Cannot provide test case names with -l"); 383*c243e490SMarcel Moolenaar } else { 384*c243e490SMarcel Moolenaar if (argc == 0) 385*c243e490SMarcel Moolenaar err = usage_error("Must provide a test case name"); 386*c243e490SMarcel Moolenaar else if (argc == 1) 387*c243e490SMarcel Moolenaar err = handle_tcarg(argv[0], &p->m_tcname, &p->m_tcpart); 388*c243e490SMarcel Moolenaar else if (argc > 1) { 389*c243e490SMarcel Moolenaar err = usage_error("Cannot provide more than one test case " 390*c243e490SMarcel Moolenaar "name"); 391*c243e490SMarcel Moolenaar } 392*c243e490SMarcel Moolenaar } 393*c243e490SMarcel Moolenaar } 394*c243e490SMarcel Moolenaar 395*c243e490SMarcel Moolenaar if (atf_is_error(err)) 396*c243e490SMarcel Moolenaar params_fini(p); 397*c243e490SMarcel Moolenaar 398*c243e490SMarcel Moolenaar out: 399*c243e490SMarcel Moolenaar return err; 400*c243e490SMarcel Moolenaar } 401*c243e490SMarcel Moolenaar 402*c243e490SMarcel Moolenaar static 403*c243e490SMarcel Moolenaar atf_error_t 404*c243e490SMarcel Moolenaar srcdir_strip_libtool(atf_fs_path_t *srcdir) 405*c243e490SMarcel Moolenaar { 406*c243e490SMarcel Moolenaar atf_error_t err; 407*c243e490SMarcel Moolenaar atf_fs_path_t parent; 408*c243e490SMarcel Moolenaar 409*c243e490SMarcel Moolenaar err = atf_fs_path_branch_path(srcdir, &parent); 410*c243e490SMarcel Moolenaar if (atf_is_error(err)) 411*c243e490SMarcel Moolenaar goto out; 412*c243e490SMarcel Moolenaar 413*c243e490SMarcel Moolenaar atf_fs_path_fini(srcdir); 414*c243e490SMarcel Moolenaar *srcdir = parent; 415*c243e490SMarcel Moolenaar 416*c243e490SMarcel Moolenaar INV(!atf_is_error(err)); 417*c243e490SMarcel Moolenaar out: 418*c243e490SMarcel Moolenaar return err; 419*c243e490SMarcel Moolenaar } 420*c243e490SMarcel Moolenaar 421*c243e490SMarcel Moolenaar static 422*c243e490SMarcel Moolenaar atf_error_t 423*c243e490SMarcel Moolenaar handle_srcdir(struct params *p) 424*c243e490SMarcel Moolenaar { 425*c243e490SMarcel Moolenaar atf_error_t err; 426*c243e490SMarcel Moolenaar atf_dynstr_t leafname; 427*c243e490SMarcel Moolenaar atf_fs_path_t exe, srcdir; 428*c243e490SMarcel Moolenaar bool b; 429*c243e490SMarcel Moolenaar 430*c243e490SMarcel Moolenaar err = atf_fs_path_copy(&srcdir, &p->m_srcdir); 431*c243e490SMarcel Moolenaar if (atf_is_error(err)) 432*c243e490SMarcel Moolenaar goto out; 433*c243e490SMarcel Moolenaar 434*c243e490SMarcel Moolenaar if (!atf_fs_path_is_absolute(&srcdir)) { 435*c243e490SMarcel Moolenaar atf_fs_path_t srcdirabs; 436*c243e490SMarcel Moolenaar 437*c243e490SMarcel Moolenaar err = atf_fs_path_to_absolute(&srcdir, &srcdirabs); 438*c243e490SMarcel Moolenaar if (atf_is_error(err)) 439*c243e490SMarcel Moolenaar goto out_srcdir; 440*c243e490SMarcel Moolenaar 441*c243e490SMarcel Moolenaar atf_fs_path_fini(&srcdir); 442*c243e490SMarcel Moolenaar srcdir = srcdirabs; 443*c243e490SMarcel Moolenaar } 444*c243e490SMarcel Moolenaar 445*c243e490SMarcel Moolenaar err = atf_fs_path_leaf_name(&srcdir, &leafname); 446*c243e490SMarcel Moolenaar if (atf_is_error(err)) 447*c243e490SMarcel Moolenaar goto out_srcdir; 448*c243e490SMarcel Moolenaar else { 449*c243e490SMarcel Moolenaar const bool libs = atf_equal_dynstr_cstring(&leafname, ".libs"); 450*c243e490SMarcel Moolenaar atf_dynstr_fini(&leafname); 451*c243e490SMarcel Moolenaar 452*c243e490SMarcel Moolenaar if (libs) { 453*c243e490SMarcel Moolenaar err = srcdir_strip_libtool(&srcdir); 454*c243e490SMarcel Moolenaar if (atf_is_error(err)) 455*c243e490SMarcel Moolenaar goto out; 456*c243e490SMarcel Moolenaar } 457*c243e490SMarcel Moolenaar } 458*c243e490SMarcel Moolenaar 459*c243e490SMarcel Moolenaar err = atf_fs_path_copy(&exe, &srcdir); 460*c243e490SMarcel Moolenaar if (atf_is_error(err)) 461*c243e490SMarcel Moolenaar goto out_srcdir; 462*c243e490SMarcel Moolenaar 463*c243e490SMarcel Moolenaar err = atf_fs_path_append_fmt(&exe, "%s", progname); 464*c243e490SMarcel Moolenaar if (atf_is_error(err)) 465*c243e490SMarcel Moolenaar goto out_exe; 466*c243e490SMarcel Moolenaar 467*c243e490SMarcel Moolenaar err = atf_fs_exists(&exe, &b); 468*c243e490SMarcel Moolenaar if (!atf_is_error(err)) { 469*c243e490SMarcel Moolenaar if (b) { 470*c243e490SMarcel Moolenaar err = atf_map_insert(&p->m_config, "srcdir", 471*c243e490SMarcel Moolenaar strdup(atf_fs_path_cstring(&srcdir)), true); 472*c243e490SMarcel Moolenaar } else { 473*c243e490SMarcel Moolenaar err = user_error("Cannot find the test program in the source " 474*c243e490SMarcel Moolenaar "directory `%s'", atf_fs_path_cstring(&srcdir)); 475*c243e490SMarcel Moolenaar } 476*c243e490SMarcel Moolenaar } 477*c243e490SMarcel Moolenaar 478*c243e490SMarcel Moolenaar out_exe: 479*c243e490SMarcel Moolenaar atf_fs_path_fini(&exe); 480*c243e490SMarcel Moolenaar out_srcdir: 481*c243e490SMarcel Moolenaar atf_fs_path_fini(&srcdir); 482*c243e490SMarcel Moolenaar out: 483*c243e490SMarcel Moolenaar return err; 484*c243e490SMarcel Moolenaar } 485*c243e490SMarcel Moolenaar 486*c243e490SMarcel Moolenaar static 487*c243e490SMarcel Moolenaar atf_error_t 488*c243e490SMarcel Moolenaar run_tc(const atf_tp_t *tp, struct params *p, int *exitcode) 489*c243e490SMarcel Moolenaar { 490*c243e490SMarcel Moolenaar atf_error_t err; 491*c243e490SMarcel Moolenaar 492*c243e490SMarcel Moolenaar err = atf_no_error(); 493*c243e490SMarcel Moolenaar 494*c243e490SMarcel Moolenaar if (!atf_tp_has_tc(tp, p->m_tcname)) { 495*c243e490SMarcel Moolenaar err = usage_error("Unknown test case `%s'", p->m_tcname); 496*c243e490SMarcel Moolenaar goto out; 497*c243e490SMarcel Moolenaar } 498*c243e490SMarcel Moolenaar 499*c243e490SMarcel Moolenaar if (!atf_env_has("__RUNNING_INSIDE_ATF_RUN") || strcmp(atf_env_get( 500*c243e490SMarcel Moolenaar "__RUNNING_INSIDE_ATF_RUN"), "internal-yes-value") != 0) 501*c243e490SMarcel Moolenaar { 502*c243e490SMarcel Moolenaar print_warning("Running test cases without atf-run(1) is unsupported"); 503*c243e490SMarcel Moolenaar print_warning("No isolation nor timeout control is being applied; you " 504*c243e490SMarcel Moolenaar "may get unexpected failures; see atf-test-case(4)"); 505*c243e490SMarcel Moolenaar } 506*c243e490SMarcel Moolenaar 507*c243e490SMarcel Moolenaar switch (p->m_tcpart) { 508*c243e490SMarcel Moolenaar case BODY: 509*c243e490SMarcel Moolenaar err = atf_tp_run(tp, p->m_tcname, atf_fs_path_cstring(&p->m_resfile)); 510*c243e490SMarcel Moolenaar if (atf_is_error(err)) { 511*c243e490SMarcel Moolenaar /* TODO: Handle error */ 512*c243e490SMarcel Moolenaar *exitcode = EXIT_FAILURE; 513*c243e490SMarcel Moolenaar atf_error_free(err); 514*c243e490SMarcel Moolenaar } else { 515*c243e490SMarcel Moolenaar *exitcode = EXIT_SUCCESS; 516*c243e490SMarcel Moolenaar } 517*c243e490SMarcel Moolenaar 518*c243e490SMarcel Moolenaar break; 519*c243e490SMarcel Moolenaar 520*c243e490SMarcel Moolenaar case CLEANUP: 521*c243e490SMarcel Moolenaar err = atf_tp_cleanup(tp, p->m_tcname); 522*c243e490SMarcel Moolenaar if (atf_is_error(err)) { 523*c243e490SMarcel Moolenaar /* TODO: Handle error */ 524*c243e490SMarcel Moolenaar *exitcode = EXIT_FAILURE; 525*c243e490SMarcel Moolenaar atf_error_free(err); 526*c243e490SMarcel Moolenaar } else { 527*c243e490SMarcel Moolenaar *exitcode = EXIT_SUCCESS; 528*c243e490SMarcel Moolenaar } 529*c243e490SMarcel Moolenaar 530*c243e490SMarcel Moolenaar break; 531*c243e490SMarcel Moolenaar 532*c243e490SMarcel Moolenaar default: 533*c243e490SMarcel Moolenaar UNREACHABLE; 534*c243e490SMarcel Moolenaar } 535*c243e490SMarcel Moolenaar 536*c243e490SMarcel Moolenaar INV(!atf_is_error(err)); 537*c243e490SMarcel Moolenaar out: 538*c243e490SMarcel Moolenaar return err; 539*c243e490SMarcel Moolenaar } 540*c243e490SMarcel Moolenaar 541*c243e490SMarcel Moolenaar static 542*c243e490SMarcel Moolenaar atf_error_t 543*c243e490SMarcel Moolenaar controlled_main(int argc, char **argv, 544*c243e490SMarcel Moolenaar atf_error_t (*add_tcs_hook)(atf_tp_t *), 545*c243e490SMarcel Moolenaar int *exitcode) 546*c243e490SMarcel Moolenaar { 547*c243e490SMarcel Moolenaar atf_error_t err; 548*c243e490SMarcel Moolenaar struct params p; 549*c243e490SMarcel Moolenaar atf_tp_t tp; 550*c243e490SMarcel Moolenaar char **raw_config; 551*c243e490SMarcel Moolenaar 552*c243e490SMarcel Moolenaar err = process_params(argc, argv, &p); 553*c243e490SMarcel Moolenaar if (atf_is_error(err)) 554*c243e490SMarcel Moolenaar goto out; 555*c243e490SMarcel Moolenaar 556*c243e490SMarcel Moolenaar err = handle_srcdir(&p); 557*c243e490SMarcel Moolenaar if (atf_is_error(err)) 558*c243e490SMarcel Moolenaar goto out_p; 559*c243e490SMarcel Moolenaar 560*c243e490SMarcel Moolenaar raw_config = atf_map_to_charpp(&p.m_config); 561*c243e490SMarcel Moolenaar if (raw_config == NULL) { 562*c243e490SMarcel Moolenaar err = atf_no_memory_error(); 563*c243e490SMarcel Moolenaar goto out_p; 564*c243e490SMarcel Moolenaar } 565*c243e490SMarcel Moolenaar err = atf_tp_init(&tp, (const char* const*)raw_config); 566*c243e490SMarcel Moolenaar atf_utils_free_charpp(raw_config); 567*c243e490SMarcel Moolenaar if (atf_is_error(err)) 568*c243e490SMarcel Moolenaar goto out_p; 569*c243e490SMarcel Moolenaar 570*c243e490SMarcel Moolenaar err = add_tcs_hook(&tp); 571*c243e490SMarcel Moolenaar if (atf_is_error(err)) 572*c243e490SMarcel Moolenaar goto out_tp; 573*c243e490SMarcel Moolenaar 574*c243e490SMarcel Moolenaar if (p.m_do_list) { 575*c243e490SMarcel Moolenaar list_tcs(&tp); 576*c243e490SMarcel Moolenaar INV(!atf_is_error(err)); 577*c243e490SMarcel Moolenaar *exitcode = EXIT_SUCCESS; 578*c243e490SMarcel Moolenaar } else { 579*c243e490SMarcel Moolenaar err = run_tc(&tp, &p, exitcode); 580*c243e490SMarcel Moolenaar } 581*c243e490SMarcel Moolenaar 582*c243e490SMarcel Moolenaar out_tp: 583*c243e490SMarcel Moolenaar atf_tp_fini(&tp); 584*c243e490SMarcel Moolenaar out_p: 585*c243e490SMarcel Moolenaar params_fini(&p); 586*c243e490SMarcel Moolenaar out: 587*c243e490SMarcel Moolenaar return err; 588*c243e490SMarcel Moolenaar } 589*c243e490SMarcel Moolenaar 590*c243e490SMarcel Moolenaar int 591*c243e490SMarcel Moolenaar atf_tp_main(int argc, char **argv, atf_error_t (*add_tcs_hook)(atf_tp_t *)) 592*c243e490SMarcel Moolenaar { 593*c243e490SMarcel Moolenaar atf_error_t err; 594*c243e490SMarcel Moolenaar int exitcode; 595*c243e490SMarcel Moolenaar 596*c243e490SMarcel Moolenaar progname = strrchr(argv[0], '/'); 597*c243e490SMarcel Moolenaar if (progname == NULL) 598*c243e490SMarcel Moolenaar progname = argv[0]; 599*c243e490SMarcel Moolenaar else 600*c243e490SMarcel Moolenaar progname++; 601*c243e490SMarcel Moolenaar 602*c243e490SMarcel Moolenaar /* Libtool workaround: if running from within the source tree (binaries 603*c243e490SMarcel Moolenaar * that are not installed yet), skip the "lt-" prefix added to files in 604*c243e490SMarcel Moolenaar * the ".libs" directory to show the real (not temporary) name. */ 605*c243e490SMarcel Moolenaar if (strncmp(progname, "lt-", 3) == 0) 606*c243e490SMarcel Moolenaar progname += 3; 607*c243e490SMarcel Moolenaar 608*c243e490SMarcel Moolenaar exitcode = EXIT_FAILURE; /* Silence GCC warning. */ 609*c243e490SMarcel Moolenaar err = controlled_main(argc, argv, add_tcs_hook, &exitcode); 610*c243e490SMarcel Moolenaar if (atf_is_error(err)) { 611*c243e490SMarcel Moolenaar print_error(err); 612*c243e490SMarcel Moolenaar atf_error_free(err); 613*c243e490SMarcel Moolenaar exitcode = EXIT_FAILURE; 614*c243e490SMarcel Moolenaar } 615*c243e490SMarcel Moolenaar 616*c243e490SMarcel Moolenaar return exitcode; 617*c243e490SMarcel Moolenaar } 618