xref: /dragonfly/usr.bin/dfregress/testcase.c (revision 039caa2712bab592ce22f44947164503333880a1)
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
testcase_from_struct(struct testcase * testcase)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 *
testcase_get_timeout(prop_dictionary_t testcase)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
testcase_get_type(prop_dictionary_t testcase)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 *
testcase_get_type_desc(prop_dictionary_t testcase)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 *
testcase_get_name(prop_dictionary_t testcase)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
testcase_get_argc(prop_dictionary_t testcase)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 **
testcase_get_args(prop_dictionary_t testcase)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
testcase_get_flags(prop_dictionary_t testcase)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
testcase_get_precmd_type(prop_dictionary_t testcase)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
testcase_get_rc(prop_dictionary_t testcase)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
testcase_get_postcmd_type(prop_dictionary_t testcase)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
testcase_needs_setuid(prop_dictionary_t testcase)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
testcase_get_runas_uid(prop_dictionary_t testcase)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 *
testcase_get_custom_precmd(prop_dictionary_t testcase)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 *
testcase_get_custom_postcmd(prop_dictionary_t testcase)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 *
_testcase_get_interpreter(prop_dictionary_t testcase,bool fatal)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 *
testcase_get_interpreter(prop_dictionary_t testcase)368 testcase_get_interpreter(prop_dictionary_t testcase)
369 {
370           return _testcase_get_interpreter(testcase, true);
371 }
372 
373 const char *
testcase_get_interpreter_noexit(prop_dictionary_t testcase)374 testcase_get_interpreter_noexit(prop_dictionary_t testcase)
375 {
376           return _testcase_get_interpreter(testcase, false);
377 }
378 
379 const char *
testcase_get_make_cmd(prop_dictionary_t testcase)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
testcase_get_result_dict(prop_dictionary_t testcase)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
testcase_set_build_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_cleanup_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_sys_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_precmd_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_postcmd_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_stdout_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_stderr_buf(prop_dictionary_t testcase,const char * buf)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
testcase_set_result(prop_dictionary_t testcase,int result)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
testcase_set_exit_value(prop_dictionary_t testcase,int exitval)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
testcase_set_signal(prop_dictionary_t testcase,int sig)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 *
testcase_get_build_buf(prop_dictionary_t testcase)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 *
testcase_get_cleanup_buf(prop_dictionary_t testcase)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 *
testcase_get_sys_buf(prop_dictionary_t testcase)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 *
testcase_get_precmd_buf(prop_dictionary_t testcase)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 *
testcase_get_postcmd_buf(prop_dictionary_t testcase)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 *
testcase_get_stdout_buf(prop_dictionary_t testcase)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 *
testcase_get_stderr_buf(prop_dictionary_t testcase)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
testcase_get_result(prop_dictionary_t testcase)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 *
testcase_get_result_desc(prop_dictionary_t testcase)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
testcase_get_exit_value(prop_dictionary_t testcase)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
testcase_get_signal(prop_dictionary_t testcase)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
parse_testcase_option(struct testcase_options * opts,char * option)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
testcase_entry_parser(void * arg,char ** tokens)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 }
791