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