1240116Smarcel/* 2240116Smarcel * Automated Testing Framework (atf) 3240116Smarcel * 4240116Smarcel * Copyright (c) 2008 The NetBSD Foundation, Inc. 5240116Smarcel * All rights reserved. 6240116Smarcel * 7240116Smarcel * Redistribution and use in source and binary forms, with or without 8240116Smarcel * modification, are permitted provided that the following conditions 9240116Smarcel * are met: 10240116Smarcel * 1. Redistributions of source code must retain the above copyright 11240116Smarcel * notice, this list of conditions and the following disclaimer. 12240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel * notice, this list of conditions and the following disclaimer in the 14240116Smarcel * documentation and/or other materials provided with the distribution. 15240116Smarcel * 16240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel */ 29240116Smarcel 30240116Smarcel#if defined(HAVE_CONFIG_H) 31240116Smarcel#include "bconfig.h" 32240116Smarcel#endif 33240116Smarcel 34240116Smarcel#include <ctype.h> 35240116Smarcel#include <stdarg.h> 36240116Smarcel#include <stdio.h> 37240116Smarcel#include <stdlib.h> 38240116Smarcel#include <string.h> 39240116Smarcel#include <unistd.h> 40240116Smarcel 41240116Smarcel#include "atf-c/error.h" 42240116Smarcel#include "atf-c/tc.h" 43240116Smarcel#include "atf-c/tp.h" 44240116Smarcel#include "atf-c/utils.h" 45240116Smarcel 46240116Smarcel#include "dynstr.h" 47240116Smarcel#include "env.h" 48240116Smarcel#include "fs.h" 49240116Smarcel#include "map.h" 50240116Smarcel#include "sanity.h" 51240116Smarcel 52240116Smarcel#if defined(HAVE_GNU_GETOPT) 53240116Smarcel# define GETOPT_POSIX "+" 54240116Smarcel#else 55240116Smarcel# define GETOPT_POSIX "" 56240116Smarcel#endif 57240116Smarcel 58240116Smarcelstatic const char *progname = NULL; 59240116Smarcel 60240116Smarcel/* This prototype is provided by macros.h during instantiation of the test 61240116Smarcel * program, so it can be kept private. Don't know if that's the best idea 62240116Smarcel * though. */ 63240116Smarcelint atf_tp_main(int, char **, atf_error_t (*)(atf_tp_t *)); 64240116Smarcel 65240116Smarcelenum tc_part { 66240116Smarcel BODY, 67240116Smarcel CLEANUP, 68240116Smarcel}; 69240116Smarcel 70240116Smarcel/* --------------------------------------------------------------------- 71240116Smarcel * The "usage" and "user" error types. 72240116Smarcel * --------------------------------------------------------------------- */ 73240116Smarcel 74240116Smarcel#define FREE_FORM_ERROR(name) \ 75240116Smarcel struct name ## _error_data { \ 76240116Smarcel char m_what[2048]; \ 77240116Smarcel }; \ 78240116Smarcel \ 79240116Smarcel static \ 80240116Smarcel void \ 81240116Smarcel name ## _format(const atf_error_t err, char *buf, size_t buflen) \ 82240116Smarcel { \ 83240116Smarcel const struct name ## _error_data *data; \ 84240116Smarcel \ 85240116Smarcel PRE(atf_error_is(err, #name)); \ 86240116Smarcel \ 87240116Smarcel data = atf_error_data(err); \ 88240116Smarcel snprintf(buf, buflen, "%s", data->m_what); \ 89240116Smarcel } \ 90240116Smarcel \ 91240116Smarcel static \ 92240116Smarcel atf_error_t \ 93240116Smarcel name ## _error(const char *fmt, ...) \ 94240116Smarcel { \ 95240116Smarcel atf_error_t err; \ 96240116Smarcel struct name ## _error_data data; \ 97240116Smarcel va_list ap; \ 98240116Smarcel \ 99240116Smarcel va_start(ap, fmt); \ 100240116Smarcel vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap); \ 101240116Smarcel va_end(ap); \ 102240116Smarcel \ 103240116Smarcel err = atf_error_new(#name, &data, sizeof(data), name ## _format); \ 104240116Smarcel \ 105240116Smarcel return err; \ 106240116Smarcel } 107240116Smarcel 108240116SmarcelFREE_FORM_ERROR(usage); 109240116SmarcelFREE_FORM_ERROR(user); 110240116Smarcel 111240116Smarcel/* --------------------------------------------------------------------- 112240116Smarcel * Printing functions. 113240116Smarcel * --------------------------------------------------------------------- */ 114240116Smarcel 115240116Smarcelstatic 116240116Smarcelvoid 117240116Smarcelprint_error(const atf_error_t err) 118240116Smarcel{ 119240116Smarcel char buf[4096]; 120240116Smarcel 121240116Smarcel PRE(atf_is_error(err)); 122240116Smarcel 123240116Smarcel atf_error_format(err, buf, sizeof(buf)); 124240116Smarcel fprintf(stderr, "%s: ERROR: %s\n", progname, buf); 125240116Smarcel 126240116Smarcel if (atf_error_is(err, "usage")) 127240116Smarcel fprintf(stderr, "%s: See atf-test-program(1) for usage details.\n", 128240116Smarcel progname); 129240116Smarcel} 130240116Smarcel 131240116Smarcelstatic 132240116Smarcelvoid 133240116Smarcelprint_warning(const char *message) 134240116Smarcel{ 135240116Smarcel fprintf(stderr, "%s: WARNING: %s\n", progname, message); 136240116Smarcel} 137240116Smarcel 138240116Smarcel/* --------------------------------------------------------------------- 139240116Smarcel * Options handling. 140240116Smarcel * --------------------------------------------------------------------- */ 141240116Smarcel 142240116Smarcelstruct params { 143240116Smarcel bool m_do_list; 144240116Smarcel atf_fs_path_t m_srcdir; 145240116Smarcel char *m_tcname; 146240116Smarcel enum tc_part m_tcpart; 147240116Smarcel atf_fs_path_t m_resfile; 148240116Smarcel atf_map_t m_config; 149240116Smarcel}; 150240116Smarcel 151240116Smarcelstatic 152240116Smarcelatf_error_t 153240116Smarcelargv0_to_dir(const char *argv0, atf_fs_path_t *dir) 154240116Smarcel{ 155240116Smarcel atf_error_t err; 156240116Smarcel atf_fs_path_t temp; 157240116Smarcel 158240116Smarcel err = atf_fs_path_init_fmt(&temp, "%s", argv0); 159240116Smarcel if (atf_is_error(err)) 160240116Smarcel goto out; 161240116Smarcel 162240116Smarcel err = atf_fs_path_branch_path(&temp, dir); 163240116Smarcel 164240116Smarcel atf_fs_path_fini(&temp); 165240116Smarcelout: 166240116Smarcel return err; 167240116Smarcel} 168240116Smarcel 169240116Smarcelstatic 170240116Smarcelatf_error_t 171240116Smarcelparams_init(struct params *p, const char *argv0) 172240116Smarcel{ 173240116Smarcel atf_error_t err; 174240116Smarcel 175240116Smarcel p->m_do_list = false; 176240116Smarcel p->m_tcname = NULL; 177240116Smarcel p->m_tcpart = BODY; 178240116Smarcel 179240116Smarcel err = argv0_to_dir(argv0, &p->m_srcdir); 180240116Smarcel if (atf_is_error(err)) 181240116Smarcel return err; 182240116Smarcel 183240116Smarcel err = atf_fs_path_init_fmt(&p->m_resfile, "/dev/stdout"); 184240116Smarcel if (atf_is_error(err)) { 185240116Smarcel atf_fs_path_fini(&p->m_srcdir); 186240116Smarcel return err; 187240116Smarcel } 188240116Smarcel 189240116Smarcel err = atf_map_init(&p->m_config); 190240116Smarcel if (atf_is_error(err)) { 191240116Smarcel atf_fs_path_fini(&p->m_resfile); 192240116Smarcel atf_fs_path_fini(&p->m_srcdir); 193240116Smarcel return err; 194240116Smarcel } 195240116Smarcel 196240116Smarcel return err; 197240116Smarcel} 198240116Smarcel 199240116Smarcelstatic 200240116Smarcelvoid 201240116Smarcelparams_fini(struct params *p) 202240116Smarcel{ 203240116Smarcel atf_map_fini(&p->m_config); 204240116Smarcel atf_fs_path_fini(&p->m_resfile); 205240116Smarcel atf_fs_path_fini(&p->m_srcdir); 206240116Smarcel if (p->m_tcname != NULL) 207240116Smarcel free(p->m_tcname); 208240116Smarcel} 209240116Smarcel 210240116Smarcelstatic 211240116Smarcelatf_error_t 212240116Smarcelparse_vflag(char *arg, atf_map_t *config) 213240116Smarcel{ 214240116Smarcel atf_error_t err; 215240116Smarcel char *split; 216240116Smarcel 217240116Smarcel split = strchr(arg, '='); 218240116Smarcel if (split == NULL) { 219240116Smarcel err = usage_error("-v requires an argument of the form var=value"); 220240116Smarcel goto out; 221240116Smarcel } 222240116Smarcel 223240116Smarcel *split = '\0'; 224240116Smarcel split++; 225240116Smarcel 226240116Smarcel err = atf_map_insert(config, arg, split, false); 227240116Smarcel 228240116Smarcelout: 229240116Smarcel return err; 230240116Smarcel} 231240116Smarcel 232240116Smarcelstatic 233240116Smarcelatf_error_t 234240116Smarcelreplace_path_param(atf_fs_path_t *param, const char *value) 235240116Smarcel{ 236240116Smarcel atf_error_t err; 237240116Smarcel atf_fs_path_t temp; 238240116Smarcel 239240116Smarcel err = atf_fs_path_init_fmt(&temp, "%s", value); 240240116Smarcel if (!atf_is_error(err)) { 241240116Smarcel atf_fs_path_fini(param); 242240116Smarcel *param = temp; 243240116Smarcel } 244240116Smarcel 245240116Smarcel return err; 246240116Smarcel} 247240116Smarcel 248240116Smarcel/* --------------------------------------------------------------------- 249240116Smarcel * Test case listing. 250240116Smarcel * --------------------------------------------------------------------- */ 251240116Smarcel 252240116Smarcelstatic 253240116Smarcelvoid 254240116Smarcellist_tcs(const atf_tp_t *tp) 255240116Smarcel{ 256240116Smarcel const atf_tc_t *const *tcs; 257240116Smarcel const atf_tc_t *const *tcsptr; 258240116Smarcel 259240116Smarcel printf("Content-Type: application/X-atf-tp; version=\"1\"\n\n"); 260240116Smarcel 261240116Smarcel tcs = atf_tp_get_tcs(tp); 262240116Smarcel INV(tcs != NULL); /* Should be checked. */ 263240116Smarcel for (tcsptr = tcs; *tcsptr != NULL; tcsptr++) { 264240116Smarcel const atf_tc_t *tc = *tcsptr; 265240116Smarcel char **vars = atf_tc_get_md_vars(tc); 266240116Smarcel char **ptr; 267240116Smarcel 268240116Smarcel INV(vars != NULL); /* Should be checked. */ 269240116Smarcel 270240116Smarcel if (tcsptr != tcs) /* Not first. */ 271240116Smarcel printf("\n"); 272240116Smarcel 273240116Smarcel for (ptr = vars; *ptr != NULL; ptr += 2) { 274240116Smarcel if (strcmp(*ptr, "ident") == 0) { 275240116Smarcel printf("ident: %s\n", *(ptr + 1)); 276240116Smarcel break; 277240116Smarcel } 278240116Smarcel } 279240116Smarcel 280240116Smarcel for (ptr = vars; *ptr != NULL; ptr += 2) { 281240116Smarcel if (strcmp(*ptr, "ident") != 0) { 282240116Smarcel printf("%s: %s\n", *ptr, *(ptr + 1)); 283240116Smarcel } 284240116Smarcel } 285240116Smarcel 286240116Smarcel atf_utils_free_charpp(vars); 287240116Smarcel } 288240116Smarcel} 289240116Smarcel 290240116Smarcel/* --------------------------------------------------------------------- 291240116Smarcel * Main. 292240116Smarcel * --------------------------------------------------------------------- */ 293240116Smarcel 294240116Smarcelstatic 295240116Smarcelatf_error_t 296240116Smarcelhandle_tcarg(const char *tcarg, char **tcname, enum tc_part *tcpart) 297240116Smarcel{ 298240116Smarcel atf_error_t err; 299240116Smarcel 300240116Smarcel err = atf_no_error(); 301240116Smarcel 302240116Smarcel *tcname = strdup(tcarg); 303240116Smarcel if (*tcname == NULL) { 304240116Smarcel err = atf_no_memory_error(); 305240116Smarcel goto out; 306240116Smarcel } 307240116Smarcel 308240116Smarcel char *delim = strchr(*tcname, ':'); 309240116Smarcel if (delim != NULL) { 310240116Smarcel *delim = '\0'; 311240116Smarcel 312240116Smarcel delim++; 313240116Smarcel if (strcmp(delim, "body") == 0) { 314240116Smarcel *tcpart = BODY; 315240116Smarcel } else if (strcmp(delim, "cleanup") == 0) { 316240116Smarcel *tcpart = CLEANUP; 317240116Smarcel } else { 318240116Smarcel err = usage_error("Invalid test case part `%s'", delim); 319240116Smarcel goto out; 320240116Smarcel } 321240116Smarcel } 322240116Smarcel 323240116Smarcelout: 324240116Smarcel return err; 325240116Smarcel} 326240116Smarcel 327240116Smarcelstatic 328240116Smarcelatf_error_t 329240116Smarcelprocess_params(int argc, char **argv, struct params *p) 330240116Smarcel{ 331240116Smarcel atf_error_t err; 332240116Smarcel int ch; 333240116Smarcel int old_opterr; 334240116Smarcel 335240116Smarcel err = params_init(p, argv[0]); 336240116Smarcel if (atf_is_error(err)) 337240116Smarcel goto out; 338240116Smarcel 339240116Smarcel old_opterr = opterr; 340240116Smarcel opterr = 0; 341240116Smarcel while (!atf_is_error(err) && 342240116Smarcel (ch = getopt(argc, argv, GETOPT_POSIX ":lr:s:v:")) != -1) { 343240116Smarcel switch (ch) { 344240116Smarcel case 'l': 345240116Smarcel p->m_do_list = true; 346240116Smarcel break; 347240116Smarcel 348240116Smarcel case 'r': 349240116Smarcel err = replace_path_param(&p->m_resfile, optarg); 350240116Smarcel break; 351240116Smarcel 352240116Smarcel case 's': 353240116Smarcel err = replace_path_param(&p->m_srcdir, optarg); 354240116Smarcel break; 355240116Smarcel 356240116Smarcel case 'v': 357240116Smarcel err = parse_vflag(optarg, &p->m_config); 358240116Smarcel break; 359240116Smarcel 360240116Smarcel case ':': 361240116Smarcel err = usage_error("Option -%c requires an argument.", optopt); 362240116Smarcel break; 363240116Smarcel 364240116Smarcel case '?': 365240116Smarcel default: 366240116Smarcel err = usage_error("Unknown option -%c.", optopt); 367240116Smarcel } 368240116Smarcel } 369240116Smarcel argc -= optind; 370240116Smarcel argv += optind; 371240116Smarcel 372240116Smarcel /* Clear getopt state just in case the test wants to use it. */ 373240116Smarcel opterr = old_opterr; 374240116Smarcel optind = 1; 375240116Smarcel#if defined(HAVE_OPTRESET) 376240116Smarcel optreset = 1; 377240116Smarcel#endif 378240116Smarcel 379240116Smarcel if (!atf_is_error(err)) { 380240116Smarcel if (p->m_do_list) { 381240116Smarcel if (argc > 0) 382240116Smarcel err = usage_error("Cannot provide test case names with -l"); 383240116Smarcel } else { 384240116Smarcel if (argc == 0) 385240116Smarcel err = usage_error("Must provide a test case name"); 386240116Smarcel else if (argc == 1) 387240116Smarcel err = handle_tcarg(argv[0], &p->m_tcname, &p->m_tcpart); 388240116Smarcel else if (argc > 1) { 389240116Smarcel err = usage_error("Cannot provide more than one test case " 390240116Smarcel "name"); 391240116Smarcel } 392240116Smarcel } 393240116Smarcel } 394240116Smarcel 395240116Smarcel if (atf_is_error(err)) 396240116Smarcel params_fini(p); 397240116Smarcel 398240116Smarcelout: 399240116Smarcel return err; 400240116Smarcel} 401240116Smarcel 402240116Smarcelstatic 403240116Smarcelatf_error_t 404240116Smarcelsrcdir_strip_libtool(atf_fs_path_t *srcdir) 405240116Smarcel{ 406240116Smarcel atf_error_t err; 407240116Smarcel atf_fs_path_t parent; 408240116Smarcel 409240116Smarcel err = atf_fs_path_branch_path(srcdir, &parent); 410240116Smarcel if (atf_is_error(err)) 411240116Smarcel goto out; 412240116Smarcel 413240116Smarcel atf_fs_path_fini(srcdir); 414240116Smarcel *srcdir = parent; 415240116Smarcel 416240116Smarcel INV(!atf_is_error(err)); 417240116Smarcelout: 418240116Smarcel return err; 419240116Smarcel} 420240116Smarcel 421240116Smarcelstatic 422240116Smarcelatf_error_t 423240116Smarcelhandle_srcdir(struct params *p) 424240116Smarcel{ 425240116Smarcel atf_error_t err; 426240116Smarcel atf_dynstr_t leafname; 427240116Smarcel atf_fs_path_t exe, srcdir; 428240116Smarcel bool b; 429240116Smarcel 430240116Smarcel err = atf_fs_path_copy(&srcdir, &p->m_srcdir); 431240116Smarcel if (atf_is_error(err)) 432240116Smarcel goto out; 433240116Smarcel 434240116Smarcel if (!atf_fs_path_is_absolute(&srcdir)) { 435240116Smarcel atf_fs_path_t srcdirabs; 436240116Smarcel 437240116Smarcel err = atf_fs_path_to_absolute(&srcdir, &srcdirabs); 438240116Smarcel if (atf_is_error(err)) 439240116Smarcel goto out_srcdir; 440240116Smarcel 441240116Smarcel atf_fs_path_fini(&srcdir); 442240116Smarcel srcdir = srcdirabs; 443240116Smarcel } 444240116Smarcel 445240116Smarcel err = atf_fs_path_leaf_name(&srcdir, &leafname); 446240116Smarcel if (atf_is_error(err)) 447240116Smarcel goto out_srcdir; 448240116Smarcel else { 449240116Smarcel const bool libs = atf_equal_dynstr_cstring(&leafname, ".libs"); 450240116Smarcel atf_dynstr_fini(&leafname); 451240116Smarcel 452240116Smarcel if (libs) { 453240116Smarcel err = srcdir_strip_libtool(&srcdir); 454240116Smarcel if (atf_is_error(err)) 455240116Smarcel goto out; 456240116Smarcel } 457240116Smarcel } 458240116Smarcel 459240116Smarcel err = atf_fs_path_copy(&exe, &srcdir); 460240116Smarcel if (atf_is_error(err)) 461240116Smarcel goto out_srcdir; 462240116Smarcel 463240116Smarcel err = atf_fs_path_append_fmt(&exe, "%s", progname); 464240116Smarcel if (atf_is_error(err)) 465240116Smarcel goto out_exe; 466240116Smarcel 467240116Smarcel err = atf_fs_exists(&exe, &b); 468240116Smarcel if (!atf_is_error(err)) { 469240116Smarcel if (b) { 470240116Smarcel err = atf_map_insert(&p->m_config, "srcdir", 471240116Smarcel strdup(atf_fs_path_cstring(&srcdir)), true); 472240116Smarcel } else { 473240116Smarcel err = user_error("Cannot find the test program in the source " 474240116Smarcel "directory `%s'", atf_fs_path_cstring(&srcdir)); 475240116Smarcel } 476240116Smarcel } 477240116Smarcel 478240116Smarcelout_exe: 479240116Smarcel atf_fs_path_fini(&exe); 480240116Smarcelout_srcdir: 481240116Smarcel atf_fs_path_fini(&srcdir); 482240116Smarcelout: 483240116Smarcel return err; 484240116Smarcel} 485240116Smarcel 486240116Smarcelstatic 487240116Smarcelatf_error_t 488240116Smarcelrun_tc(const atf_tp_t *tp, struct params *p, int *exitcode) 489240116Smarcel{ 490240116Smarcel atf_error_t err; 491240116Smarcel 492240116Smarcel err = atf_no_error(); 493240116Smarcel 494240116Smarcel if (!atf_tp_has_tc(tp, p->m_tcname)) { 495240116Smarcel err = usage_error("Unknown test case `%s'", p->m_tcname); 496240116Smarcel goto out; 497240116Smarcel } 498240116Smarcel 499240116Smarcel if (!atf_env_has("__RUNNING_INSIDE_ATF_RUN") || strcmp(atf_env_get( 500240116Smarcel "__RUNNING_INSIDE_ATF_RUN"), "internal-yes-value") != 0) 501240116Smarcel { 502240116Smarcel print_warning("Running test cases without atf-run(1) is unsupported"); 503240116Smarcel print_warning("No isolation nor timeout control is being applied; you " 504240116Smarcel "may get unexpected failures; see atf-test-case(4)"); 505240116Smarcel } 506240116Smarcel 507240116Smarcel switch (p->m_tcpart) { 508240116Smarcel case BODY: 509240116Smarcel err = atf_tp_run(tp, p->m_tcname, atf_fs_path_cstring(&p->m_resfile)); 510240116Smarcel if (atf_is_error(err)) { 511240116Smarcel /* TODO: Handle error */ 512240116Smarcel *exitcode = EXIT_FAILURE; 513240116Smarcel atf_error_free(err); 514240116Smarcel } else { 515240116Smarcel *exitcode = EXIT_SUCCESS; 516240116Smarcel } 517240116Smarcel 518240116Smarcel break; 519240116Smarcel 520240116Smarcel case CLEANUP: 521240116Smarcel err = atf_tp_cleanup(tp, p->m_tcname); 522240116Smarcel if (atf_is_error(err)) { 523240116Smarcel /* TODO: Handle error */ 524240116Smarcel *exitcode = EXIT_FAILURE; 525240116Smarcel atf_error_free(err); 526240116Smarcel } else { 527240116Smarcel *exitcode = EXIT_SUCCESS; 528240116Smarcel } 529240116Smarcel 530240116Smarcel break; 531240116Smarcel 532240116Smarcel default: 533240116Smarcel UNREACHABLE; 534240116Smarcel } 535240116Smarcel 536240116Smarcel INV(!atf_is_error(err)); 537240116Smarcelout: 538240116Smarcel return err; 539240116Smarcel} 540240116Smarcel 541240116Smarcelstatic 542240116Smarcelatf_error_t 543240116Smarcelcontrolled_main(int argc, char **argv, 544240116Smarcel atf_error_t (*add_tcs_hook)(atf_tp_t *), 545240116Smarcel int *exitcode) 546240116Smarcel{ 547240116Smarcel atf_error_t err; 548240116Smarcel struct params p; 549240116Smarcel atf_tp_t tp; 550240116Smarcel char **raw_config; 551240116Smarcel 552240116Smarcel err = process_params(argc, argv, &p); 553240116Smarcel if (atf_is_error(err)) 554240116Smarcel goto out; 555240116Smarcel 556240116Smarcel err = handle_srcdir(&p); 557240116Smarcel if (atf_is_error(err)) 558240116Smarcel goto out_p; 559240116Smarcel 560240116Smarcel raw_config = atf_map_to_charpp(&p.m_config); 561240116Smarcel if (raw_config == NULL) { 562240116Smarcel err = atf_no_memory_error(); 563240116Smarcel goto out_p; 564240116Smarcel } 565240116Smarcel err = atf_tp_init(&tp, (const char* const*)raw_config); 566240116Smarcel atf_utils_free_charpp(raw_config); 567240116Smarcel if (atf_is_error(err)) 568240116Smarcel goto out_p; 569240116Smarcel 570240116Smarcel err = add_tcs_hook(&tp); 571240116Smarcel if (atf_is_error(err)) 572240116Smarcel goto out_tp; 573240116Smarcel 574240116Smarcel if (p.m_do_list) { 575240116Smarcel list_tcs(&tp); 576240116Smarcel INV(!atf_is_error(err)); 577240116Smarcel *exitcode = EXIT_SUCCESS; 578240116Smarcel } else { 579240116Smarcel err = run_tc(&tp, &p, exitcode); 580240116Smarcel } 581240116Smarcel 582240116Smarcelout_tp: 583240116Smarcel atf_tp_fini(&tp); 584240116Smarcelout_p: 585240116Smarcel params_fini(&p); 586240116Smarcelout: 587240116Smarcel return err; 588240116Smarcel} 589240116Smarcel 590240116Smarcelint 591240116Smarcelatf_tp_main(int argc, char **argv, atf_error_t (*add_tcs_hook)(atf_tp_t *)) 592240116Smarcel{ 593240116Smarcel atf_error_t err; 594240116Smarcel int exitcode; 595240116Smarcel 596240116Smarcel progname = strrchr(argv[0], '/'); 597240116Smarcel if (progname == NULL) 598240116Smarcel progname = argv[0]; 599240116Smarcel else 600240116Smarcel progname++; 601240116Smarcel 602240116Smarcel /* Libtool workaround: if running from within the source tree (binaries 603240116Smarcel * that are not installed yet), skip the "lt-" prefix added to files in 604240116Smarcel * the ".libs" directory to show the real (not temporary) name. */ 605240116Smarcel if (strncmp(progname, "lt-", 3) == 0) 606240116Smarcel progname += 3; 607240116Smarcel 608240116Smarcel exitcode = EXIT_FAILURE; /* Silence GCC warning. */ 609240116Smarcel err = controlled_main(argc, argv, add_tcs_hook, &exitcode); 610240116Smarcel if (atf_is_error(err)) { 611240116Smarcel print_error(err); 612240116Smarcel atf_error_free(err); 613240116Smarcel exitcode = EXIT_FAILURE; 614240116Smarcel } 615240116Smarcel 616240116Smarcel return exitcode; 617240116Smarcel} 618