1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2023 Oxide Computer Company
14 * Copyright 2024 Ryan Zezeski
15 */
16 #include <sys/debug.h>
17 #include <sys/ktest.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/list.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <stropts.h>
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <err.h>
29 #include <stdarg.h>
30 #include <strings.h>
31 #include <libgen.h>
32 #include <libnvpair.h>
33 #include <regex.h>
34 #include <libcmdutils.h>
35 #include <ofmt.h>
36 #include <zone.h>
37
38 #define EXIT_USAGE 2
39 #define KTEST_CMD_SZ 24
40 #define KTEST_DEV_PATH "/dev/ktest"
41
42 static const char *ktest_prog;
43
44 /* Print a horizontal rule. */
45 static void
ktest_print_hr(uint8_t cols)46 ktest_print_hr(uint8_t cols)
47 {
48 for (uint8_t i = 0; i < cols; i++) {
49 (void) putchar('-');
50 }
51
52 (void) putchar('\n');
53 }
54
55 /* An adapter to use errx with libofmt. */
56 void
ktest_ofmt_errx(const char * fmt,...)57 ktest_ofmt_errx(const char *fmt, ...)
58 {
59 va_list ap;
60
61 va_start(ap, fmt);
62 verrx(EXIT_FAILURE, fmt, ap);
63 }
64
65 typedef enum ktest_fmt_fields {
66 KTEST_FMT_RESULT,
67 KTEST_FMT_MODULE,
68 KTEST_FMT_SUITE,
69 KTEST_FMT_TEST,
70 KTEST_FMT_INPUT_FLAG,
71 KTEST_FMT_INPUT_PATH,
72 KTEST_FMT_LINE,
73 KTEST_FMT_REASON,
74 } ktest_fmt_fields_t;
75
76 typedef struct ktest_list_ofmt {
77 char *klof_module;
78 char *klof_suite;
79 char *klof_test;
80 boolean_t klof_input;
81 } ktest_list_ofmt_t;
82
83 static boolean_t
ktest_list_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t len)84 ktest_list_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t len)
85 {
86 ktest_list_ofmt_t *klof = ofarg->ofmt_cbarg;
87
88 switch (ofarg->ofmt_id) {
89 case KTEST_FMT_MODULE:
90 if (snprintf(buf, len, "%s", klof->klof_module) >= len) {
91 return (B_FALSE);
92 }
93 break;
94
95 case KTEST_FMT_SUITE:
96 if (snprintf(buf, len, "%s", klof->klof_suite) >= len) {
97 return (B_FALSE);
98 }
99 break;
100
101 case KTEST_FMT_TEST:
102 if (snprintf(buf, len, "%s", klof->klof_test) >= len) {
103 return (B_FALSE);
104 }
105 break;
106
107 case KTEST_FMT_INPUT_FLAG: {
108 const char *flag = klof->klof_input ? "Y" : "N";
109
110 if (snprintf(buf, len, "%s", flag) >= len) {
111 return (B_FALSE);
112 }
113 }
114 }
115
116 return (B_TRUE);
117 }
118
119 #define KTEST_LIST_CMD_DEF_FIELDS "module,suite,test,input"
120
121 static const ofmt_field_t ktest_list_ofmt[] = {
122 { "MODULE", 12, KTEST_FMT_MODULE, ktest_list_ofmt_cb },
123 { "SUITE", 16, KTEST_FMT_SUITE, ktest_list_ofmt_cb },
124 { "TEST", 45, KTEST_FMT_TEST, ktest_list_ofmt_cb },
125 { "INPUT", 7, KTEST_FMT_INPUT_FLAG, ktest_list_ofmt_cb },
126 { NULL, 0, 0, NULL },
127 };
128
129 static const char *
ktest_result_str(ktest_result_t * result)130 ktest_result_str(ktest_result_t *result)
131 {
132 switch (result->kr_type) {
133 case KTEST_RESULT_NONE:
134 return ("NONE");
135 case KTEST_RESULT_PASS:
136 return ("PASS");
137 case KTEST_RESULT_FAIL:
138 return ("FAIL");
139 case KTEST_RESULT_SKIP:
140 return ("SKIP");
141 case KTEST_RESULT_ERROR:
142 return ("ERROR");
143 }
144
145 /* Make the compiler happy. */
146 return ("NONE");
147 }
148
149 static boolean_t
ktest_run_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t len)150 ktest_run_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t len)
151 {
152 ktest_run_op_t *op = ofarg->ofmt_cbarg;
153 ktest_result_t *res = &op->kro_result;
154
155 switch (ofarg->ofmt_id) {
156 case KTEST_FMT_RESULT:
157 if (snprintf(buf, len, "%s", ktest_result_str(res)) >= len) {
158 return (B_FALSE);
159 }
160 break;
161
162 case KTEST_FMT_MODULE:
163 if (snprintf(buf, len, "%s", op->kro_module) >= len) {
164 return (B_FALSE);
165 }
166 break;
167
168 case KTEST_FMT_SUITE:
169 if (snprintf(buf, len, "%s", op->kro_suite) >= len) {
170 return (B_FALSE);
171 }
172 break;
173
174 case KTEST_FMT_TEST:
175 if (snprintf(buf, len, "%s", op->kro_test) >= len) {
176 return (B_FALSE);
177 }
178 break;
179
180 case KTEST_FMT_INPUT_PATH: {
181 if (snprintf(buf, len, "%s", op->kro_input_path) >= len) {
182 return (B_FALSE);
183 }
184 break;
185 }
186
187 case KTEST_FMT_LINE:
188 if (snprintf(buf, len, "%d", op->kro_result.kr_line) >= len) {
189 return (B_FALSE);
190 }
191 break;
192
193 case KTEST_FMT_REASON: {
194 if (snprintf(buf, len, "%s%s", res->kr_msg_prepend,
195 res->kr_msg) >= len) {
196 return (B_FALSE);
197 }
198 break;
199 }
200 }
201
202 return (B_TRUE);
203 }
204
205 /*
206 * The 'run' and 'run-file' commands share the same fields.
207 */
208 #define KTEST_RUN_CMD_DEF_FIELDS "result,line,module,suite,test"
209
210 /*
211 * The input column for the run command is for displaying the path to
212 * the input file, as opposed to the list command which indicates if
213 * the test requires input or not.
214 */
215 static const ofmt_field_t ktest_run_ofmt[] = {
216 { "RESULT", 7, KTEST_FMT_RESULT, ktest_run_ofmt_cb },
217 { "MODULE", 12, KTEST_FMT_MODULE, ktest_run_ofmt_cb },
218 { "SUITE", 16, KTEST_FMT_SUITE, ktest_run_ofmt_cb },
219 { "TEST", 45, KTEST_FMT_TEST, ktest_run_ofmt_cb },
220 { "INPUT", 48, KTEST_FMT_INPUT_PATH, ktest_run_ofmt_cb },
221 { "LINE", 6, KTEST_FMT_LINE, ktest_run_ofmt_cb },
222 { "REASON", 256, KTEST_FMT_REASON, ktest_run_ofmt_cb },
223 { NULL, 0, 0, NULL },
224 };
225
226 typedef enum ktest_stat_type {
227 KTEST_STAT_MOD,
228 KTEST_STAT_SUITE,
229 } ktest_stat_type_t;
230
231 typedef struct ktest_stats {
232 list_node_t ks_node;
233 ktest_stat_type_t ks_type;
234 char *ks_name;
235 uint32_t ks_total;
236 uint32_t ks_pass;
237 uint32_t ks_fail;
238 uint32_t ks_err;
239 uint32_t ks_skip;
240 uint32_t ks_none;
241 } ktest_stats_t;
242
243 static ktest_stats_t *
ktest_stats_new(ktest_stat_type_t type,const char * name)244 ktest_stats_new(ktest_stat_type_t type, const char *name)
245 {
246 ktest_stats_t *stats;
247
248 if ((stats = malloc(sizeof (ktest_stats_t))) == NULL) {
249 err(EXIT_FAILURE, "failed to allocate stats structure");
250 }
251
252 stats->ks_type = type;
253 stats->ks_name = strndup(name, KTEST_MAX_NAME_LEN);
254
255 if (stats->ks_name == NULL) {
256 err(EXIT_FAILURE, "failed to allocate stats name");
257 }
258
259 stats->ks_total = 0;
260 stats->ks_pass = 0;
261 stats->ks_fail = 0;
262 stats->ks_err = 0;
263 stats->ks_skip = 0;
264 stats->ks_none = 0;
265 return (stats);
266 }
267
268 static void
ktest_record_stat(ktest_stats_t * mod,ktest_stats_t * suite,const ktest_result_t * res)269 ktest_record_stat(ktest_stats_t *mod, ktest_stats_t *suite,
270 const ktest_result_t *res)
271 {
272 mod->ks_total++;
273 suite->ks_total++;
274
275 switch (res->kr_type) {
276 case KTEST_RESULT_NONE:
277 mod->ks_none++;
278 suite->ks_none++;
279 break;
280
281 case KTEST_RESULT_PASS:
282 mod->ks_pass++;
283 suite->ks_pass++;
284 break;
285
286 case KTEST_RESULT_FAIL:
287 mod->ks_fail++;
288 suite->ks_fail++;
289 break;
290
291 case KTEST_RESULT_SKIP:
292 mod->ks_skip++;
293 suite->ks_skip++;
294 break;
295
296 case KTEST_RESULT_ERROR:
297 mod->ks_err++;
298 suite->ks_err++;
299 break;
300 }
301 }
302
303 typedef enum ktest_fmt_stats {
304 KTEST_FMT_STATS_MS,
305 KTEST_FMT_STATS_TOTAL,
306 KTEST_FMT_STATS_PASS,
307 KTEST_FMT_STATS_FAIL,
308 KTEST_FMT_STATS_ERR,
309 KTEST_FMT_STATS_SKIP,
310 KTEST_FMT_STATS_NONE,
311 } ktest_fmt_stats_t;
312
313 static boolean_t
ktest_stats_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t len)314 ktest_stats_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t len)
315 {
316 ktest_stats_t *stats = ofarg->ofmt_cbarg;
317
318 switch (ofarg->ofmt_id) {
319 case KTEST_FMT_STATS_MS: {
320 char *pre = (stats->ks_type == KTEST_STAT_MOD) ? "" : " ";
321
322 if (snprintf(buf, len, "%s%s", pre, stats->ks_name) >= len) {
323 return (B_FALSE);
324 }
325 break;
326 }
327
328 case KTEST_FMT_STATS_TOTAL:
329 if (snprintf(buf, len, "%" PRIu32, stats->ks_total) >= len) {
330 return (B_FALSE);
331 }
332 break;
333
334 case KTEST_FMT_STATS_PASS:
335 if (snprintf(buf, len, "%" PRIu32, stats->ks_pass) >= len) {
336 return (B_FALSE);
337 }
338 break;
339
340 case KTEST_FMT_STATS_FAIL:
341 if (snprintf(buf, len, "%" PRIu32, stats->ks_fail) >= len) {
342 return (B_FALSE);
343 }
344 break;
345
346 case KTEST_FMT_STATS_ERR:
347 if (snprintf(buf, len, "%" PRIu32, stats->ks_err) >= len) {
348 return (B_FALSE);
349 }
350 break;
351
352 case KTEST_FMT_STATS_SKIP:
353 if (snprintf(buf, len, "%" PRIu32, stats->ks_skip) >= len) {
354 return (B_FALSE);
355 }
356 break;
357
358 case KTEST_FMT_STATS_NONE:
359 if (snprintf(buf, len, "%" PRIu32, stats->ks_none) >= len) {
360 return (B_FALSE);
361 }
362 break;
363 }
364
365 return (B_TRUE);
366 }
367
368 #define KTEST_STATS_FIELDS "module/suite,total,pass,fail,err,skip,none"
369
370 static const ofmt_field_t ktest_stats_ofmt[] = {
371 { "MODULE/SUITE", 40, KTEST_FMT_STATS_MS, ktest_stats_ofmt_cb },
372 { "TOTAL", 6, KTEST_FMT_STATS_TOTAL, ktest_stats_ofmt_cb },
373 { "PASS", 6, KTEST_FMT_STATS_PASS, ktest_stats_ofmt_cb },
374 { "FAIL", 6, KTEST_FMT_STATS_FAIL, ktest_stats_ofmt_cb },
375 { "ERR", 6, KTEST_FMT_STATS_ERR, ktest_stats_ofmt_cb },
376 { "SKIP", 6, KTEST_FMT_STATS_SKIP, ktest_stats_ofmt_cb },
377 { "NONE", 6, KTEST_FMT_STATS_NONE, ktest_stats_ofmt_cb },
378 };
379
380 static void
ktest_usage(const char * fmt,...)381 ktest_usage(const char *fmt, ...)
382 {
383 if (fmt != NULL) {
384 va_list ap;
385
386 va_start(ap, fmt);
387 vwarnx(fmt, ap);
388 va_end(ap);
389 }
390
391 (void) fprintf(stderr,
392 "usage: %s <subcommand> [<opts>] [<args>]\n\n"
393 "\tlist [-H] [[-p] -o field,...] [<triple> ...]: "
394 "list registered tests\n"
395 "\trun [-H] [[-p] -o field,...] [-i <file>] <triple> ...: "
396 "run specified tests\n"
397 "\trun-file [-H] [[-p] -o field,...] [<runfile>]: "
398 "run tests specified in runfile\n",
399 ktest_prog);
400 }
401
402 /*
403 * A user-specified test triple. The input path is set to the empty
404 * string if no input is provided. The line number provides useful
405 * error reporting when an error is encountered in the run file.
406 */
407 typedef struct ktest_triple {
408 list_node_t ktr_node;
409 char ktr_module[KTEST_MAX_NAME_LEN];
410 char ktr_suite[KTEST_MAX_NAME_LEN];
411 char ktr_test[KTEST_MAX_NAME_LEN];
412 char ktr_input_path[MAXPATHLEN];
413 uint32_t ktr_lineno;
414 } ktest_triple_t;
415
416 /* The default triple matches all tests. */
417 static ktest_triple_t *ktest_def_triple;
418
419 /*
420 * A test description obtained from iterating the list tests nvlist.
421 */
422 typedef struct ktest_test_desc {
423 char *ktd_module;
424 char *ktd_suite;
425 char *ktd_test;
426 boolean_t ktd_requires_input;
427 } ktest_test_desc_t;
428
429 static void
ktest_test_desc_init(ktest_test_desc_t * desc)430 ktest_test_desc_init(ktest_test_desc_t *desc)
431 {
432 desc->ktd_module = NULL;
433 desc->ktd_suite = NULL;
434 desc->ktd_test = NULL;
435 desc->ktd_requires_input = B_FALSE;
436 }
437
438 static void
ktest_free_triples(list_t * triples)439 ktest_free_triples(list_t *triples)
440 {
441 ktest_triple_t *t = NULL;
442
443 while ((t = list_remove_head(triples)) != NULL) {
444 free(t);
445 }
446 }
447
448 /*
449 * Does the test descriptor match this triple? The descriptor will
450 * always have module name present, but the suite and test names may
451 * or may not be present.
452 */
453 static boolean_t
ktest_match_triple(const ktest_test_desc_t * desc,const ktest_triple_t * triple)454 ktest_match_triple(const ktest_test_desc_t *desc, const ktest_triple_t *triple)
455 {
456 /* Must at least specify the module. */
457 VERIFY(desc->ktd_module != NULL);
458
459 if (desc->ktd_suite != NULL && desc->ktd_test != NULL) {
460 return (gmatch(desc->ktd_module, triple->ktr_module) != 0 &&
461 gmatch(desc->ktd_suite, triple->ktr_suite) != 0 &&
462 gmatch(desc->ktd_test, triple->ktr_test) != 0);
463 } else if (desc->ktd_suite != NULL) {
464 return (gmatch(desc->ktd_module, triple->ktr_module) != 0 &&
465 gmatch(desc->ktd_suite, triple->ktr_suite) != 0);
466 }
467
468 return (gmatch(desc->ktd_module, triple->ktr_module) != 0);
469 }
470
471 /*
472 * Does the test descriptor match any of the triples?
473 */
474 static boolean_t
ktest_match_any(const ktest_test_desc_t * desc,list_t * triples)475 ktest_match_any(const ktest_test_desc_t *desc, list_t *triples)
476 {
477 for (ktest_triple_t *triple = list_head(triples); triple != NULL;
478 triple = list_next(triples, triple)) {
479 if (ktest_match_triple(desc, triple)) {
480 return (B_TRUE);
481 }
482 }
483
484 return (B_FALSE);
485 }
486
487 typedef struct ktest_iter {
488 /*
489 * The list of all modules and current module the iterator is on.
490 */
491 nvlist_t *ki_modules;
492 nvpair_t *ki_module;
493
494 /*
495 * The list of all suites in the current module and the
496 * current suite the iterator is on.
497 */
498 nvlist_t *ki_suites;
499 nvpair_t *ki_suite;
500
501 /*
502 * The list of all tests in the current suite and the current
503 * test the iterator is on.
504 */
505 nvlist_t *ki_tests;
506 nvpair_t *ki_test;
507
508 ktest_test_desc_t ki_desc;
509
510 /*
511 * A list of ktest_triple_t used to filter the tests returned
512 * by the iterator.
513 */
514 list_t *ki_triples;
515 } ktest_iter_t;
516
517 static char *
ktest_module_name(nvpair_t * module)518 ktest_module_name(nvpair_t *module)
519 {
520 nvlist_t *desc = fnvpair_value_nvlist(module);
521 return (fnvlist_lookup_string(desc, KTEST_NAME_KEY));
522 }
523
524 static nvlist_t *
ktest_module_suites(nvpair_t * module)525 ktest_module_suites(nvpair_t *module)
526 {
527 nvlist_t *desc = fnvpair_value_nvlist(module);
528 return (fnvlist_lookup_nvlist(desc, KTEST_MODULE_SUITES_KEY));
529 }
530
531 static char *
ktest_suite_name(nvpair_t * suite)532 ktest_suite_name(nvpair_t *suite)
533 {
534 nvlist_t *desc = fnvpair_value_nvlist(suite);
535 return (fnvlist_lookup_string(desc, KTEST_NAME_KEY));
536 }
537
538 static nvlist_t *
ktest_suite_tests(nvpair_t * suite)539 ktest_suite_tests(nvpair_t *suite)
540 {
541 nvlist_t *desc = fnvpair_value_nvlist(suite);
542 return (fnvlist_lookup_nvlist(desc, KTEST_SUITE_TESTS_KEY));
543 }
544
545 static char *
ktest_test_name(nvpair_t * test)546 ktest_test_name(nvpair_t *test)
547 {
548 nvlist_t *desc = fnvpair_value_nvlist(test);
549 return (fnvlist_lookup_string(desc, KTEST_NAME_KEY));
550 }
551
552 static boolean_t
ktest_test_requires_input(nvpair_t * test)553 ktest_test_requires_input(nvpair_t *test)
554 {
555 nvlist_t *desc = fnvpair_value_nvlist(test);
556 return (fnvlist_lookup_boolean_value(desc, KTEST_TEST_INPUT_KEY));
557 }
558
559 static ktest_iter_t *
ktest_iter(nvlist_t * tests,list_t * triples)560 ktest_iter(nvlist_t *tests, list_t *triples)
561 {
562 ktest_iter_t *iter = malloc(sizeof (ktest_iter_t));
563
564 if (iter == NULL) {
565 err(EXIT_FAILURE, "failed to allocate test iterator");
566 }
567
568 iter->ki_modules = tests;
569 iter->ki_module = nvlist_next_nvpair(tests, NULL);
570
571 iter->ki_suites = NULL;
572 iter->ki_suite = NULL;
573
574 iter->ki_tests = NULL;
575 iter->ki_test = NULL;
576
577 ktest_test_desc_init(&iter->ki_desc);
578
579 iter->ki_triples = triples;
580 return (iter);
581 }
582
583 #define KT_NEXT_TEST(iter) \
584 (nvlist_next_nvpair((iter)->ki_tests, (iter)->ki_test))
585
586 static boolean_t
ktest_iter_tests(ktest_iter_t * iter,ktest_test_desc_t * desc)587 ktest_iter_tests(ktest_iter_t *iter, ktest_test_desc_t *desc)
588 {
589 if (iter->ki_test == NULL) {
590 iter->ki_test = KT_NEXT_TEST(iter);
591 }
592
593 for (; iter->ki_test != NULL; iter->ki_test = KT_NEXT_TEST(iter)) {
594 iter->ki_desc.ktd_test = ktest_test_name(iter->ki_test);
595 iter->ki_desc.ktd_requires_input =
596 ktest_test_requires_input(iter->ki_test);
597
598 /*
599 * We found a match and are returning control to the
600 * ktest_iter_next() caller; but we first need to copy
601 * the matching descriptor and move the iterator to
602 * the next test in preparation for the next call to
603 * ktest_iter_next().
604 */
605 if (ktest_match_any(&iter->ki_desc, iter->ki_triples)) {
606 *desc = iter->ki_desc;
607 iter->ki_test = KT_NEXT_TEST(iter);
608 return (B_TRUE);
609 }
610 }
611
612 return (B_FALSE);
613 }
614
615 #define KT_NEXT_SUITE(iter) \
616 (nvlist_next_nvpair((iter)->ki_suites, (iter)->ki_suite))
617
618 static boolean_t
ktest_iter_suites(ktest_iter_t * iter,ktest_test_desc_t * desc)619 ktest_iter_suites(ktest_iter_t *iter, ktest_test_desc_t *desc)
620 {
621 if (iter->ki_suite == NULL) {
622 iter->ki_suite = KT_NEXT_SUITE(iter);
623 }
624
625 for (; iter->ki_suite != NULL; iter->ki_suite = KT_NEXT_SUITE(iter)) {
626 iter->ki_desc.ktd_suite = ktest_suite_name(iter->ki_suite);
627
628 if (!ktest_match_any(&iter->ki_desc, iter->ki_triples)) {
629 continue;
630 }
631
632 iter->ki_tests = ktest_suite_tests(iter->ki_suite);
633
634 if (ktest_iter_tests(iter, desc)) {
635 /*
636 * We've iterated all tests in the suite, move
637 * to the next one.
638 */
639 if (iter->ki_test == NULL) {
640 iter->ki_suite = KT_NEXT_SUITE(iter);
641 }
642
643 return (B_TRUE);
644 }
645 }
646
647 return (B_FALSE);
648 }
649
650 #define KT_NEXT_MOD(iter) \
651 (nvlist_next_nvpair((iter)->ki_modules, (iter)->ki_module))
652
653 static boolean_t
ktest_iter_next(ktest_iter_t * iter,ktest_test_desc_t * desc)654 ktest_iter_next(ktest_iter_t *iter, ktest_test_desc_t *desc)
655 {
656 for (; iter->ki_module != NULL; iter->ki_module = KT_NEXT_MOD(iter)) {
657 ktest_test_desc_init(&iter->ki_desc);
658 iter->ki_desc.ktd_module = ktest_module_name(iter->ki_module);
659
660 if (!ktest_match_any(&iter->ki_desc, iter->ki_triples)) {
661 continue;
662 }
663
664 iter->ki_suites = ktest_module_suites(iter->ki_module);
665
666 if (ktest_iter_suites(iter, desc)) {
667 /*
668 * We've iterated all suites in the module,
669 * move to the next one.
670 */
671 if (iter->ki_suite == NULL) {
672 iter->ki_module = KT_NEXT_MOD(iter);
673 }
674
675 return (B_TRUE);
676 }
677 }
678
679 return (B_FALSE);
680 }
681
682 /*
683 * Get a list of tests from the in-kernel ktest registry.
684 */
685 static nvlist_t *
ktest_list_tests(int dev)686 ktest_list_tests(int dev)
687 {
688 int ret = 0;
689 nvlist_t *tests = NULL;
690 boolean_t retry = B_FALSE;
691 ktest_list_op_t klo;
692 size_t resp_len = 1 * 1024 * 1024;
693 char *resp = NULL;
694 uint64_t vsn = 0;
695
696 if ((resp = malloc(resp_len)) == NULL) {
697 err(EXIT_FAILURE, "failed to allocate response buffer");
698 }
699
700 bzero(resp, resp_len);
701 klo.klo_resp = resp;
702 klo.klo_resp_len = resp_len;
703
704 retry:
705 ret = ioctl(dev, KTEST_IOCTL_LIST_TESTS, &klo);
706
707 if (ret == -1 && errno == ENOBUFS && !retry) {
708 free(resp);
709 resp_len = klo.klo_resp_len;
710
711 if ((resp = malloc(resp_len)) == NULL) {
712 err(EXIT_FAILURE, "failed to allocate response buffer");
713 }
714
715 bzero(resp, resp_len);
716 retry = B_TRUE;
717 goto retry;
718 } else if (ret == -1) {
719 err(EXIT_FAILURE, "list ioctl failed");
720 }
721
722 resp_len = klo.klo_resp_len;
723
724 if ((ret = nvlist_unpack(resp, resp_len, &tests, 0)) != 0) {
725 errx(EXIT_FAILURE, "failed to unpack list response: %s",
726 strerror(ret));
727 }
728
729 free(resp);
730
731 /*
732 * Verify that the response is marked with the expected
733 * serialization format. Remove the nvpair so that only the
734 * modules remain.
735 */
736 if (nvlist_lookup_uint64(tests, KTEST_SER_FMT_KEY, &vsn) != 0) {
737 errx(EXIT_FAILURE, "invalid list response, missing %s key\n",
738 KTEST_SER_FMT_KEY);
739 }
740
741 if (vsn != KTEST_SER_FMT_VSN) {
742 errx(EXIT_FAILURE,
743 "invalid serialization format version: %" PRIu64 "\n", vsn);
744 }
745
746 fnvlist_remove(tests, KTEST_SER_FMT_KEY);
747 return (tests);
748 }
749
750 static void
ktest_print_tests(nvlist_t * tests,list_t * triples,ofmt_handle_t ofmt)751 ktest_print_tests(nvlist_t *tests, list_t *triples, ofmt_handle_t ofmt)
752 {
753 ktest_iter_t *iter = ktest_iter(tests, triples);
754 ktest_test_desc_t desc;
755
756 while (ktest_iter_next(iter, &desc)) {
757 ktest_list_ofmt_t klof;
758
759 klof.klof_module = desc.ktd_module;
760 klof.klof_suite = desc.ktd_suite;
761 klof.klof_test = desc.ktd_test;
762 klof.klof_input = desc.ktd_requires_input;
763 ofmt_print(ofmt, &klof);
764 }
765
766 free(iter);
767 }
768
769 static void
ktest_print_stats(list_t * stats)770 ktest_print_stats(list_t *stats)
771 {
772 ktest_stats_t *stat;
773 ofmt_handle_t stats_ofmt;
774 ofmt_status_t oferr;
775 boolean_t first = B_FALSE;
776
777 oferr = ofmt_open(KTEST_STATS_FIELDS, ktest_stats_ofmt, 0, 0,
778 &stats_ofmt);
779 ofmt_check(oferr, B_FALSE, stats_ofmt, ktest_ofmt_errx, warnx);
780
781 for (stat = list_head(stats); stat != NULL;
782 stat = list_next(stats, stat)) {
783 if (!first && stat->ks_type == KTEST_STAT_MOD) {
784 printf("\n");
785 }
786
787 ofmt_print(stats_ofmt, stat);
788
789 if (stat->ks_type == KTEST_STAT_MOD) {
790 first = B_FALSE;
791 ktest_print_hr(74);
792 }
793 }
794
795 ofmt_close(stats_ofmt);
796 }
797
798 /*
799 * Read file at path into the byte array. The byte array is allocated
800 * as part of this function and ownership is given to the caller via
801 * the bytes argument along with its length returned by 'len'. If an
802 * error occurs while reading, the 'err' string is filled in with the
803 * appropriate error message.
804 *
805 * It might be nice to replace this with kobj_{open,read}_file() in
806 * the ktest kernel module to avoid shuffling bytes between user and
807 * kernel (see devcache which uses these private APIs for the purpose
808 * of reading serialized nvlists).
809 */
810 static boolean_t
ktest_read_file(const char * path,uchar_t ** bytes,uint64_t * len,char * err)811 ktest_read_file(const char *path, uchar_t **bytes, uint64_t *len, char *err)
812 {
813 FILE *f;
814 struct stat stats;
815 uchar_t *tmp_bytes;
816 uint64_t tmp_len;
817
818 *bytes = NULL;
819 *len = 0;
820
821 if ((f = fopen(path, "r")) == NULL) {
822 (void) strcpy(err, "failed to open input file");
823 return (B_FALSE);
824 }
825
826 if (fstat(fileno(f), &stats) == -1) {
827 (void) fclose(f);
828 (void) strcpy(err, "failed to stat input file");
829 return (B_FALSE);
830 }
831
832 tmp_len = (uint64_t)stats.st_size;
833
834 if ((tmp_bytes = malloc(tmp_len)) == NULL) {
835 (void) fclose(f);
836 (void) strcpy(err, "failed to allocate byte array of size");
837 return (B_FALSE);
838 }
839
840 if (fread(tmp_bytes, sizeof (*tmp_bytes), tmp_len, f) != tmp_len) {
841 (void) fclose(f);
842 (void) snprintf(err, KTEST_MAX_LOG_LEN,
843 "failed to read %u bytes from input file", tmp_len);
844 return (B_FALSE);
845 }
846
847 *bytes = tmp_bytes;
848 *len = tmp_len;
849 return (B_TRUE);
850 }
851
852 static boolean_t
ktest_run_test(int dev,const ktest_test_desc_t * desc,const char * input_path,ktest_stats_t * mod_stats,ktest_stats_t * suite_stats,ofmt_handle_t ofmt)853 ktest_run_test(int dev, const ktest_test_desc_t *desc, const char *input_path,
854 ktest_stats_t *mod_stats, ktest_stats_t *suite_stats, ofmt_handle_t ofmt)
855 {
856 ktest_run_op_t kro;
857 char err_msg[KTEST_MAX_LOG_LEN];
858
859 /*
860 * It is up to the caller to ensure that an input path is
861 * specified when a test requires it.
862 */
863 if (desc->ktd_requires_input) {
864 VERIFY(input_path != NULL);
865 }
866
867 bzero(&err_msg, KTEST_MAX_LOG_LEN);
868 bzero(&kro, sizeof (kro));
869
870 /*
871 * The module/suite/test come from the kernel's list tests
872 * nvlist which we know contain properly sized strings.
873 */
874 (void) strlcpy(kro.kro_module, desc->ktd_module, KTEST_MAX_NAME_LEN);
875 (void) strlcpy(kro.kro_suite, desc->ktd_suite, KTEST_MAX_NAME_LEN);
876 (void) strlcpy(kro.kro_test, desc->ktd_test, KTEST_MAX_NAME_LEN);
877
878 if (input_path != NULL) {
879 uchar_t *bytes = NULL;
880 uint64_t len = 0;
881
882 /*
883 * The input_path came from the ktest_triple_t which
884 * we know contains a properly sized string.
885 */
886 (void) strlcpy(kro.kro_input_path, input_path,
887 sizeof (kro.kro_input_path));
888
889 /*
890 * We treat a failure to read the input file as a test
891 * error.
892 */
893 if (!ktest_read_file(input_path, &bytes, &len, err_msg)) {
894 kro.kro_result.kr_type = KTEST_RESULT_ERROR;
895 (void) strlcpy(kro.kro_result.kr_msg, err_msg,
896 KTEST_MAX_LOG_LEN);
897 ktest_record_stat(mod_stats, suite_stats,
898 &kro.kro_result);
899 ofmt_print(ofmt, &kro);
900 return (B_FALSE);
901 }
902
903 /*
904 * The input stream must contain at least 1 byte.
905 */
906 if (len == 0) {
907 kro.kro_result.kr_type = KTEST_RESULT_ERROR;
908 (void) strcpy(kro.kro_result.kr_msg,
909 "zero-length input stream");
910 ktest_record_stat(mod_stats, suite_stats,
911 &kro.kro_result);
912 ofmt_print(ofmt, &kro);
913 return (B_FALSE);
914 }
915
916 kro.kro_input_len = len;
917 kro.kro_input_bytes = bytes;
918 }
919
920 if (ioctl(dev, KTEST_IOCTL_RUN_TEST, &kro) == -1) {
921 if (input_path != NULL) {
922 err(EXIT_FAILURE, "failed to run test %s:%s:%s with "
923 "input %s", desc->ktd_module, desc->ktd_suite,
924 desc->ktd_test, input_path);
925 } else {
926 err(EXIT_FAILURE, "failed to run test %s:%s:%s",
927 desc->ktd_module, desc->ktd_suite, desc->ktd_test);
928 }
929 }
930
931 ktest_record_stat(mod_stats, suite_stats, &kro.kro_result);
932 ofmt_print(ofmt, &kro);
933 return (kro.kro_result.kr_type == KTEST_RESULT_PASS ||
934 kro.kro_result.kr_type == KTEST_RESULT_SKIP);
935 }
936
937 /*
938 * Run all tests specified in the run list and print the result of
939 * each test. If print_stats is true, the result statistics are
940 * printed as well. A return of true indicates all tests passed. A
941 * return of false indicates one or more tests produced an ERROR or
942 * FAIL result.
943 */
944 static boolean_t
ktest_run_tests(int dev,nvlist_t * tests,list_t * run_list,ofmt_handle_t ofmt,boolean_t print_stats)945 ktest_run_tests(int dev, nvlist_t *tests, list_t *run_list, ofmt_handle_t ofmt,
946 boolean_t print_stats)
947 {
948 ktest_iter_t *iter = ktest_iter(tests, run_list);
949 ktest_test_desc_t desc;
950 ktest_stats_t *mod_stats = NULL;
951 ktest_stats_t *suite_stats = NULL;
952 list_t stats;
953 ktest_stats_t *stat = NULL;
954 boolean_t all_pass = B_TRUE;
955
956 ktest_test_desc_init(&desc);
957 list_create(&stats, sizeof (ktest_stats_t),
958 offsetof(ktest_stats_t, ks_node));
959
960 while (ktest_iter_next(iter, &desc)) {
961 /*
962 * Either this is our first matching test or we are
963 * transitioning to a new module and/or suite. In
964 * either case, create new stats structures and add
965 * them to the list.
966 */
967 if (mod_stats == NULL ||
968 strcmp(mod_stats->ks_name, desc.ktd_module) != 0) {
969 mod_stats = ktest_stats_new(KTEST_STAT_MOD,
970 desc.ktd_module);
971 list_insert_tail(&stats, mod_stats);
972 }
973
974 if (suite_stats == NULL ||
975 strcmp(suite_stats->ks_name, desc.ktd_suite) != 0) {
976 suite_stats = ktest_stats_new(KTEST_STAT_SUITE,
977 desc.ktd_suite);
978 list_insert_tail(&stats, suite_stats);
979 }
980
981 /*
982 * A test that does not require input only has to run
983 * once.
984 */
985 if (!desc.ktd_requires_input) {
986 if (!ktest_run_test(dev, &desc, NULL, mod_stats,
987 suite_stats, ofmt)) {
988 all_pass = B_FALSE;
989 }
990 continue;
991 }
992
993 /*
994 * A test that requires input may have more than one
995 * matching triple. This feature allows a user to
996 * specify multiple input streams for the same test
997 * where each input stream is a separate run of the
998 * test. We iterate the run list; running the test
999 * for each triple that matches and has an input path
1000 * specified.
1001 */
1002 for (ktest_triple_t *triple = list_head(run_list);
1003 triple != NULL;
1004 triple = list_next(run_list, triple)) {
1005 if (ktest_match_triple(&desc, triple) &&
1006 triple->ktr_input_path[0] != '\0') {
1007 if (!ktest_run_test(dev, &desc,
1008 triple->ktr_input_path, mod_stats,
1009 suite_stats, ofmt)) {
1010 all_pass = B_FALSE;
1011 }
1012 }
1013 }
1014 }
1015
1016 if (print_stats) {
1017 printf("\n");
1018 ktest_print_stats(&stats);
1019 }
1020
1021 while ((stat = list_remove_head(&stats)) != NULL) {
1022 free(stat);
1023 }
1024
1025 list_destroy(&stats);
1026 free(iter);
1027 return (all_pass);
1028 }
1029
1030 /*
1031 * Attempt to parse the test triple string and return the resulting
1032 * triple struct. This leaves the original triple string untouched.
1033 *
1034 * This function produces a warning when failing to parse a triple,
1035 * this is on purpose. This allows the run file parser to produce an
1036 * error that points out the line number with the bad triple.
1037 */
1038 static ktest_triple_t *
ktest_parse_triple(const char * tstr,uint32_t lineno)1039 ktest_parse_triple(const char *tstr, uint32_t lineno)
1040 {
1041 char *cp = NULL, *orig = NULL;
1042 char *module = NULL;
1043 char *suite = NULL;
1044 char *test = NULL;
1045 ktest_triple_t *triple = NULL;
1046
1047 if ((triple = calloc(1, sizeof (*triple))) == NULL) {
1048 warn("failed to allocate triple");
1049 return (NULL);
1050 }
1051
1052 triple->ktr_lineno = lineno;
1053
1054 if (strnlen(tstr, KTEST_MAX_TRIPLE_LEN) >= KTEST_MAX_TRIPLE_LEN) {
1055 warnx("triple is too long");
1056 goto fail;
1057 }
1058
1059 if ((cp = strndup(tstr, KTEST_MAX_TRIPLE_LEN)) == NULL) {
1060 warn("failed to dup triple string");
1061 goto fail;
1062 }
1063
1064 orig = cp;
1065 module = strsep(&cp, KTEST_SEPARATOR);
1066
1067 if (strnlen(module, KTEST_MAX_NAME_LEN) >= KTEST_MAX_NAME_LEN) {
1068 warnx("module pattern too long: %s", module);
1069 goto fail;
1070 }
1071
1072 if (*module == '\0') {
1073 module = "*";
1074 }
1075
1076 if (cp == NULL) {
1077 suite = "*";
1078 test = "*";
1079 goto copy;
1080 }
1081
1082 suite = strsep(&cp, KTEST_SEPARATOR);
1083
1084 if (strnlen(suite, KTEST_MAX_NAME_LEN) >= KTEST_MAX_NAME_LEN) {
1085 warnx("suite pattern too long: %s", suite);
1086 goto fail;
1087 }
1088
1089 if (*suite == '\0') {
1090 suite = "*";
1091 }
1092
1093 if (cp == NULL) {
1094 test = "*";
1095 goto copy;
1096 }
1097
1098 test = cp;
1099
1100 if (strstr(cp, KTEST_SEPARATOR) != NULL) {
1101 warnx("malformed triple, unexpected ':' in test pattern: %s",
1102 test);
1103 goto fail;
1104 }
1105
1106 if (strnlen(test, KTEST_MAX_NAME_LEN) >= KTEST_MAX_NAME_LEN) {
1107 warnx("test pattern too long: %s", test);
1108 goto fail;
1109 }
1110
1111 if (*test == '\0') {
1112 test = "*";
1113 }
1114
1115 copy:
1116 /* We've checked the string lengths, but just in case. */
1117 (void) strlcpy(triple->ktr_module, module, sizeof (triple->ktr_module));
1118 (void) strlcpy(triple->ktr_suite, suite, sizeof (triple->ktr_suite));
1119 (void) strlcpy(triple->ktr_test, test, sizeof (triple->ktr_test));
1120 free(orig);
1121 return (triple);
1122
1123 fail:
1124 free(orig);
1125 free(triple);
1126 return (NULL);
1127 }
1128
1129 /*
1130 * Attempt to load the run file specified and decode it into a run
1131 * list. Use stdin as the content of the runfile when use_stdin is
1132 * true.
1133 *
1134 * Currently all input files must either be relative to the working
1135 * directory or an absolute path. In the future it would be nice to
1136 * support something like glob(3C) to perform tilde expansion for the
1137 * input file path. Another idea would be to add a search path for
1138 * input files, allowing us to more easily constrain where on the
1139 * filesystem these files are searched for.
1140 */
1141 static void
ktest_load_run_file(const char * path,boolean_t use_stdin,nvlist_t * tests,list_t * run_list)1142 ktest_load_run_file(const char *path, boolean_t use_stdin, nvlist_t *tests,
1143 list_t *run_list)
1144 {
1145 FILE *f;
1146 char *line = NULL;
1147 size_t cap = 0;
1148 ssize_t len;
1149 uint32_t lineno = 0;
1150 boolean_t one_line = B_FALSE; /* At least one valid line? */
1151
1152 if (use_stdin) {
1153 f = stdin;
1154 } else {
1155 if ((f = fopen(path, "r")) == NULL) {
1156 err(EXIT_FAILURE, "failed to open run file %s", path);
1157 }
1158 }
1159
1160 while ((len = getline(&line, &cap, f)) != -1) {
1161 char *input, *lasts, *tstr;
1162 ktest_triple_t *triple;
1163
1164 lineno++;
1165 /* A line is always at least one character: newline. */
1166 VERIFY3S(len, >=, 1);
1167 /* Skip the newline. */
1168 line[len - 1] = '\0';
1169
1170 /* Skip empty lines. */
1171 if (line[0] == '\0') {
1172 continue;
1173 }
1174
1175 /*
1176 * A valid line consists of either a test triple on
1177 * its own or a test triple and an input file
1178 * separated by whitespace.
1179 */
1180 tstr = strtok_r(line, " \t", &lasts);
1181 triple = ktest_parse_triple(tstr, lineno);
1182
1183 if (triple == NULL) {
1184 errx(EXIT_FAILURE, "failed to parse triple %s at line "
1185 "%u", tstr, lineno);
1186 }
1187
1188 input = strtok_r(NULL, " \t", &lasts);
1189
1190 if (input != NULL) {
1191 size_t len = strlcpy(triple->ktr_input_path, input,
1192 sizeof (triple->ktr_input_path));
1193 if (len >= sizeof (triple->ktr_input_path)) {
1194 err(EXIT_FAILURE, "input path at line %u too "
1195 "long: %s\n", lineno, input);
1196 }
1197 }
1198
1199 list_insert_tail(run_list, triple);
1200 one_line = B_TRUE;
1201 }
1202
1203 /*
1204 * If we broke from the loop for a reason other than EOF, then
1205 * assume we do not have a full run list and exit.
1206 */
1207 if (ferror(f)) {
1208 err(EXIT_FAILURE, "failed to read entire runfile");
1209 }
1210
1211 if (!use_stdin) {
1212 (void) fclose(f);
1213 }
1214
1215 free(line);
1216
1217 if (!one_line) {
1218 errx(EXIT_FAILURE, "no tests specified in: %s", path);
1219 }
1220 }
1221
1222 /*
1223 * Is this test triple fully-qualified?
1224 *
1225 * A fully-qualified triple is one where the module, suite, and test
1226 * use no glob characters with the intent that it refers to a single,
1227 * unique test.
1228 */
1229 static boolean_t
ktest_is_fqt(const ktest_triple_t * triple)1230 ktest_is_fqt(const ktest_triple_t *triple)
1231 {
1232 return (strpbrk(triple->ktr_module, KTEST_GMATCH_CHARS) == NULL &&
1233 strpbrk(triple->ktr_suite, KTEST_GMATCH_CHARS) == NULL &&
1234 strpbrk(triple->ktr_test, KTEST_GMATCH_CHARS) == NULL);
1235 }
1236
1237 /*
1238 * Does this fully-qualified triple refer to a test which requires
1239 * input?
1240 */
1241 static boolean_t
ktest_fqt_requires_input(ktest_triple_t * triple,nvlist_t * tests)1242 ktest_fqt_requires_input(ktest_triple_t *triple, nvlist_t *tests)
1243 {
1244 list_t filter;
1245 ktest_iter_t *iter = NULL;
1246 ktest_test_desc_t desc;
1247 /*
1248 * Need a local copy of the triple in order to build a filter
1249 * list for ktest_iter() because the argument is already a
1250 * part of the run list and reusing it would clobber its node
1251 * link.
1252 */
1253 ktest_triple_t cp = *triple;
1254
1255 VERIFY(ktest_is_fqt(triple));
1256
1257 list_create(&filter, sizeof (ktest_triple_t),
1258 offsetof(ktest_triple_t, ktr_node));
1259 list_insert_head(&filter, &cp);
1260 iter = ktest_iter(tests, &filter);
1261
1262 if (!ktest_iter_next(iter, &desc)) {
1263 return (B_FALSE);
1264 }
1265
1266 return (desc.ktd_requires_input);
1267 }
1268
1269 /*
1270 * Check if the fully-qualified triple has an input path when it
1271 * should. Return true if the entry is okay and false if there is a
1272 * mismatch between the test descriptor the the triple entry.
1273 */
1274 static boolean_t
ktest_check_fqt_entry(nvlist_t * tests,ktest_triple_t * triple)1275 ktest_check_fqt_entry(nvlist_t *tests, ktest_triple_t *triple)
1276 {
1277 boolean_t requires_input = ktest_fqt_requires_input(triple, tests);
1278
1279 if (requires_input && strlen(triple->ktr_input_path) == 0) {
1280 warnx("fully-qualified triple %s:%s:%s at line %u missing "
1281 "input for test that requires input", triple->ktr_module,
1282 triple->ktr_suite, triple->ktr_test, triple->ktr_lineno);
1283 return (B_FALSE);
1284 } else if (!requires_input && strlen(triple->ktr_input_path) != 0) {
1285 warnx("fully-qualified triple %s:%s:%s at line %u specifies "
1286 "input for test that does not require it",
1287 triple->ktr_module, triple->ktr_suite, triple->ktr_test,
1288 triple->ktr_lineno);
1289 return (B_FALSE);
1290 }
1291
1292 return (B_TRUE);
1293 }
1294
1295 /*
1296 * When a test is fully-qualified it could be for the purpose of
1297 * specifying an input stream. We provide this check to catch missing
1298 * input (or input on a test that does not require it) as a benefit to
1299 * the user.
1300 *
1301 * We do not exit immediately upon finding a bad entry; but instead
1302 * print a warning for each bad triple and then exit with failure.
1303 */
1304 static void
ktest_check_fqt_entries(nvlist_t * tests,list_t * run_list)1305 ktest_check_fqt_entries(nvlist_t *tests, list_t *run_list)
1306 {
1307 boolean_t bad_triple = B_FALSE;
1308
1309 for (ktest_triple_t *triple = list_head(run_list); triple != NULL;
1310 triple = list_next(run_list, triple)) {
1311 if (ktest_is_fqt(triple)) {
1312 if (!ktest_check_fqt_entry(tests, triple)) {
1313 bad_triple = B_TRUE;
1314 }
1315 }
1316 }
1317
1318 if (bad_triple) {
1319 errx(EXIT_FAILURE, "one or more incorrect triples");
1320 }
1321 }
1322
1323 /*
1324 * Verify that the run list is acceptable.
1325 */
1326 static void
ktest_verify_run_list(nvlist_t * tests,list_t * run_list)1327 ktest_verify_run_list(nvlist_t *tests, list_t *run_list)
1328 {
1329 ktest_check_fqt_entries(tests, run_list);
1330 }
1331
1332 static boolean_t
ktest_run_cmd(int argc,char * argv[],int ktdev)1333 ktest_run_cmd(int argc, char *argv[], int ktdev)
1334 {
1335 int c;
1336 nvlist_t *tests = NULL;
1337 list_t run_list;
1338 char *input_path = NULL;
1339 boolean_t parsable = B_FALSE;
1340 boolean_t fields_set = B_FALSE;
1341 boolean_t print_stats = B_TRUE;
1342 char *fields = KTEST_RUN_CMD_DEF_FIELDS;
1343 uint_t oflags = 0;
1344 ofmt_handle_t ofmt = NULL;
1345 ofmt_status_t oferr;
1346 boolean_t all_pass = B_FALSE;
1347
1348 while ((c = getopt(argc, argv, ":Ho:pi:")) != -1) {
1349 switch (c) {
1350 case 'H':
1351 oflags |= OFMT_NOHEADER;
1352 break;
1353 case 'o':
1354 fields = optarg;
1355 fields_set = B_TRUE;
1356 break;
1357 case 'p':
1358 parsable = B_TRUE;
1359 print_stats = B_FALSE;
1360 oflags |= OFMT_PARSABLE;
1361 break;
1362 case 'i':
1363 if (input_path != NULL) {
1364 ktest_usage("cannot specify -i more than once");
1365 exit(EXIT_USAGE);
1366 }
1367
1368 input_path = optarg;
1369
1370 if (strnlen(input_path, MAXPATHLEN) >= MAXPATHLEN) {
1371 err(EXIT_FAILURE, "input path too long");
1372 }
1373
1374 break;
1375 case ':':
1376 ktest_usage("missing argument to -%c", optopt);
1377 exit(EXIT_USAGE);
1378
1379 case '?':
1380 ktest_usage("unknown run option: -%c", optopt);
1381 exit(EXIT_USAGE);
1382 }
1383 }
1384
1385 if (parsable && !fields_set) {
1386 ktest_usage("must specify -o with -p");
1387 exit(EXIT_USAGE);
1388 }
1389
1390 oferr = ofmt_open(fields, ktest_run_ofmt, oflags, 0, &ofmt);
1391 ofmt_check(oferr, parsable, ofmt, ktest_ofmt_errx, warnx);
1392
1393 argc -= optind;
1394 argv += optind;
1395
1396 /*
1397 * We don't run all tests by default. We assume that as the
1398 * library of test modules grows we want to be sure the user
1399 * actually wants to run all tests by forcing them to at least
1400 * specify the `*` glob.
1401 */
1402 if (argc < 1) {
1403 ktest_usage("must specify at least one triple");
1404 exit(EXIT_USAGE);
1405 }
1406
1407 list_create(&run_list, sizeof (ktest_triple_t),
1408 offsetof(ktest_triple_t, ktr_node));
1409
1410 for (uint_t i = 0; i < argc; i++) {
1411 ktest_triple_t *triple = ktest_parse_triple(argv[i], 0);
1412
1413 if (triple == NULL) {
1414 errx(EXIT_FAILURE, "failed to parse triple: %s",
1415 argv[i]);
1416 }
1417
1418 if (input_path != NULL) {
1419 /*
1420 * The path length was checked during option
1421 * parsing.
1422 */
1423 (void) strcpy(triple->ktr_input_path, input_path);
1424 }
1425
1426 list_insert_tail(&run_list, triple);
1427 }
1428
1429 tests = ktest_list_tests(ktdev);
1430 ktest_verify_run_list(tests, &run_list);
1431 all_pass = ktest_run_tests(ktdev, tests, &run_list, ofmt, print_stats);
1432 ofmt_close(ofmt);
1433 ktest_free_triples(&run_list);
1434 list_destroy(&run_list);
1435 nvlist_free(tests);
1436 return (all_pass);
1437 }
1438
1439 static boolean_t
ktest_run_file_cmd(int argc,char * argv[],int ktdev)1440 ktest_run_file_cmd(int argc, char *argv[], int ktdev)
1441 {
1442 int c;
1443 nvlist_t *tests = NULL;
1444 list_t run_list;
1445 char *run_file = NULL;
1446 boolean_t use_stdin = B_FALSE;
1447 boolean_t parsable = B_FALSE;
1448 boolean_t fields_set = B_FALSE;
1449 boolean_t print_stats = B_TRUE;
1450 char *fields = KTEST_RUN_CMD_DEF_FIELDS;
1451 uint_t oflags = 0;
1452 ofmt_handle_t ofmt = NULL;
1453 ofmt_status_t oferr;
1454 boolean_t all_pass = B_FALSE;
1455
1456 while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
1457 switch (c) {
1458 case 'H':
1459 oflags |= OFMT_NOHEADER;
1460 break;
1461 case 'o':
1462 fields = optarg;
1463 fields_set = B_TRUE;
1464 break;
1465 case 'p':
1466 parsable = B_TRUE;
1467 print_stats = B_FALSE;
1468 oflags |= OFMT_PARSABLE;
1469 break;
1470 case ':':
1471 ktest_usage("missing argument to -%c", optopt);
1472 exit(EXIT_USAGE);
1473 case '?':
1474 ktest_usage("unknown option: -%c", optopt);
1475 exit(EXIT_USAGE);
1476 }
1477 }
1478
1479 if (parsable && !fields_set) {
1480 ktest_usage("must specify -o with -p");
1481 exit(EXIT_USAGE);
1482 }
1483
1484 oferr = ofmt_open(fields, ktest_run_ofmt, oflags, 0, &ofmt);
1485 ofmt_check(oferr, parsable, ofmt, ktest_ofmt_errx, warnx);
1486
1487 argc -= optind;
1488 argv += optind;
1489
1490 if (argc > 1) {
1491 ktest_usage("must specify only one run file");
1492 exit(EXIT_USAGE);
1493 }
1494
1495 /*
1496 * Use stdin as the run file when no run file argument is
1497 * specified.
1498 */
1499 if (argc == 0) {
1500 use_stdin = B_TRUE;
1501 }
1502
1503 run_file = argv[0];
1504 tests = ktest_list_tests(ktdev);
1505 list_create(&run_list, sizeof (ktest_triple_t),
1506 offsetof(ktest_triple_t, ktr_node));
1507 ktest_load_run_file(run_file, use_stdin, tests, &run_list);
1508 ktest_verify_run_list(tests, &run_list);
1509 all_pass = ktest_run_tests(ktdev, tests, &run_list, ofmt, print_stats);
1510 ofmt_close(ofmt);
1511 ktest_free_triples(&run_list);
1512 list_destroy(&run_list);
1513 nvlist_free(tests);
1514 return (all_pass);
1515 }
1516
1517 static void
ktest_list_cmd(int argc,char * argv[],int dev)1518 ktest_list_cmd(int argc, char *argv[], int dev)
1519 {
1520 int c;
1521 list_t triples;
1522 nvlist_t *tests = NULL;
1523 boolean_t parsable = B_FALSE;
1524 boolean_t fields_set = B_FALSE;
1525 char *fields = KTEST_LIST_CMD_DEF_FIELDS;
1526 uint_t oflags = 0;
1527 ofmt_handle_t ofmt = NULL;
1528 ofmt_status_t oferr;
1529
1530 list_create(&triples, sizeof (ktest_triple_t),
1531 offsetof(ktest_triple_t, ktr_node));
1532
1533 while ((c = getopt(argc, argv, ":Ho:p")) != -1) {
1534 switch (c) {
1535 case 'H':
1536 oflags |= OFMT_NOHEADER;
1537 break;
1538 case 'o':
1539 fields = optarg;
1540 fields_set = B_TRUE;
1541 break;
1542 case 'p':
1543 parsable = B_TRUE;
1544 oflags |= OFMT_PARSABLE;
1545 break;
1546 case ':':
1547 ktest_usage("missing argument to -%c", optopt);
1548 exit(EXIT_USAGE);
1549 case '?':
1550 ktest_usage("unknown option: -%c", optopt);
1551 exit(EXIT_USAGE);
1552 }
1553 }
1554
1555 if (parsable && !fields_set) {
1556 ktest_usage("must specify -o with -p");
1557 exit(EXIT_USAGE);
1558 }
1559
1560 oferr = ofmt_open(fields, ktest_list_ofmt, oflags, 0, &ofmt);
1561 ofmt_check(oferr, parsable, ofmt, ktest_ofmt_errx, warnx);
1562
1563 argc -= optind;
1564 argv += optind;
1565
1566 if (argc == 0) {
1567 list_insert_tail(&triples, ktest_def_triple);
1568 } else {
1569 for (uint_t i = 0; i < argc; i++) {
1570 ktest_triple_t *triple = ktest_parse_triple(argv[i], 0);
1571
1572 if (triple == NULL) {
1573 errx(EXIT_FAILURE, "failed to parse triple: %s",
1574 argv[i]);
1575 }
1576
1577 list_insert_tail(&triples, triple);
1578 }
1579 }
1580
1581 tests = ktest_list_tests(dev);
1582 ktest_print_tests(tests, &triples, ofmt);
1583 ofmt_close(ofmt);
1584 nvlist_free(tests);
1585 ktest_free_triples(&triples);
1586 list_destroy(&triples);
1587 }
1588
1589 static void
ktest_alloc_def_triple()1590 ktest_alloc_def_triple()
1591 {
1592 ktest_def_triple = ktest_parse_triple(KTEST_DEF_TRIPLE, 0);
1593
1594 if (ktest_def_triple == NULL) {
1595 err(EXIT_FAILURE, "failed to initialize default triple");
1596 }
1597 }
1598
1599 int
main(int argc,char * argv[])1600 main(int argc, char *argv[])
1601 {
1602 int fd;
1603 const char *cmd;
1604
1605 ktest_prog = basename(argv[0]);
1606
1607 if (getzoneid() != GLOBAL_ZONEID || getuid() != 0) {
1608 errx(EXIT_FAILURE, "can only be used by root from"
1609 " the global zone");
1610 }
1611
1612 if (argc < 2) {
1613 ktest_usage("no command specified");
1614 exit(EXIT_USAGE);
1615 }
1616
1617 /*
1618 * Peel off program name and command.
1619 */
1620 cmd = argv[1];
1621 argc -= 2;
1622 argv += 2;
1623 optind = 0;
1624
1625 if ((fd = open(KTEST_DEV_PATH, O_RDONLY, 0)) == -1) {
1626 err(EXIT_FAILURE, "failed to open %s", KTEST_DEV_PATH);
1627 }
1628
1629 ktest_alloc_def_triple();
1630
1631 if (strncasecmp("list", cmd, KTEST_CMD_SZ) == 0) {
1632 ktest_list_cmd(argc, argv, fd);
1633 } else if (strncasecmp("run", cmd, KTEST_CMD_SZ) == 0) {
1634 if (!ktest_run_cmd(argc, argv, fd)) {
1635 errx(EXIT_FAILURE, "one or more tests did not pass");
1636 }
1637 } else if (strncasecmp("run-file", cmd, KTEST_CMD_SZ) == 0) {
1638 if (!ktest_run_file_cmd(argc, argv, fd)) {
1639 errx(EXIT_FAILURE, "one or more tests did not pass");
1640 }
1641 } else if (strncasecmp("help", cmd, KTEST_CMD_SZ) == 0) {
1642 ktest_usage(NULL);
1643 } else {
1644 ktest_usage("unknown command: %s", cmd);
1645 exit(EXIT_USAGE);
1646 }
1647
1648 (void) close(fd);
1649 return (0);
1650 }
1651