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