usr.sbin/makefs: Sync with sys/vfs/hammer2
[dragonfly.git] / usr.bin / dfregress / testcase.c
blob306979a3f93f4c54452a2fa9a2f29b77f0ca23dc
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 r = prop_dictionary_set_int32(testcase_dict, "argc",
73 (int32_t)testcase->argc);
74 if (r == 0)
75 err(1, "prop_dictionary operation failed");
77 a = prop_array_create_with_capacity(testcase->argc+1);
78 if (a == NULL)
79 err(1, "prop_array_create for argv failed");
81 s = strrchr(testcase->name, '/');
82 r = prop_array_set_cstring(a, 0, (s == NULL) ? testcase->name : s+1);
83 if (r == 0)
84 err(1, "prop_array_set_cstring operation failed");
86 for (i = 1; i <= testcase->argc; i++) {
87 r = prop_array_set_cstring(a, i, testcase->argv[i-1]);
88 if (r == 0)
89 err(1, "prop_array_set_cstring operation failed");
92 r = prop_dictionary_set(testcase_dict, "args", a);
93 if (r == 0)
94 err(1, "prop_dictionary_set \"args\" failed");
96 dict = prop_dictionary_create();
97 if (dict == NULL)
98 err(1, "could not create dict");
100 r = prop_dictionary_set_int32(dict, "timeout_in_secs",
101 (int32_t)testcase->opts.timeout_in_secs);
102 if (r == 0)
103 err(1, "prop_dictionary operation failed");
105 r = prop_dictionary_set_int32(dict, "rc",
106 (int32_t)testcase->opts.rc);
107 if (r == 0)
108 err(1, "prop_dictionary operation failed");
110 r = prop_dictionary_set_uint32(dict, "flags", testcase->opts.flags);
111 if (r == 0)
112 err(1, "prop_dictionary operation failed");
114 if (testcase->opts.pre_cmd != NULL) {
115 r = prop_dictionary_set_cstring(dict, "pre_cmd",
116 testcase->opts.pre_cmd);
117 if (r == 0)
118 err(1, "prop_dictionary operation failed");
121 if (testcase->opts.post_cmd != NULL) {
122 r = prop_dictionary_set_cstring(dict, "post_cmd",
123 testcase->opts.post_cmd);
124 if (r == 0)
125 err(1, "prop_dictionary operation failed");
128 if (testcase->opts.interpreter != NULL) {
129 r = prop_dictionary_set_cstring(dict, "interpreter",
130 testcase->opts.interpreter);
131 if (r == 0)
132 err(1, "prop_dictionary operation failed");
135 r = prop_dictionary_set_uint32(dict, "runas_uid",
136 (uint32_t)testcase->opts.runas_uid);
137 if (r == 0)
138 err(1, "prop_dictionary operation failed");
140 r = prop_dictionary_set_cstring(dict, "make_cmd",
141 (testcase->opts.make_cmd != NULL) ? testcase->opts.make_cmd : "make");
142 if (r == 0)
143 err(1, "prop_dictionary operation failed");
145 r = prop_dictionary_set(testcase_dict, "opts", dict);
146 if (r == 0)
147 err(1, "prop_dictionary operation failed");
149 return testcase_dict;
152 struct timeval *
153 testcase_get_timeout(prop_dictionary_t testcase)
155 static struct timeval tv;
156 int32_t val;
157 int r;
159 r = prop_dictionary_get_int32(prop_dictionary_get(testcase, "opts"),
160 "timeout_in_secs", &val);
161 if (r == 0)
162 err(1, "prop_dictionary operation failed");
164 tv.tv_usec = 0;
165 tv.tv_sec = (long)val;
167 return &tv;
171 testcase_get_type(prop_dictionary_t testcase)
173 const char *type;
174 int r;
176 r = prop_dictionary_get_cstring_nocopy(testcase, "type", &type);
177 if (r == 0)
178 err(1, "prop_dictionary operation failed");
180 if (strcmp(type, "userland") == 0)
181 return TESTCASE_TYPE_USERLAND;
182 else if (strcmp(type, "kernel") == 0)
183 return TESTCASE_TYPE_KERNEL;
184 else if (strcmp(type, "buildonly") == 0)
185 return TESTCASE_TYPE_BUILDONLY;
187 return 0;
190 const char *
191 testcase_get_type_desc(prop_dictionary_t testcase)
193 const char *str;
194 int r;
196 r = prop_dictionary_get_cstring_nocopy(testcase, "type", &str);
197 if (r == 0)
198 err(1, "prop_dictionary operation failed");
200 return str;
203 const char *
204 testcase_get_name(prop_dictionary_t testcase)
206 const char *str;
207 int r;
209 r = prop_dictionary_get_cstring_nocopy(testcase, "name", &str);
210 if (r == 0)
211 err(1, "prop_dictionary operation failed");
213 return str;
217 testcase_get_argc(prop_dictionary_t testcase)
219 int32_t argc;
220 int r;
222 r = prop_dictionary_get_int32(testcase, "argc", &argc);
223 if (r == 0)
224 err(1, "prop_dictionary operation failed for argc");
226 return argc;
229 const char **
230 testcase_get_args(prop_dictionary_t testcase)
232 /* Sane limit of 63 arguments... who wants more than that? */
233 static const char *argv[64];
234 unsigned int i, count;
235 prop_array_t a;
236 int r;
238 a = prop_dictionary_get(testcase, "args");
239 if (a == NULL)
240 err(1, "testcase_get_args NULL array");
242 count = prop_array_count(a);
244 for (i = 0; i < count; i++) {
245 r = prop_array_get_cstring_nocopy(a, i, &argv[i]);
246 if (r == 0)
247 err(1, "error building argv");
250 argv[i] = NULL;
252 return argv;
255 uint32_t
256 testcase_get_flags(prop_dictionary_t testcase)
258 uint32_t flags;
259 int r;
261 r = prop_dictionary_get_uint32(prop_dictionary_get(testcase, "opts"),
262 "flags", &flags);
263 if (r == 0)
264 err(1, "prop_dictionary operation failed");
266 return flags;
270 testcase_get_precmd_type(prop_dictionary_t testcase)
272 uint32_t flags = testcase_get_flags(testcase);
274 return (flags & (TESTCASE_INT_PRE | TESTCASE_CUSTOM_PRE));
278 testcase_get_rc(prop_dictionary_t testcase)
280 int32_t rc;
281 int r;
283 r = prop_dictionary_get_int32(prop_dictionary_get(testcase, "opts"),
284 "rc", &rc);
285 if (r == 0)
286 err(1, "prop_dictionary operation failed for rc");
288 return rc;
292 testcase_get_postcmd_type(prop_dictionary_t testcase)
294 uint32_t flags = testcase_get_flags(testcase);
296 return (flags & (TESTCASE_INT_POST | TESTCASE_CUSTOM_POST));
300 testcase_needs_setuid(prop_dictionary_t testcase)
302 uint32_t flags = testcase_get_flags(testcase);
304 return (flags & TESTCASE_RUN_AS);
307 uid_t
308 testcase_get_runas_uid(prop_dictionary_t testcase)
310 uint32_t uid = 0;
311 int r;
313 r = prop_dictionary_get_uint32(
314 prop_dictionary_get(testcase, "opts"), "runas_uid", &uid);
315 if (r == 0)
316 err(1, "prop_dictionary operation failed");
318 return (uid_t)uid;
321 const char *
322 testcase_get_custom_precmd(prop_dictionary_t testcase)
324 const char *str;
325 int r;
327 r = prop_dictionary_get_cstring_nocopy(
328 prop_dictionary_get(testcase, "opts"), "pre_cmd", &str);
329 if (r == 0)
330 err(1, "prop_dictionary operation failed");
332 return str;
335 const char *
336 testcase_get_custom_postcmd(prop_dictionary_t testcase)
338 const char *str;
339 int r;
341 r = prop_dictionary_get_cstring_nocopy(
342 prop_dictionary_get(testcase, "opts"), "pre_cmd", &str);
343 if (r == 0)
344 err(1, "prop_dictionary operation failed");
346 return str;
349 static const char *
350 _testcase_get_interpreter(prop_dictionary_t testcase, bool fatal)
352 const char *str;
353 int r;
355 r = prop_dictionary_get_cstring_nocopy(
356 prop_dictionary_get(testcase, "opts"), "interpreter", &str);
357 if (r == 0) {
358 if (fatal)
359 err(1, "prop_dictionary operation failed for interpreter");
360 else
361 return NULL;
364 return str;
367 const char *
368 testcase_get_interpreter(prop_dictionary_t testcase)
370 return _testcase_get_interpreter(testcase, true);
373 const char *
374 testcase_get_interpreter_noexit(prop_dictionary_t testcase)
376 return _testcase_get_interpreter(testcase, false);
379 const char *
380 testcase_get_make_cmd(prop_dictionary_t testcase)
382 const char *str;
383 int r;
385 r = prop_dictionary_get_cstring_nocopy(
386 prop_dictionary_get(testcase, "opts"), "make_cmd", &str);
387 if (r == 0)
388 err(1, "prop_dictionary operation failed");
390 return str;
393 prop_dictionary_t
394 testcase_get_result_dict(prop_dictionary_t testcase)
396 prop_dictionary_t result_dict;
397 int r;
399 result_dict = prop_dictionary_get(testcase, "result");
400 if (result_dict == NULL) {
401 result_dict = prop_dictionary_create();
402 if (result_dict == NULL)
403 err(1, "could not allocate new result dict");
405 r = prop_dictionary_set(testcase, "result", result_dict);
406 if (r == 0)
407 err(1, "prop_dictionary operation failed");
410 return result_dict;
414 testcase_set_build_buf(prop_dictionary_t testcase, const char *buf)
416 prop_dictionary_t dict = testcase_get_result_dict(testcase);
418 return !prop_dictionary_set_cstring(dict, "build_buf", buf);
422 testcase_set_cleanup_buf(prop_dictionary_t testcase, const char *buf)
424 prop_dictionary_t dict = testcase_get_result_dict(testcase);
426 return !prop_dictionary_set_cstring(dict, "cleanup_buf", buf);
430 testcase_set_sys_buf(prop_dictionary_t testcase, const char *buf)
432 prop_dictionary_t dict = testcase_get_result_dict(testcase);
434 return !prop_dictionary_set_cstring(dict, "sys_buf", buf);
438 testcase_set_precmd_buf(prop_dictionary_t testcase, const char *buf)
440 prop_dictionary_t dict = testcase_get_result_dict(testcase);
442 return !prop_dictionary_set_cstring(dict, "precmd_buf", buf);
446 testcase_set_postcmd_buf(prop_dictionary_t testcase, const char *buf)
448 prop_dictionary_t dict = testcase_get_result_dict(testcase);
450 return !prop_dictionary_set_cstring(dict, "postcmd_buf", buf);
454 testcase_set_stdout_buf(prop_dictionary_t testcase, const char *buf)
456 prop_dictionary_t dict = testcase_get_result_dict(testcase);
458 return !prop_dictionary_set_cstring(dict, "stdout_buf", buf);
462 testcase_set_stderr_buf(prop_dictionary_t testcase, const char *buf)
464 prop_dictionary_t dict = testcase_get_result_dict(testcase);
466 return !prop_dictionary_set_cstring(dict, "stderr_buf", buf);
470 testcase_set_result(prop_dictionary_t testcase, int result)
472 prop_dictionary_t dict = testcase_get_result_dict(testcase);
474 return !prop_dictionary_set_int32(dict, "result", result);
478 testcase_set_exit_value(prop_dictionary_t testcase, int exitval)
480 prop_dictionary_t dict = testcase_get_result_dict(testcase);
482 return !prop_dictionary_set_int32(dict, "exit_value", exitval);
486 testcase_set_signal(prop_dictionary_t testcase, int sig)
488 prop_dictionary_t dict = testcase_get_result_dict(testcase);
490 return !prop_dictionary_set_int32(dict, "signal", sig);
493 const char *
494 testcase_get_build_buf(prop_dictionary_t testcase)
496 const char *str = "";
498 prop_dictionary_t dict = testcase_get_result_dict(testcase);
499 prop_dictionary_get_cstring_nocopy(dict, "build_buf", &str);
501 return str;
504 const char *
505 testcase_get_cleanup_buf(prop_dictionary_t testcase)
507 const char *str = "";
509 prop_dictionary_t dict = testcase_get_result_dict(testcase);
510 prop_dictionary_get_cstring_nocopy(dict, "cleanup_buf", &str);
512 return str;
515 const char *
516 testcase_get_sys_buf(prop_dictionary_t testcase)
518 const char *str = "";
520 prop_dictionary_t dict = testcase_get_result_dict(testcase);
521 prop_dictionary_get_cstring_nocopy(dict, "sys_buf", &str);
523 return str;
526 const char *
527 testcase_get_precmd_buf(prop_dictionary_t testcase)
529 const char *str = "";
531 prop_dictionary_t dict = testcase_get_result_dict(testcase);
532 prop_dictionary_get_cstring_nocopy(dict, "precmd_buf", &str);
534 return str;
537 const char *
538 testcase_get_postcmd_buf(prop_dictionary_t testcase)
540 const char *str = "";
542 prop_dictionary_t dict = testcase_get_result_dict(testcase);
543 prop_dictionary_get_cstring_nocopy(dict, "postcmd_buf", &str);
545 return str;
548 const char *
549 testcase_get_stdout_buf(prop_dictionary_t testcase)
551 const char *str = "";
553 prop_dictionary_t dict = testcase_get_result_dict(testcase);
554 prop_dictionary_get_cstring_nocopy(dict, "stdout_buf", &str);
556 return str;
559 const char *
560 testcase_get_stderr_buf(prop_dictionary_t testcase)
562 const char *str = "";
564 prop_dictionary_t dict = testcase_get_result_dict(testcase);
565 prop_dictionary_get_cstring_nocopy(dict, "stderr_buf", &str);
567 return str;
571 testcase_get_result(prop_dictionary_t testcase)
573 int32_t result = RESULT_NOTRUN;
575 prop_dictionary_t dict = testcase_get_result_dict(testcase);
576 prop_dictionary_get_int32(dict, "result", &result);
578 return (int)result;
581 const char *
582 testcase_get_result_desc(prop_dictionary_t testcase)
584 int result = testcase_get_result(testcase);
586 switch(result) {
587 case RESULT_TIMEOUT: return "TIMEOUT";
588 case RESULT_SIGNALLED: return "SIGNALLED";
589 case RESULT_NOTRUN: return "NOT RUN";
590 case RESULT_FAIL: return "FAIL";
591 case RESULT_PASS: return "PASS";
592 case RESULT_PREFAIL: return "PREFAIL";
593 case RESULT_POSTFAIL: return "POSTFAIL";
594 case RESULT_BUILDFAIL: return "BUILDFAIL";
595 default: return "UNKNOWN";
600 testcase_get_exit_value(prop_dictionary_t testcase)
602 int32_t exitval;
603 int r;
605 prop_dictionary_t dict = testcase_get_result_dict(testcase);
606 r = prop_dictionary_get_int32(dict, "exit_value", &exitval);
607 if (r == 0)
608 err(1, "prop_dictionary operation failed");
610 return (int)exitval;
614 testcase_get_signal(prop_dictionary_t testcase)
616 int32_t sig;
617 int r;
619 prop_dictionary_t dict = testcase_get_result_dict(testcase);
620 r = prop_dictionary_get_int32(dict, "signal", &sig);
621 if (r == 0)
622 err(1, "prop_dictionary operation failed");
624 return (int)sig;
628 parse_testcase_option(struct testcase_options *opts, char *option)
630 struct passwd *pwd;
631 char *parameter, *endptr;
632 long lval;
633 int noparam = 0;
635 parameter = strchr(option, '=');
636 noparam = (parameter == NULL);
637 if (!noparam)
639 *parameter = '\0';
640 ++parameter;
643 if (strcmp(option, "timeout") == 0) {
644 if (noparam)
645 syntax_error("The option 'timeout' needs a parameter");
646 /* NOTREACHED */
648 lval = strtol(parameter, &endptr, 10);
649 if (*endptr != '\0')
650 syntax_error("The option 'timeout' expects an integer "
651 "parameter, not '%s'", parameter);
652 /* NOTREACHED */
654 opts->timeout_in_secs = (long int)lval;
655 } else if (strcmp(option, "rc") == 0) {
656 if (noparam)
657 syntax_error("The option 'timeout' needs a parameter");
658 /* NOTREACHED */
660 lval = strtol(parameter, &endptr, 10);
661 if (*endptr != '\0')
662 syntax_error("The option 'timeout' expects an integer "
663 "parameter, not '%s'", parameter);
664 /* NOTREACHED */
666 opts->rc = (int)lval;
667 } else if (strcmp(option, "intpre") == 0) {
668 opts->flags |= TESTCASE_INT_PRE;
669 } else if (strcmp(option, "intpost") == 0) {
670 opts->flags |= TESTCASE_INT_POST;
671 } else if (strcmp(option, "pre") == 0) {
672 if (noparam)
673 syntax_error("The option 'pre' needs a parameter");
674 /* NOTREACHED */
676 opts->flags |= TESTCASE_CUSTOM_PRE;
677 opts->pre_cmd = strdup(parameter);
678 } else if (strcmp(option, "post") == 0) {
679 if (noparam)
680 syntax_error("The option 'post' needs a parameter");
681 /* NOTREACHED */
683 opts->flags |= TESTCASE_CUSTOM_POST;
684 opts->post_cmd = strdup(parameter);
685 } else if (strcmp(option, "runas") == 0) {
686 if (noparam)
687 syntax_error("The option 'runas' needs a parameter");
688 /* NOTREACHED */
690 if ((pwd = getpwnam(parameter))) {
691 opts->runas_uid = pwd->pw_uid;
692 opts->flags |= TESTCASE_RUN_AS;
693 } else {
694 syntax_error("invalid user name for 'runas': %s",
695 parameter);
697 } else if (strcmp(option, "nobuild") == 0) {
698 opts->flags |= TESTCASE_NOBUILD;
699 } else if (strcmp(option, "interpreter") == 0) {
700 if (noparam)
701 syntax_error("The option 'interpreter' needs a parameter");
702 /* NOTREACHED */
703 opts->interpreter = strdup(parameter);
704 } else if (strcmp(option, "make") == 0) {
705 if (noparam)
706 syntax_error("The option 'make' needs a parameter");
707 /* NOTREACHED */
709 opts->make_cmd = strdup(parameter);
710 } else if (strcmp(option, "defaults") == 0) {
711 /* Valid option, does nothing */
712 } else {
713 syntax_error("Unknown option: %s", option);
714 /* NOTREACHED */
717 return 0;
720 void
721 testcase_entry_parser(void *arg, char **tokens)
723 prop_array_t runlist;
724 prop_dictionary_t testcase_dict;
725 struct testcase *testcase;
726 char *options[256];
727 int i, r, nopts;
729 runlist = (prop_array_t)arg;
731 testcase = malloc(sizeof(struct testcase));
732 if (testcase == NULL)
733 err(1, "could not malloc testcase memory");
735 bzero(testcase, sizeof(struct testcase));
737 entry_check_num_args(tokens, 3);
739 testcase->argv = &tokens[3];
740 for (testcase->argc = 0; testcase->argv[testcase->argc] != NULL;
741 testcase->argc++)
744 nopts = parse_options(tokens[2], options);
746 testcase->name = tokens[0];
748 if (strcmp(tokens[1], "userland") == 0) {
749 testcase->type = TESTCASE_TYPE_USERLAND;
750 } else if (strcmp(tokens[1], "kernel") == 0) {
751 testcase->type = TESTCASE_TYPE_KERNEL;
752 } else if (strcmp(tokens[1], "buildonly") == 0) {
753 testcase->type = TESTCASE_TYPE_BUILDONLY;
754 } else {
755 syntax_error("Unknown type: %s", tokens[1]);
756 /* NOTREACHED */
759 testcase->type_str = tokens[1];
761 config_get_defaults(&testcase->opts);
763 for (i = 0; i < nopts; i++)
764 parse_testcase_option(&testcase->opts, options[i]);
766 if ((testcase->type != TESTCASE_TYPE_USERLAND) &&
767 (testcase->opts.flags & (TESTCASE_INT_PRE | TESTCASE_INT_POST)))
768 syntax_error("'intpre' and 'intpost' options are only valid "
769 "with testcase type 'userland'");
771 if ((testcase->type == TESTCASE_TYPE_BUILDONLY) &&
772 (testcase->opts.flags & TESTCASE_NOBUILD))
773 syntax_error("'nobuild' option is incompatible with type "
774 "'buildonly'");
776 testcase_dict = testcase_from_struct(testcase);
777 if (testcase->opts.pre_cmd != NULL)
778 free(testcase->opts.pre_cmd);
779 if (testcase->opts.post_cmd != NULL)
780 free(testcase->opts.post_cmd);
781 if (testcase->opts.interpreter != NULL)
782 free(testcase->opts.interpreter);
783 if (testcase->opts.make_cmd != NULL)
784 free(testcase->opts.make_cmd);
785 free(testcase);
787 r = prop_array_add(runlist, testcase_dict);
788 if (r == 0)
789 err(1, "prop_array_add failed");