xref: /freebsd/contrib/atf/atf-c/detail/tp_main.c (revision c243e4902be8df1e643c76b5f18b68bb77cc5268)
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