Bring in an errno.9 manual page (based on NetBSD's).
[dragonfly.git] / usr.bin / dfregress / testcase.c
blobf69883aa75a8bc6532acc1f423c4017d6aa0c1f5
1 /*
2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
30 #include <sys/resource.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdint.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <pwd.h>
44 #include <err.h>
46 #include <libprop/proplib.h>
48 #include "parser.h"
49 #include "testcase.h"
50 #include "runlist.h"
51 #include "config.h"
52 #include <dfregress.h>
54 prop_dictionary_t
55 testcase_from_struct(struct testcase *testcase)
57 int i, r;
58 prop_dictionary_t dict, testcase_dict;
59 prop_array_t a;
60 char *s;
62 testcase_dict = prop_dictionary_create();
63 if (testcase_dict == NULL)
64 err(1, "could not create testcase dict");
65 r = prop_dictionary_set_cstring(testcase_dict, "name", testcase->name);
66 if (r == 0)
67 err(1, "prop_dictionary operation failed");
68 r = prop_dictionary_set_cstring(testcase_dict, "type", testcase->type_str);
69 if (r == 0)
70 err(1, "prop_dictionary operation failed");
72 a = prop_array_create_with_capacity(testcase->argc+1);
73 if (a == NULL)
74 err(1, "prop_array_create for argv failed");
76 s = strrchr(testcase->name, '/');
77 r = prop_array_set_cstring(a, 0, (s == NULL) ? testcase->name : s+1);
78 if (r == 0)
79 err(1, "prop_array_set_cstring operation failed");
81 for (i = 1; i <= testcase->argc; i++) {
82 r = prop_array_set_cstring(a, i, testcase->argv[i-1]);
83 if (r == 0)
84 err(1, "prop_array_set_cstring operation failed");
87 r = prop_dictionary_set(testcase_dict, "args", a);
88 if (r == 0)
89 err(1, "prop_dictionary_set \"args\" failed");
91 dict = prop_dictionary_create();
92 if (dict == NULL)
93 err(1, "could not create dict");
95 r = prop_dictionary_set_int32(dict, "timeout_in_secs",
96 (int32_t)testcase->opts.timeout_in_secs);
97 if (r == 0)
98 err(1, "prop_dictionary operation failed");
100 r = prop_dictionary_set_uint32(dict, "flags", testcase->opts.flags);
101 if (r == 0)
102 err(1, "prop_dictionary operation failed");
104 if (testcase->opts.pre_cmd != NULL) {
105 r = prop_dictionary_set_cstring(dict, "pre_cmd",
106 testcase->opts.pre_cmd);
107 if (r == 0)
108 err(1, "prop_dictionary operation failed");
111 if (testcase->opts.post_cmd != NULL) {
112 r = prop_dictionary_set_cstring(dict, "post_cmd",
113 testcase->opts.post_cmd);
114 if (r == 0)
115 err(1, "prop_dictionary operation failed");
118 r = prop_dictionary_set_uint32(dict, "runas_uid",
119 (uint32_t)testcase->opts.runas_uid);
120 if (r == 0)
121 err(1, "prop_dictionary operation failed");
123 r = prop_dictionary_set_cstring(dict, "make_cmd",
124 (testcase->opts.make_cmd != NULL) ? testcase->opts.make_cmd : "make");
125 if (r == 0)
126 err(1, "prop_dictionary operation failed");
128 r = prop_dictionary_set(testcase_dict, "opts", dict);
129 if (r == 0)
130 err(1, "prop_dictionary operation failed");
132 return testcase_dict;
135 struct timeval *
136 testcase_get_timeout(prop_dictionary_t testcase)
138 static struct timeval tv;
139 int32_t val;
140 int r;
142 r = prop_dictionary_get_int32(prop_dictionary_get(testcase, "opts"),
143 "timeout_in_secs", &val);
144 if (r == 0)
145 err(1, "prop_dictionary operation failed");
147 tv.tv_usec = 0;
148 tv.tv_sec = (long)val;
150 return &tv;
154 testcase_get_type(prop_dictionary_t testcase)
156 const char *type;
157 int r;
159 r = prop_dictionary_get_cstring_nocopy(testcase, "type", &type);
160 if (r == 0)
161 err(1, "prop_dictionary operation failed");
163 if (strcmp(type, "userland") == 0)
164 return TESTCASE_TYPE_USERLAND;
165 else if (strcmp(type, "kernel") == 0)
166 return TESTCASE_TYPE_KERNEL;
167 else if (strcmp(type, "buildonly") == 0)
168 return TESTCASE_TYPE_BUILDONLY;
170 return 0;
173 const char *
174 testcase_get_type_desc(prop_dictionary_t testcase)
176 const char *str;
177 int r;
179 r = prop_dictionary_get_cstring_nocopy(testcase, "type", &str);
180 if (r == 0)
181 err(1, "prop_dictionary operation failed");
183 return str;
186 const char *
187 testcase_get_name(prop_dictionary_t testcase)
189 const char *str;
190 int r;
192 r = prop_dictionary_get_cstring_nocopy(testcase, "name", &str);
193 if (r == 0)
194 err(1, "prop_dictionary operation failed");
196 return str;
199 const char **
200 testcase_get_args(prop_dictionary_t testcase)
202 /* Sane limit of 63 arguments... who wants more than that? */
203 static const char *argv[64];
204 unsigned int i, count;
205 prop_array_t a;
206 int r;
208 a = prop_dictionary_get(testcase, "args");
209 if (a == NULL)
210 err(1, "testcase_get_args NULL array");
212 count = prop_array_count(a);
214 for (i = 0; i < count; i++) {
215 r = prop_array_get_cstring_nocopy(a, i, &argv[i]);
216 if (r == 0)
217 err(1, "error building argv");
220 argv[i] = NULL;
222 return argv;
225 uint32_t
226 testcase_get_flags(prop_dictionary_t testcase)
228 uint32_t flags;
229 int r;
231 r = prop_dictionary_get_uint32(prop_dictionary_get(testcase, "opts"),
232 "flags", &flags);
233 if (r == 0)
234 err(1, "prop_dictionary operation failed");
236 return flags;
240 testcase_get_precmd_type(prop_dictionary_t testcase)
242 uint32_t flags = testcase_get_flags(testcase);
244 return (flags & (TESTCASE_INT_PRE | TESTCASE_CUSTOM_PRE));
248 testcase_get_postcmd_type(prop_dictionary_t testcase)
250 uint32_t flags = testcase_get_flags(testcase);
252 return (flags & (TESTCASE_INT_POST | TESTCASE_CUSTOM_POST));
256 testcase_needs_setuid(prop_dictionary_t testcase)
258 uint32_t flags = testcase_get_flags(testcase);
260 return (flags & TESTCASE_RUN_AS);
263 uid_t
264 testcase_get_runas_uid(prop_dictionary_t testcase)
266 uint32_t uid = 0;
267 int r;
269 r = prop_dictionary_get_uint32(
270 prop_dictionary_get(testcase, "opts"), "runas_uid", &uid);
271 if (r == 0)
272 err(1, "prop_dictionary operation failed");
274 return (uid_t)uid;
277 const char *
278 testcase_get_custom_precmd(prop_dictionary_t testcase)
280 const char *str;
281 int r;
283 r = prop_dictionary_get_cstring_nocopy(
284 prop_dictionary_get(testcase, "opts"), "pre_cmd", &str);
285 if (r == 0)
286 err(1, "prop_dictionary operation failed");
288 return str;
291 const char *
292 testcase_get_custom_postcmd(prop_dictionary_t testcase)
294 const char *str;
295 int r;
297 r = prop_dictionary_get_cstring_nocopy(
298 prop_dictionary_get(testcase, "opts"), "pre_cmd", &str);
299 if (r == 0)
300 err(1, "prop_dictionary operation failed");
302 return str;
305 const char *
306 testcase_get_make_cmd(prop_dictionary_t testcase)
308 const char *str;
309 int r;
311 r = prop_dictionary_get_cstring_nocopy(
312 prop_dictionary_get(testcase, "opts"), "make_cmd", &str);
313 if (r == 0)
314 err(1, "prop_dictionary operation failed");
316 return str;
319 prop_dictionary_t
320 testcase_get_result_dict(prop_dictionary_t testcase)
322 prop_dictionary_t result_dict;
323 int r;
325 result_dict = prop_dictionary_get(testcase, "result");
326 if (result_dict == NULL) {
327 result_dict = prop_dictionary_create();
328 if (result_dict == NULL)
329 err(1, "could not allocate new result dict");
331 r = prop_dictionary_set(testcase, "result", result_dict);
332 if (r == 0)
333 err(1, "prop_dictionary operation failed");
336 return result_dict;
340 testcase_set_build_buf(prop_dictionary_t testcase, const char *buf)
342 prop_dictionary_t dict = testcase_get_result_dict(testcase);
344 return !prop_dictionary_set_cstring(dict, "build_buf", buf);
348 testcase_set_cleanup_buf(prop_dictionary_t testcase, const char *buf)
350 prop_dictionary_t dict = testcase_get_result_dict(testcase);
352 return !prop_dictionary_set_cstring(dict, "cleanup_buf", buf);
356 testcase_set_sys_buf(prop_dictionary_t testcase, const char *buf)
358 prop_dictionary_t dict = testcase_get_result_dict(testcase);
360 return !prop_dictionary_set_cstring(dict, "sys_buf", buf);
364 testcase_set_precmd_buf(prop_dictionary_t testcase, const char *buf)
366 prop_dictionary_t dict = testcase_get_result_dict(testcase);
368 return !prop_dictionary_set_cstring(dict, "precmd_buf", buf);
372 testcase_set_postcmd_buf(prop_dictionary_t testcase, const char *buf)
374 prop_dictionary_t dict = testcase_get_result_dict(testcase);
376 return !prop_dictionary_set_cstring(dict, "postcmd_buf", buf);
380 testcase_set_stdout_buf(prop_dictionary_t testcase, const char *buf)
382 prop_dictionary_t dict = testcase_get_result_dict(testcase);
384 return !prop_dictionary_set_cstring(dict, "stdout_buf", buf);
388 testcase_set_stderr_buf(prop_dictionary_t testcase, const char *buf)
390 prop_dictionary_t dict = testcase_get_result_dict(testcase);
392 return !prop_dictionary_set_cstring(dict, "stderr_buf", buf);
396 testcase_set_result(prop_dictionary_t testcase, int result)
398 prop_dictionary_t dict = testcase_get_result_dict(testcase);
400 return !prop_dictionary_set_int32(dict, "result", result);
404 testcase_set_exit_value(prop_dictionary_t testcase, int exitval)
406 prop_dictionary_t dict = testcase_get_result_dict(testcase);
408 return !prop_dictionary_set_int32(dict, "exit_value", exitval);
412 testcase_set_signal(prop_dictionary_t testcase, int sig)
414 prop_dictionary_t dict = testcase_get_result_dict(testcase);
416 return !prop_dictionary_set_int32(dict, "signal", sig);
419 const char *
420 testcase_get_build_buf(prop_dictionary_t testcase)
422 const char *str = "";
424 prop_dictionary_t dict = testcase_get_result_dict(testcase);
425 prop_dictionary_get_cstring_nocopy(dict, "build_buf", &str);
427 return str;
430 const char *
431 testcase_get_cleanup_buf(prop_dictionary_t testcase)
433 const char *str = "";
435 prop_dictionary_t dict = testcase_get_result_dict(testcase);
436 prop_dictionary_get_cstring_nocopy(dict, "cleanup_buf", &str);
438 return str;
441 const char *
442 testcase_get_sys_buf(prop_dictionary_t testcase)
444 const char *str = "";
446 prop_dictionary_t dict = testcase_get_result_dict(testcase);
447 prop_dictionary_get_cstring_nocopy(dict, "sys_buf", &str);
449 return str;
452 const char *
453 testcase_get_precmd_buf(prop_dictionary_t testcase)
455 const char *str = "";
457 prop_dictionary_t dict = testcase_get_result_dict(testcase);
458 prop_dictionary_get_cstring_nocopy(dict, "precmd_buf", &str);
460 return str;
463 const char *
464 testcase_get_postcmd_buf(prop_dictionary_t testcase)
466 const char *str = "";
468 prop_dictionary_t dict = testcase_get_result_dict(testcase);
469 prop_dictionary_get_cstring_nocopy(dict, "postcmd_buf", &str);
471 return str;
474 const char *
475 testcase_get_stdout_buf(prop_dictionary_t testcase)
477 const char *str = "";
479 prop_dictionary_t dict = testcase_get_result_dict(testcase);
480 prop_dictionary_get_cstring_nocopy(dict, "stdout_buf", &str);
482 return str;
485 const char *
486 testcase_get_stderr_buf(prop_dictionary_t testcase)
488 const char *str = "";
490 prop_dictionary_t dict = testcase_get_result_dict(testcase);
491 prop_dictionary_get_cstring_nocopy(dict, "stderr_buf", &str);
493 return str;
497 testcase_get_result(prop_dictionary_t testcase)
499 int32_t result = RESULT_NOTRUN;
501 prop_dictionary_t dict = testcase_get_result_dict(testcase);
502 prop_dictionary_get_int32(dict, "result", &result);
504 return (int)result;
507 const char *
508 testcase_get_result_desc(prop_dictionary_t testcase)
510 int result = testcase_get_result(testcase);
512 switch(result) {
513 case RESULT_TIMEOUT: return "TIMEOUT";
514 case RESULT_SIGNALLED: return "SIGNALLED";
515 case RESULT_NOTRUN: return "NOT RUN";
516 case RESULT_FAIL: return "FAIL";
517 case RESULT_PASS: return "PASS";
518 case RESULT_PREFAIL: return "PREFAIL";
519 case RESULT_POSTFAIL: return "POSTFAIL";
520 case RESULT_BUILDFAIL: return "BUILDFAIL";
521 default: return "UNKNOWN";
526 testcase_get_exit_value(prop_dictionary_t testcase)
528 int32_t exitval;
529 int r;
531 prop_dictionary_t dict = testcase_get_result_dict(testcase);
532 r = prop_dictionary_get_int32(dict, "exit_value", &exitval);
533 if (r == 0)
534 err(1, "prop_dictionary operation failed");
536 return (int)exitval;
540 testcase_get_signal(prop_dictionary_t testcase)
542 int32_t sig;
543 int r;
545 prop_dictionary_t dict = testcase_get_result_dict(testcase);
546 r = prop_dictionary_get_int32(dict, "signal", &sig);
547 if (r == 0)
548 err(1, "prop_dictionary operation failed");
550 return (int)sig;
554 parse_testcase_option(struct testcase_options *opts, char *option)
556 struct passwd *pwd;
557 char *parameter, *endptr;
558 long lval;
559 int noparam = 0;
561 parameter = strchr(option, '=');
562 noparam = (parameter == NULL);
563 if (!noparam)
565 *parameter = '\0';
566 ++parameter;
569 if (strcmp(option, "timeout") == 0) {
570 if (noparam)
571 syntax_error("The option 'timeout' needs a parameter");
572 /* NOTREACHED */
574 lval = strtol(parameter, &endptr, 10);
575 if (*endptr != '\0')
576 syntax_error("The option 'timeout' expects an integer "
577 "parameter, not '%s'", parameter);
578 /* NOTREACHED */
580 opts->timeout_in_secs = (long int)lval;
581 } else if (strcmp(option, "intpre") == 0) {
582 opts->flags |= TESTCASE_INT_PRE;
583 } else if (strcmp(option, "intpost") == 0) {
584 opts->flags |= TESTCASE_INT_POST;
585 } else if (strcmp(option, "pre") == 0) {
586 if (noparam)
587 syntax_error("The option 'pre' needs a parameter");
588 /* NOTREACHED */
590 opts->flags |= TESTCASE_CUSTOM_PRE;
591 opts->pre_cmd = strdup(parameter);
592 } else if (strcmp(option, "post") == 0) {
593 if (noparam)
594 syntax_error("The option 'post' needs a parameter");
595 /* NOTREACHED */
597 opts->flags |= TESTCASE_CUSTOM_POST;
598 opts->post_cmd = strdup(parameter);
599 } else if (strcmp(option, "runas") == 0) {
600 if (noparam)
601 syntax_error("The option 'runas' needs a parameter");
602 /* NOTREACHED */
604 if ((pwd = getpwnam(parameter))) {
605 opts->runas_uid = pwd->pw_uid;
606 opts->flags |= TESTCASE_RUN_AS;
607 } else {
608 syntax_error("invalid user name for 'runas': %s",
609 parameter);
611 } else if (strcmp(option, "nobuild") == 0) {
612 opts->flags |= TESTCASE_NOBUILD;
613 } else if (strcmp(option, "make") == 0) {
614 if (noparam)
615 syntax_error("The option 'make' needs a parameter");
616 /* NOTREACHED */
618 opts->make_cmd = strdup(parameter);
619 } else if (strcmp(option, "defaults") == 0) {
620 /* Valid option, does nothing */
621 } else {
622 syntax_error("Unknown option: %s", option);
623 /* NOTREACHED */
626 return 0;
629 void
630 testcase_entry_parser(void *arg, char **tokens)
632 prop_array_t runlist;
633 prop_dictionary_t testcase_dict;
634 struct testcase *testcase;
635 char *options[256];
636 int i, r, nopts;
638 runlist = (prop_array_t)arg;
640 testcase = malloc(sizeof(struct testcase));
641 if (testcase == NULL)
642 err(1, "could not malloc testcase memory");
644 bzero(testcase, sizeof(struct testcase));
646 entry_check_num_args(tokens, 3);
648 testcase->argv = &tokens[3];
649 for (testcase->argc = 0; testcase->argv[testcase->argc] != NULL;
650 testcase->argc++)
653 nopts = parse_options(tokens[2], options);
655 testcase->name = tokens[0];
657 if (strcmp(tokens[1], "userland") == 0) {
658 testcase->type = TESTCASE_TYPE_USERLAND;
659 } else if (strcmp(tokens[1], "kernel") == 0) {
660 testcase->type = TESTCASE_TYPE_KERNEL;
661 } else if (strcmp(tokens[1], "buildonly") == 0) {
662 testcase->type = TESTCASE_TYPE_BUILDONLY;
663 } else {
664 syntax_error("Unknown type: %s", tokens[1]);
665 /* NOTREACHED */
668 testcase->type_str = tokens[1];
670 config_get_defaults(&testcase->opts);
672 for (i = 0; i < nopts; i++)
673 parse_testcase_option(&testcase->opts, options[i]);
675 if ((testcase->type != TESTCASE_TYPE_USERLAND) &&
676 (testcase->opts.flags & (TESTCASE_INT_PRE | TESTCASE_INT_POST)))
677 syntax_error("'intpre' and 'intpost' options are only valid "
678 "with testcase type 'userland'");
680 if ((testcase->type == TESTCASE_TYPE_BUILDONLY) &&
681 (testcase->opts.flags & TESTCASE_NOBUILD))
682 syntax_error("'nobuild' option is incompatible with type "
683 "'buildonly'");
685 testcase_dict = testcase_from_struct(testcase);
686 if (testcase->opts.pre_cmd != NULL)
687 free(testcase->opts.pre_cmd);
688 if (testcase->opts.post_cmd != NULL)
689 free(testcase->opts.post_cmd);
690 if (testcase->opts.make_cmd != NULL)
691 free(testcase->opts.make_cmd);
692 free(testcase);
694 r = prop_array_add(runlist, testcase_dict);
695 if (r == 0)
696 err(1, "prop_array_add failed");