xref: /illumos-gate/usr/src/lib/libktest/common/libktest.c (revision 2a838cdeeca0eef6fcf8eaa3df95be38375b4af7)
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