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