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 2025 Oxide Computer Company 14 * Copyright 2024 Ryan Zezeski 15 */ 16 17 #include <stdlib.h> 18 #include <stdio.h> 19 #include <unistd.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <string.h> 23 #include <dirent.h> 24 #include <atomic.h> 25 #include <sys/ktest.h> 26 #include <sys/systeminfo.h> 27 #include <sys/modctl.h> 28 #include <upanic.h> 29 30 #include "libktest_impl.h" 31 32 /* 33 * Open ktest device handle. 34 * 35 * Returns handle pointer on success, otherwise NULL (setting errno). 36 */ 37 ktest_hdl_t * 38 ktest_init(void) 39 { 40 int fd = open(KTEST_DEV_PATH, O_RDONLY | O_CLOEXEC, 0); 41 if (fd < 0) { 42 return (NULL); 43 } 44 45 ktest_hdl_t *hdl = malloc(sizeof (ktest_hdl_t)); 46 if (hdl == NULL) { 47 const int err = errno; 48 (void) close(fd); 49 errno = err; 50 return (NULL); 51 } 52 53 hdl->kt_fd = fd; 54 return (hdl); 55 } 56 57 /* 58 * Close ktest device handle. 59 */ 60 void 61 ktest_fini(ktest_hdl_t *hdl) 62 { 63 if (hdl == NULL) { 64 return; 65 } 66 if (hdl->kt_fd >= 0) { 67 (void) close(hdl->kt_fd); 68 hdl->kt_fd = -1; 69 } 70 free(hdl); 71 } 72 73 #define DEFAULT_LIST_BUF_SZ (64 * 1024) 74 75 static nvlist_t * 76 ktest_query_tests(ktest_hdl_t *hdl) 77 { 78 char *resp = malloc(DEFAULT_LIST_BUF_SZ); 79 ktest_list_op_t op = { 80 .klo_resp = resp, 81 .klo_resp_len = DEFAULT_LIST_BUF_SZ, 82 }; 83 84 if (resp == NULL) { 85 return (NULL); 86 } 87 88 int ret; 89 ret = ioctl(hdl->kt_fd, KTEST_IOCTL_LIST_TESTS, &op); 90 91 /* Resize buffer and retry, if ioctl indicates it was too small */ 92 if (ret == -1 && errno == ENOBUFS) { 93 free(resp); 94 95 if ((resp = malloc(op.klo_resp_len)) == NULL) { 96 return (NULL); 97 } 98 op.klo_resp = resp; 99 ret = ioctl(hdl->kt_fd, KTEST_IOCTL_LIST_TESTS, &op); 100 } 101 if (ret == -1) { 102 free(resp); 103 return (NULL); 104 } 105 106 nvlist_t *tests = NULL; 107 if ((ret = nvlist_unpack(resp, op.klo_resp_len, &tests, 0)) != 0) { 108 free(resp); 109 errno = ret; 110 return (NULL); 111 } 112 free(resp); 113 114 /* 115 * Verify that the response is marked with the expected serialization 116 * format. Remove the nvpair so that only the modules remain. 117 */ 118 uint64_t vsn = 0; 119 if (nvlist_lookup_uint64(tests, KTEST_SER_FMT_KEY, &vsn) != 0 || 120 vsn != KTEST_SER_FMT_VSN) { 121 nvlist_free(tests); 122 errno = EINVAL; 123 return (NULL); 124 } 125 fnvlist_remove(tests, KTEST_SER_FMT_KEY); 126 127 return (tests); 128 } 129 130 static void 131 ktest_iter_next_test(ktest_list_iter_t *iter, bool do_reset) 132 { 133 if (iter->kli_test == NULL && !do_reset) { 134 return; 135 } 136 if (iter->kli_tests == NULL) { 137 return; 138 } 139 140 iter->kli_test = nvlist_next_nvpair(iter->kli_tests, iter->kli_test); 141 while (iter->kli_test != NULL) { 142 boolean_t requires_input; 143 if (nvpair_type(iter->kli_test) == DATA_TYPE_NVLIST && 144 nvlist_lookup_boolean_value( 145 fnvpair_value_nvlist(iter->kli_test), KTEST_TEST_INPUT_KEY, 146 &requires_input) == 0) { 147 iter->kli_req_input = requires_input; 148 break; 149 } 150 iter->kli_test = 151 nvlist_next_nvpair(iter->kli_tests, iter->kli_test); 152 } 153 } 154 155 static void 156 ktest_iter_next_suite(ktest_list_iter_t *iter, bool do_reset) 157 { 158 if (iter->kli_suite == NULL && !do_reset) { 159 return; 160 } 161 if (iter->kli_suites == NULL) { 162 return; 163 } 164 165 iter->kli_suite = nvlist_next_nvpair(iter->kli_suites, iter->kli_suite); 166 iter->kli_tests = NULL; 167 iter->kli_test = NULL; 168 while (iter->kli_suite != NULL) { 169 if (nvpair_type(iter->kli_suite) == DATA_TYPE_NVLIST && 170 nvlist_lookup_nvlist(fnvpair_value_nvlist(iter->kli_suite), 171 KTEST_SUITE_TESTS_KEY, &iter->kli_tests) == 0) { 172 break; 173 } 174 175 iter->kli_suite = nvlist_next_nvpair(iter->kli_suites, 176 iter->kli_suite); 177 } 178 179 ktest_iter_next_test(iter, true); 180 } 181 182 static void 183 ktest_iter_next_module(ktest_list_iter_t *iter, bool do_reset) 184 { 185 if (iter->kli_module == NULL && !do_reset) { 186 return; 187 } 188 VERIFY(iter->kli_modules != NULL); 189 190 iter->kli_module = nvlist_next_nvpair(iter->kli_modules, 191 iter->kli_module); 192 iter->kli_suites = NULL; 193 iter->kli_suite = NULL; 194 195 while (iter->kli_module != NULL) { 196 if (nvpair_type(iter->kli_module) == DATA_TYPE_NVLIST && 197 nvlist_lookup_nvlist(fnvpair_value_nvlist(iter->kli_module), 198 KTEST_MODULE_SUITES_KEY, &iter->kli_suites) == 0) { 199 break; 200 } 201 202 iter->kli_module = 203 nvlist_next_nvpair(iter->kli_modules, iter->kli_module); 204 } 205 206 ktest_iter_next_suite(iter, true); 207 } 208 209 /* 210 * List currently available ktests. 211 * 212 * Returns test list iterator on success, otherwise NULL (setting errno). 213 */ 214 ktest_list_iter_t * 215 ktest_list(ktest_hdl_t *hdl) 216 { 217 nvlist_t *tests = ktest_query_tests(hdl); 218 219 if (tests == NULL) { 220 return (NULL); 221 } 222 223 ktest_list_iter_t *iter = malloc(sizeof (ktest_list_iter_t)); 224 if (iter == NULL) { 225 const int err = errno; 226 nvlist_free(tests); 227 errno = err; 228 return (NULL); 229 } 230 231 iter->kli_hdl = hdl; 232 iter->kli_modules = tests; 233 iter->kli_module = NULL; 234 ktest_iter_next_module(iter, true); 235 236 return (iter); 237 } 238 239 /* 240 * Get the next ktest entry from a test list iterator. 241 * 242 * Returns true an item was available from the iterator (populating entry), 243 * otherwise false. 244 */ 245 bool 246 ktest_list_next(ktest_list_iter_t *iter, ktest_entry_t *entry) 247 { 248 while (iter->kli_module != NULL) { 249 if (iter->kli_test != NULL) { 250 /* 251 * Output the current test, and move iterator to the 252 * next in preparation for a subsequent call. 253 */ 254 entry->ke_module = nvpair_name(iter->kli_module); 255 entry->ke_suite = nvpair_name(iter->kli_suite); 256 entry->ke_test = nvpair_name(iter->kli_test); 257 entry->ke_requires_input = iter->kli_req_input; 258 ktest_iter_next_test(iter, false); 259 return (true); 260 } 261 262 ktest_iter_next_suite(iter, false); 263 if (iter->kli_suite != NULL) { 264 continue; 265 } 266 ktest_iter_next_module(iter, false); 267 } 268 return (false); 269 } 270 271 /* 272 * Reset ktest list iterator to its beginning. 273 */ 274 void 275 ktest_list_reset(ktest_list_iter_t *iter) 276 { 277 iter->kli_module = NULL; 278 ktest_iter_next_module(iter, true); 279 } 280 281 /* 282 * Free a ktest list iterator. 283 */ 284 void 285 ktest_list_free(ktest_list_iter_t *iter) 286 { 287 if (iter == NULL) { 288 return; 289 } 290 iter->kli_test = iter->kli_suite = iter->kli_module = NULL; 291 if (iter->kli_modules != NULL) { 292 nvlist_free(iter->kli_modules); 293 iter->kli_modules = NULL; 294 } 295 free(iter); 296 } 297 298 /* 299 * Run a ktest. 300 * 301 * Requests that the ktest module run a ktest specified by module/suite/test 302 * triple in the ktest_run_req_t. If the test requires input, that too is 303 * expected to be set in the run request. 304 * 305 * If the test was able to be run (regardless of its actual result), and the 306 * emitted results data processed, ktest_run() will return true. Any message 307 * output from the test will be placed in krr_msg, which the caller is 308 * responsible for free()-ing. 309 * 310 * If an error was encountered while attempting to run the test, or process its 311 * results, ktest_run() will return false, and the ktest_run_result_t will not 312 * be populated. 313 */ 314 bool 315 ktest_run(ktest_hdl_t *hdl, const ktest_run_req_t *req, ktest_run_result_t *res) 316 { 317 ktest_run_op_t kro = { 318 .kro_input_bytes = req->krq_input, 319 .kro_input_len = req->krq_input_len, 320 }; 321 322 (void) strncpy(kro.kro_module, req->krq_module, 323 sizeof (kro.kro_module)); 324 (void) strncpy(kro.kro_suite, req->krq_suite, sizeof (kro.kro_suite)); 325 (void) strncpy(kro.kro_test, req->krq_test, sizeof (kro.kro_test)); 326 327 if (ioctl(hdl->kt_fd, KTEST_IOCTL_RUN_TEST, &kro) == -1) { 328 return (false); 329 } 330 331 const ktest_result_t *kres = &kro.kro_result; 332 res->krr_code = (ktest_code_t)kres->kr_type; 333 res->krr_line = (uint_t)kres->kr_line; 334 335 const size_t msg_len = 336 strnlen(kres->kr_msg_prepend, sizeof (kres->kr_msg_prepend)) + 337 strnlen(kres->kr_msg, sizeof (kres->kr_msg)); 338 339 if (msg_len != 0) { 340 if (asprintf(&res->krr_msg, "%s%s", kres->kr_msg_prepend, 341 kres->kr_msg) == -1) { 342 return (false); 343 } 344 } else { 345 res->krr_msg = NULL; 346 } 347 348 return (true); 349 } 350 351 352 /* 353 * Get the string name for a ktest_code_t. 354 */ 355 const char * 356 ktest_code_name(ktest_code_t code) 357 { 358 switch (code) { 359 case KTEST_CODE_NONE: 360 return ("NONE"); 361 case KTEST_CODE_PASS: 362 return ("PASS"); 363 case KTEST_CODE_FAIL: 364 return ("FAIL"); 365 case KTEST_CODE_SKIP: 366 return ("SKIP"); 367 case KTEST_CODE_ERROR: 368 return ("ERROR"); 369 default: 370 break; 371 } 372 const char errmsg[] = "unexpected ktest_code value"; 373 upanic(errmsg, sizeof (errmsg)); 374 } 375 376 #define KTEST_MODULE_SUFFIX "_ktest" 377 #define KTEST_BASE_MODULE_DIR "/usr/kernel/misc/ktest" 378 379 static char *ktest_cached_module_dir; 380 381 static const char * 382 ktest_mod_directory(void) 383 { 384 if (ktest_cached_module_dir != NULL) { 385 return (ktest_cached_module_dir); 386 } 387 388 char archbuf[20]; 389 if (sysinfo(SI_ARCHITECTURE_64, archbuf, sizeof (archbuf)) < 0) { 390 return (NULL); 391 } 392 393 char *path = NULL; 394 if (asprintf(&path, "%s/%s", KTEST_BASE_MODULE_DIR, archbuf) < 0) { 395 return (NULL); 396 } 397 398 char *old = atomic_cas_ptr(&ktest_cached_module_dir, NULL, path); 399 if (old == NULL) { 400 return (path); 401 } else { 402 free(path); 403 return (ktest_cached_module_dir); 404 } 405 } 406 407 static bool 408 ktest_mod_path(const char *name, char *buf) 409 { 410 const char *base = ktest_mod_directory(); 411 if (base == NULL) { 412 return (false); 413 } 414 415 (void) snprintf(buf, MAXPATHLEN, "%s/%s" KTEST_MODULE_SUFFIX, base, 416 name); 417 return (true); 418 } 419 420 static int 421 ktest_mod_id_for_name(const char *name) 422 { 423 struct modinfo modinfo = { 424 .mi_info = MI_INFO_ONE | MI_INFO_BY_NAME, 425 }; 426 (void) snprintf(modinfo.mi_name, sizeof (modinfo.mi_name), 427 "%s" KTEST_MODULE_SUFFIX, name); 428 429 if (modctl(MODINFO, 0, &modinfo) < 0) { 430 return (-1); 431 } 432 return (modinfo.mi_id); 433 } 434 435 /* 436 * Attempt to load a test module. 437 * 438 * Returns true if a ktests for the module could be loaded (or were already so), 439 * otherwise false (setting errno). 440 */ 441 bool 442 ktest_mod_load(const char *name) 443 { 444 if (ktest_mod_id_for_name(name) > 0) { 445 /* Module is already loaded */ 446 return (true); 447 } 448 449 char path[MAXPATHLEN]; 450 if (!ktest_mod_path(name, path)) { 451 return (false); 452 } 453 454 int id = 0; 455 if (modctl(MODLOAD, 0, path, &id) != 0) { 456 return (false); 457 } 458 return (true); 459 } 460 461 /* 462 * Attempt to unload a test module. 463 */ 464 void 465 ktest_mod_unload(const char *name) 466 { 467 const int id = ktest_mod_id_for_name(name); 468 if (id > 0) { 469 (void) modctl(MODUNLOAD, id); 470 } 471 } 472 473 static bool 474 ktest_mod_for_each(void (*cb)(const char *)) 475 { 476 const char *dpath; 477 478 if ((dpath = ktest_mod_directory()) == NULL) { 479 return (false); 480 } 481 482 DIR *dp = opendir(dpath); 483 if (dp == NULL) { 484 return (false); 485 } 486 struct dirent *de; 487 while ((de = readdir(dp)) != NULL) { 488 char *suffix = strrchr(de->d_name, '_'); 489 490 if (suffix == NULL || 491 strcmp(suffix, KTEST_MODULE_SUFFIX) != 0) { 492 continue; 493 } 494 /* 495 * Drop the suffix from the name, and confirm that it is 496 * appropriately sized for a module. 497 */ 498 *suffix = '\0'; 499 const size_t name_sz = strnlen(de->d_name, MODMAXNAMELEN); 500 if (name_sz == 0 || name_sz >= MODMAXNAMELEN) { 501 continue; 502 } 503 504 /* Execute on valid candidate */ 505 cb(de->d_name); 506 } 507 return (true); 508 } 509 510 static void 511 ktest_mod_load_cb(const char *name) 512 { 513 (void) ktest_mod_load(name); 514 } 515 516 /* 517 * Attempt to load all known test modules. 518 * 519 * Returns true if the modules could be found in their expected directory, and 520 * all were loaded successfully, otherwise false (setting errno). In the case 521 * of error, some modules may have been loaded. 522 */ 523 bool 524 ktest_mod_load_all(void) 525 { 526 return (ktest_mod_for_each(ktest_mod_load_cb)); 527 } 528 529 static void 530 ktest_mod_unload_cb(const char *name) 531 { 532 ktest_mod_unload(name); 533 } 534 535 /* 536 * Attempt to unload all known test modules. 537 * 538 * Returns true if the test modules could be iterated over, and unload 539 * operations attempted. A false result (with its accompanying errno) indicates 540 * a problem reading the directory in which the tests reside. 541 */ 542 bool 543 ktest_mod_unload_all(void) 544 { 545 return (ktest_mod_for_each(ktest_mod_unload_cb)); 546 } 547 548 /* 549 * Query the max input data size (in bytes) which can be provided to a test. 550 */ 551 size_t 552 ktest_max_input_size(void) 553 { 554 return (KTEST_IOCTL_MAX_LEN); 555 } 556