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 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 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 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 * 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 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 * 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 * 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 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 * 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 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 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 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 * 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 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 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 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 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 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 * 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 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 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 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 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 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 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 1333 ktest_run_cmd(int argc, char *argv[], int ktdev) 1334 { 1335 char 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 1440 ktest_run_file_cmd(int argc, char *argv[], int ktdev) 1441 { 1442 char 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 1518 ktest_list_cmd(int argc, char *argv[], int dev) 1519 { 1520 char 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 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 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