nrelease - fix/improve livecd
[dragonfly.git] / usr.bin / dfregress / testcase.c
1 /*
2  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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.
15  *
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.
28  */
29
30 #include <sys/resource.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
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>
43
44 #include <err.h>
45
46 #include <libprop/proplib.h>
47
48 #include "parser.h"
49 #include "testcase.h"
50 #include "runlist.h"
51 #include "config.h"
52 #include <dfregress.h>
53
54 prop_dictionary_t
55 testcase_from_struct(struct testcase *testcase)
56 {
57         int i, r;
58         prop_dictionary_t dict, testcase_dict;
59         prop_array_t a;
60         char *s;
61
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");
71
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");
76
77         a = prop_array_create_with_capacity(testcase->argc+1);
78         if (a == NULL)
79                 err(1, "prop_array_create for argv failed");
80
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");
85
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");
90         }
91
92         r = prop_dictionary_set(testcase_dict, "args", a);
93         if (r == 0)
94                 err(1, "prop_dictionary_set \"args\" failed");
95
96         dict = prop_dictionary_create();
97         if (dict == NULL)
98                 err(1, "could not create dict");
99
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");
104
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");
109
110         r = prop_dictionary_set_uint32(dict, "flags", testcase->opts.flags);
111         if (r == 0)
112                 err(1, "prop_dictionary operation failed");
113
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");
119         }
120
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");
126         }
127
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");
133         }
134
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");
139
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");
144
145         r = prop_dictionary_set(testcase_dict, "opts", dict);
146         if (r == 0)
147                 err(1, "prop_dictionary operation failed");
148
149         return testcase_dict;
150 }
151
152 struct timeval *
153 testcase_get_timeout(prop_dictionary_t testcase)
154 {
155         static struct timeval tv;
156         int32_t val;
157         int r;
158
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");
163
164         tv.tv_usec = 0;
165         tv.tv_sec = (long)val;
166
167         return &tv;
168 }
169
170 int
171 testcase_get_type(prop_dictionary_t testcase)
172 {
173         const char *type;
174         int r;
175
176         r = prop_dictionary_get_cstring_nocopy(testcase, "type", &type);
177         if (r == 0)
178                 err(1, "prop_dictionary operation failed");
179
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;
186
187         return 0;
188 }
189
190 const char *
191 testcase_get_type_desc(prop_dictionary_t testcase)
192 {
193         const char *str;
194         int r;
195
196         r = prop_dictionary_get_cstring_nocopy(testcase, "type", &str);
197         if (r == 0)
198                 err(1, "prop_dictionary operation failed");
199
200         return str;
201 }
202
203 const char *
204 testcase_get_name(prop_dictionary_t testcase)
205 {
206         const char *str;
207         int r;
208
209         r = prop_dictionary_get_cstring_nocopy(testcase, "name", &str);
210         if (r == 0)
211                 err(1, "prop_dictionary operation failed");
212
213         return str;
214 }
215
216 int
217 testcase_get_argc(prop_dictionary_t testcase)
218 {
219         int32_t argc;
220         int r;
221
222         r = prop_dictionary_get_int32(testcase, "argc", &argc);
223         if (r == 0)
224                 err(1, "prop_dictionary operation failed for argc");
225
226         return argc;
227 }
228
229 const char **
230 testcase_get_args(prop_dictionary_t testcase)
231 {
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;
237
238         a = prop_dictionary_get(testcase, "args");
239         if (a == NULL)
240                 err(1, "testcase_get_args NULL array");
241
242         count = prop_array_count(a);
243
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");
248         }
249
250         argv[i] = NULL;
251
252         return argv;
253 }
254
255 uint32_t
256 testcase_get_flags(prop_dictionary_t testcase)
257 {
258         uint32_t flags;
259         int r;
260
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");
265
266         return flags;
267 }
268
269 int
270 testcase_get_precmd_type(prop_dictionary_t testcase)
271 {
272         uint32_t flags = testcase_get_flags(testcase);
273
274         return (flags & (TESTCASE_INT_PRE | TESTCASE_CUSTOM_PRE));
275 }
276
277 int
278 testcase_get_rc(prop_dictionary_t testcase)
279 {
280         int32_t rc;
281         int r;
282
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");
287
288         return rc;
289 }
290
291 int
292 testcase_get_postcmd_type(prop_dictionary_t testcase)
293 {
294         uint32_t flags = testcase_get_flags(testcase);
295
296         return (flags & (TESTCASE_INT_POST | TESTCASE_CUSTOM_POST));
297 }
298
299 int
300 testcase_needs_setuid(prop_dictionary_t testcase)
301 {
302         uint32_t flags = testcase_get_flags(testcase);
303
304         return (flags & TESTCASE_RUN_AS);
305 }
306
307 uid_t
308 testcase_get_runas_uid(prop_dictionary_t testcase)
309 {
310         uint32_t uid = 0;
311         int r;
312
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");
317
318         return (uid_t)uid;
319 }
320
321 const char *
322 testcase_get_custom_precmd(prop_dictionary_t testcase)
323 {
324         const char *str;
325         int r;
326
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");
331
332         return str;
333 }
334
335 const char *
336 testcase_get_custom_postcmd(prop_dictionary_t testcase)
337 {
338         const char *str;
339         int r;
340
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");
345
346         return str;
347 }
348
349 static const char *
350 _testcase_get_interpreter(prop_dictionary_t testcase, bool fatal)
351 {
352         const char *str;
353         int r;
354
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;
362         }
363
364         return str;
365 }
366
367 const char *
368 testcase_get_interpreter(prop_dictionary_t testcase)
369 {
370         return _testcase_get_interpreter(testcase, true);
371 }
372
373 const char *
374 testcase_get_interpreter_noexit(prop_dictionary_t testcase)
375 {
376         return _testcase_get_interpreter(testcase, false);
377 }
378
379 const char *
380 testcase_get_make_cmd(prop_dictionary_t testcase)
381 {
382         const char *str;
383         int r;
384
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");
389
390         return str;
391 }
392
393 prop_dictionary_t
394 testcase_get_result_dict(prop_dictionary_t testcase)
395 {
396         prop_dictionary_t result_dict;
397         int r;
398
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");
404
405                 r = prop_dictionary_set(testcase, "result", result_dict);
406                 if (r == 0)
407                         err(1, "prop_dictionary operation failed");
408         }
409
410         return result_dict;
411 }
412
413 int
414 testcase_set_build_buf(prop_dictionary_t testcase, const char *buf)
415 {
416         prop_dictionary_t dict = testcase_get_result_dict(testcase);
417
418         return !prop_dictionary_set_cstring(dict, "build_buf", buf);
419 }
420
421 int
422 testcase_set_cleanup_buf(prop_dictionary_t testcase, const char *buf)
423 {
424         prop_dictionary_t dict = testcase_get_result_dict(testcase);
425
426         return !prop_dictionary_set_cstring(dict, "cleanup_buf", buf);
427 }
428
429 int
430 testcase_set_sys_buf(prop_dictionary_t testcase, const char *buf)
431 {
432         prop_dictionary_t dict = testcase_get_result_dict(testcase);
433
434         return !prop_dictionary_set_cstring(dict, "sys_buf", buf);
435 }
436
437 int
438 testcase_set_precmd_buf(prop_dictionary_t testcase, const char *buf)
439 {
440         prop_dictionary_t dict = testcase_get_result_dict(testcase);
441
442         return !prop_dictionary_set_cstring(dict, "precmd_buf", buf);
443 }
444
445 int
446 testcase_set_postcmd_buf(prop_dictionary_t testcase, const char *buf)
447 {
448         prop_dictionary_t dict = testcase_get_result_dict(testcase);
449
450         return !prop_dictionary_set_cstring(dict, "postcmd_buf", buf);
451 }
452
453 int
454 testcase_set_stdout_buf(prop_dictionary_t testcase, const char *buf)
455 {
456         prop_dictionary_t dict = testcase_get_result_dict(testcase);
457
458         return !prop_dictionary_set_cstring(dict, "stdout_buf", buf);
459 }
460
461 int
462 testcase_set_stderr_buf(prop_dictionary_t testcase, const char *buf)
463 {
464         prop_dictionary_t dict = testcase_get_result_dict(testcase);
465
466         return !prop_dictionary_set_cstring(dict, "stderr_buf", buf);
467 }
468
469 int
470 testcase_set_result(prop_dictionary_t testcase, int result)
471 {
472         prop_dictionary_t dict = testcase_get_result_dict(testcase);
473
474         return !prop_dictionary_set_int32(dict, "result", result);
475 }
476
477 int
478 testcase_set_exit_value(prop_dictionary_t testcase, int exitval)
479 {
480         prop_dictionary_t dict = testcase_get_result_dict(testcase);
481
482         return !prop_dictionary_set_int32(dict, "exit_value", exitval);
483 }
484
485 int
486 testcase_set_signal(prop_dictionary_t testcase, int sig)
487 {
488         prop_dictionary_t dict = testcase_get_result_dict(testcase);
489
490         return !prop_dictionary_set_int32(dict, "signal", sig);
491 }
492
493 const char *
494 testcase_get_build_buf(prop_dictionary_t testcase)
495 {
496         const char *str = "";
497
498         prop_dictionary_t dict = testcase_get_result_dict(testcase);
499         prop_dictionary_get_cstring_nocopy(dict, "build_buf", &str);
500
501         return str;
502 }
503
504 const char *
505 testcase_get_cleanup_buf(prop_dictionary_t testcase)
506 {
507         const char *str = "";
508
509         prop_dictionary_t dict = testcase_get_result_dict(testcase);
510         prop_dictionary_get_cstring_nocopy(dict, "cleanup_buf", &str);
511
512         return str;
513 }
514
515 const char *
516 testcase_get_sys_buf(prop_dictionary_t testcase)
517 {
518         const char *str = "";
519
520         prop_dictionary_t dict = testcase_get_result_dict(testcase);
521         prop_dictionary_get_cstring_nocopy(dict, "sys_buf", &str);
522
523         return str;
524 }
525
526 const char *
527 testcase_get_precmd_buf(prop_dictionary_t testcase)
528 {
529         const char *str = "";
530
531         prop_dictionary_t dict = testcase_get_result_dict(testcase);
532         prop_dictionary_get_cstring_nocopy(dict, "precmd_buf", &str);
533
534         return str;
535 }
536
537 const char *
538 testcase_get_postcmd_buf(prop_dictionary_t testcase)
539 {
540         const char *str = "";
541
542         prop_dictionary_t dict = testcase_get_result_dict(testcase);
543         prop_dictionary_get_cstring_nocopy(dict, "postcmd_buf", &str);
544
545         return str;
546 }
547
548 const char *
549 testcase_get_stdout_buf(prop_dictionary_t testcase)
550 {
551         const char *str = "";
552
553         prop_dictionary_t dict = testcase_get_result_dict(testcase);
554         prop_dictionary_get_cstring_nocopy(dict, "stdout_buf", &str);
555
556         return str;
557 }
558
559 const char *
560 testcase_get_stderr_buf(prop_dictionary_t testcase)
561 {
562         const char *str = "";
563
564         prop_dictionary_t dict = testcase_get_result_dict(testcase);
565         prop_dictionary_get_cstring_nocopy(dict, "stderr_buf", &str);
566
567         return str;
568 }
569
570 int
571 testcase_get_result(prop_dictionary_t testcase)
572 {
573         int32_t result = RESULT_NOTRUN;
574
575         prop_dictionary_t dict = testcase_get_result_dict(testcase);
576         prop_dictionary_get_int32(dict, "result", &result);
577
578         return (int)result;
579 }
580
581 const char *
582 testcase_get_result_desc(prop_dictionary_t testcase)
583 {
584         int result = testcase_get_result(testcase);
585
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";
596         }
597 }
598
599 int
600 testcase_get_exit_value(prop_dictionary_t testcase)
601 {
602         int32_t exitval;
603         int r;
604
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");
609
610         return (int)exitval;
611 }
612
613 int
614 testcase_get_signal(prop_dictionary_t testcase)
615 {
616         int32_t sig;
617         int r;
618
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");
623
624         return (int)sig;
625 }
626
627 int
628 parse_testcase_option(struct testcase_options *opts, char *option)
629 {
630         struct passwd *pwd;
631         char    *parameter, *endptr;
632         long    lval;
633         int     noparam = 0;
634
635         parameter = strchr(option, '=');
636         noparam = (parameter == NULL);
637         if (!noparam)
638         {
639                 *parameter = '\0';
640                 ++parameter;
641         }
642
643         if (strcmp(option, "timeout") == 0) {
644                 if (noparam)
645                         syntax_error("The option 'timeout' needs a parameter");
646                         /* NOTREACHED */
647
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 */
653
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 */
659
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 */
665
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 */
675
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 */
682
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 */
689
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);
696                 }
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 */
708
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 */
715         }
716
717         return 0;
718 }
719
720 void
721 testcase_entry_parser(void *arg, char **tokens)
722 {
723         prop_array_t runlist;
724         prop_dictionary_t testcase_dict;
725         struct testcase *testcase;
726         char *options[256];
727         int i, r, nopts;
728
729         runlist = (prop_array_t)arg;
730
731         testcase = malloc(sizeof(struct testcase));
732         if (testcase == NULL)
733                 err(1, "could not malloc testcase memory");
734
735         bzero(testcase, sizeof(struct testcase));
736
737         entry_check_num_args(tokens, 3);
738
739         testcase->argv = &tokens[3];
740         for (testcase->argc = 0; testcase->argv[testcase->argc] != NULL;
741              testcase->argc++)
742                 ;
743
744         nopts = parse_options(tokens[2], options);
745
746         testcase->name = tokens[0];
747
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 */
757         }
758
759         testcase->type_str = tokens[1];
760
761         config_get_defaults(&testcase->opts);
762
763         for (i = 0; i < nopts; i++)
764                 parse_testcase_option(&testcase->opts, options[i]);
765
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'");
770
771         if ((testcase->type == TESTCASE_TYPE_BUILDONLY) &&
772             (testcase->opts.flags & TESTCASE_NOBUILD))
773                 syntax_error("'nobuild' option is incompatible with type "
774                     "'buildonly'");
775
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);
786
787         r = prop_array_add(runlist, testcase_dict);
788         if (r == 0)
789                 err(1, "prop_array_add failed");
790 }