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