1 1.16 pgoyette /* $NetBSD: t_modctl.c,v 1.16 2020/02/22 19:54:34 pgoyette Exp $ */ 2 1.1 jmmv /* 3 1.1 jmmv * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 1.1 jmmv * All rights reserved. 5 1.1 jmmv * 6 1.1 jmmv * Redistribution and use in source and binary forms, with or without 7 1.1 jmmv * modification, are permitted provided that the following conditions 8 1.1 jmmv * are met: 9 1.1 jmmv * 1. Redistributions of source code must retain the above copyright 10 1.1 jmmv * notice, this list of conditions and the following disclaimer. 11 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 jmmv * notice, this list of conditions and the following disclaimer in the 13 1.1 jmmv * documentation and/or other materials provided with the distribution. 14 1.1 jmmv * 15 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 16 1.1 jmmv * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 1.1 jmmv * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 1.1 jmmv * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmmv * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 20 1.1 jmmv * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 jmmv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 1.1 jmmv * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 24 1.1 jmmv * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 1.1 jmmv * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 1.1 jmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 jmmv */ 28 1.1 jmmv 29 1.1 jmmv #include <sys/cdefs.h> 30 1.16 pgoyette __KERNEL_RCSID(0, "$NetBSD: t_modctl.c,v 1.16 2020/02/22 19:54:34 pgoyette Exp $"); 31 1.1 jmmv 32 1.1 jmmv #include <sys/module.h> 33 1.1 jmmv #include <sys/sysctl.h> 34 1.1 jmmv 35 1.1 jmmv #include <assert.h> 36 1.1 jmmv #include <errno.h> 37 1.1 jmmv #include <stdarg.h> 38 1.1 jmmv #include <stdbool.h> 39 1.1 jmmv #include <stdio.h> 40 1.1 jmmv #include <stdlib.h> 41 1.1 jmmv #include <string.h> 42 1.16 pgoyette #include <sys/evcnt.h> 43 1.1 jmmv 44 1.1 jmmv #include <prop/proplib.h> 45 1.1 jmmv 46 1.1 jmmv #include <atf-c.h> 47 1.1 jmmv 48 1.16 pgoyette enum presence_check { all_checks, stat_check, sysctl_check, evcnt_check }; 49 1.1 jmmv 50 1.10 martin static void check_permission(void); 51 1.7 jruoho static bool get_modstat_info(const char *, modstat_t *); 52 1.7 jruoho static bool get_sysctl(const char *, void *buf, const size_t); 53 1.7 jruoho static bool k_helper_is_present_stat(void); 54 1.7 jruoho static bool k_helper_is_present_sysctl(void); 55 1.16 pgoyette static bool k_helper_is_present_evcnt(void); 56 1.7 jruoho static bool k_helper_is_present(enum presence_check); 57 1.7 jruoho static int load(prop_dictionary_t, bool, const char *, ...); 58 1.7 jruoho static int unload(const char *, bool); 59 1.7 jruoho static void unload_cleanup(const char *); 60 1.1 jmmv 61 1.1 jmmv /* --------------------------------------------------------------------- */ 62 1.1 jmmv /* Auxiliary functions */ 63 1.1 jmmv /* --------------------------------------------------------------------- */ 64 1.1 jmmv 65 1.1 jmmv /* 66 1.14 maya * A function checking whether we are allowed to load modules currently 67 1.10 martin * (either the kernel is not modular, or securelevel may prevent it) 68 1.1 jmmv */ 69 1.10 martin static void 70 1.10 martin check_permission(void) 71 1.1 jmmv { 72 1.10 martin int err; 73 1.10 martin 74 1.10 martin err = modctl(MODCTL_EXISTS, 0); 75 1.12 martin if (err == 0) return; 76 1.12 martin if (errno == ENOSYS) 77 1.10 martin atf_tc_skip("Kernel does not have 'options MODULAR'."); 78 1.12 martin else if (errno == EPERM) 79 1.10 martin atf_tc_skip("Module loading administratively forbidden"); 80 1.12 martin ATF_REQUIRE_EQ_MSG(errno, 0, "unexpected error %d from " 81 1.12 martin "modctl(MODCTL_EXISTS, 0)", errno); 82 1.1 jmmv } 83 1.1 jmmv 84 1.7 jruoho static bool 85 1.1 jmmv get_modstat_info(const char *name, modstat_t *msdest) 86 1.1 jmmv { 87 1.1 jmmv bool found; 88 1.1 jmmv size_t len; 89 1.13 pgoyette int count; 90 1.1 jmmv struct iovec iov; 91 1.1 jmmv modstat_t *ms; 92 1.15 kamil modstat_t m; 93 1.1 jmmv 94 1.10 martin check_permission(); 95 1.13 pgoyette for (len = 8192; ;) { 96 1.1 jmmv iov.iov_base = malloc(len); 97 1.1 jmmv iov.iov_len = len; 98 1.7 jruoho 99 1.7 jruoho errno = 0; 100 1.7 jruoho 101 1.1 jmmv if (modctl(MODCTL_STAT, &iov) != 0) { 102 1.1 jmmv int err = errno; 103 1.1 jmmv fprintf(stderr, "modctl(MODCTL_STAT) failed: %s\n", 104 1.1 jmmv strerror(err)); 105 1.1 jmmv atf_tc_fail("Failed to query module status"); 106 1.1 jmmv } 107 1.1 jmmv if (len >= iov.iov_len) 108 1.1 jmmv break; 109 1.1 jmmv free(iov.iov_base); 110 1.1 jmmv len = iov.iov_len; 111 1.1 jmmv } 112 1.1 jmmv 113 1.1 jmmv found = false; 114 1.13 pgoyette count = *(int *)iov.iov_base; 115 1.13 pgoyette ms = (modstat_t *)((char *)iov.iov_base + sizeof(int)); 116 1.13 pgoyette while ( count ) { 117 1.15 kamil memcpy(&m, ms, sizeof(m)); 118 1.15 kamil if (strcmp(m.ms_name, name) == 0) { 119 1.1 jmmv if (msdest != NULL) 120 1.15 kamil memcpy(msdest, &m, sizeof(*msdest)); 121 1.1 jmmv found = true; 122 1.13 pgoyette break; 123 1.1 jmmv } 124 1.13 pgoyette ms++; 125 1.13 pgoyette count--; 126 1.1 jmmv } 127 1.1 jmmv 128 1.1 jmmv free(iov.iov_base); 129 1.1 jmmv 130 1.1 jmmv return found; 131 1.1 jmmv } 132 1.1 jmmv 133 1.1 jmmv /* 134 1.1 jmmv * Queries a sysctl property. 135 1.1 jmmv */ 136 1.7 jruoho static bool 137 1.1 jmmv get_sysctl(const char *name, void *buf, const size_t len) 138 1.1 jmmv { 139 1.1 jmmv size_t len2 = len; 140 1.1 jmmv printf("Querying sysctl variable: %s\n", name); 141 1.1 jmmv int ret = sysctlbyname(name, buf, &len2, NULL, 0); 142 1.1 jmmv if (ret == -1 && errno != ENOENT) { 143 1.1 jmmv fprintf(stderr, "sysctlbyname(2) failed: %s\n", 144 1.1 jmmv strerror(errno)); 145 1.1 jmmv atf_tc_fail("Failed to query %s", name); 146 1.1 jmmv } 147 1.1 jmmv return ret != -1; 148 1.1 jmmv } 149 1.1 jmmv 150 1.1 jmmv /* 151 1.1 jmmv * Returns a boolean indicating if the k_helper module was loaded 152 1.1 jmmv * successfully. This implementation uses modctl(2)'s MODCTL_STAT 153 1.1 jmmv * subcommand to do the check. 154 1.1 jmmv */ 155 1.7 jruoho static bool 156 1.1 jmmv k_helper_is_present_stat(void) 157 1.1 jmmv { 158 1.1 jmmv 159 1.1 jmmv return get_modstat_info("k_helper", NULL); 160 1.1 jmmv } 161 1.1 jmmv 162 1.1 jmmv /* 163 1.1 jmmv * Returns a boolean indicating if the k_helper module was loaded 164 1.1 jmmv * successfully. This implementation uses the module's sysctl 165 1.1 jmmv * installed node to do the check. 166 1.1 jmmv */ 167 1.7 jruoho static bool 168 1.1 jmmv k_helper_is_present_sysctl(void) 169 1.1 jmmv { 170 1.1 jmmv size_t present; 171 1.1 jmmv 172 1.1 jmmv return get_sysctl("vendor.k_helper.present", &present, 173 1.1 jmmv sizeof(present)); 174 1.1 jmmv } 175 1.1 jmmv 176 1.1 jmmv /* 177 1.1 jmmv * Returns a boolean indicating if the k_helper module was loaded 178 1.16 pgoyette * successfully. This implementation uses the module's evcnt 179 1.16 pgoyette * to do the check. 180 1.16 pgoyette */ 181 1.16 pgoyette static bool 182 1.16 pgoyette k_helper_is_present_evcnt(void) 183 1.16 pgoyette { 184 1.16 pgoyette const int mib[4] = {CTL_KERN, KERN_EVCNT, EVCNT_TYPE_ANY, 185 1.16 pgoyette KERN_EVCNT_COUNT_ANY }; 186 1.16 pgoyette int error; 187 1.16 pgoyette size_t newlen, buflen = 0; 188 1.16 pgoyette void *buf0, *buf = NULL; 189 1.16 pgoyette const struct evcnt_sysctl *evs, *last_evs; 190 1.16 pgoyette 191 1.16 pgoyette for (;;) { 192 1.16 pgoyette if (buflen) 193 1.16 pgoyette buf = malloc(buflen); 194 1.16 pgoyette error = sysctl(mib, __arraycount(mib), buf, &newlen, NULL, 0); 195 1.16 pgoyette if (error) { 196 1.16 pgoyette if (buf) 197 1.16 pgoyette free(buf); 198 1.16 pgoyette return false; 199 1.16 pgoyette } 200 1.16 pgoyette if (newlen <= buflen) { 201 1.16 pgoyette buflen = newlen; 202 1.16 pgoyette break; 203 1.16 pgoyette } 204 1.16 pgoyette if (buf) 205 1.16 pgoyette free(buf); 206 1.16 pgoyette buflen = newlen; 207 1.16 pgoyette } 208 1.16 pgoyette evs = buf0 = buf; 209 1.16 pgoyette last_evs = (void *)((char *)buf + buflen); 210 1.16 pgoyette buflen /= sizeof(uint64_t); 211 1.16 pgoyette while (evs < last_evs 212 1.16 pgoyette && buflen >= sizeof(*evs)/sizeof(uint64_t) 213 1.16 pgoyette && buflen >= evs->ev_len) { 214 1.16 pgoyette if ( strncmp(evs->ev_strings, "k_helper", evs->ev_grouplen) 215 1.16 pgoyette == 0) { 216 1.16 pgoyette free(buf); 217 1.16 pgoyette return true; 218 1.16 pgoyette } 219 1.16 pgoyette buflen -= evs->ev_len; 220 1.16 pgoyette evs = (const void *)((const uint64_t *)evs + evs->ev_len); 221 1.16 pgoyette } 222 1.16 pgoyette free(buf); 223 1.16 pgoyette return false; 224 1.16 pgoyette } 225 1.16 pgoyette 226 1.16 pgoyette /* 227 1.16 pgoyette * Returns a boolean indicating if the k_helper module was loaded 228 1.1 jmmv * successfully. The 'how' parameter specifies the implementation to 229 1.1 jmmv * use to do the check. 230 1.1 jmmv */ 231 1.7 jruoho static bool 232 1.1 jmmv k_helper_is_present(enum presence_check how) 233 1.1 jmmv { 234 1.1 jmmv bool found; 235 1.1 jmmv 236 1.1 jmmv switch (how) { 237 1.16 pgoyette case all_checks: 238 1.1 jmmv found = k_helper_is_present_stat(); 239 1.1 jmmv ATF_CHECK(k_helper_is_present_sysctl() == found); 240 1.16 pgoyette ATF_CHECK(k_helper_is_present_evcnt() == found); 241 1.1 jmmv break; 242 1.1 jmmv 243 1.1 jmmv case stat_check: 244 1.1 jmmv found = k_helper_is_present_stat(); 245 1.1 jmmv break; 246 1.1 jmmv 247 1.1 jmmv case sysctl_check: 248 1.1 jmmv found = k_helper_is_present_sysctl(); 249 1.1 jmmv break; 250 1.1 jmmv 251 1.16 pgoyette case evcnt_check: 252 1.16 pgoyette found = k_helper_is_present_evcnt(); 253 1.16 pgoyette break; 254 1.16 pgoyette 255 1.1 jmmv default: 256 1.5 christos found = false; 257 1.5 christos assert(found); 258 1.1 jmmv } 259 1.1 jmmv 260 1.1 jmmv return found; 261 1.1 jmmv } 262 1.1 jmmv 263 1.1 jmmv /* 264 1.1 jmmv * Loads the specified module from a file. If fatal is set and an error 265 1.1 jmmv * occurs when loading the module, an error message is printed and the 266 1.1 jmmv * test case is aborted. 267 1.1 jmmv */ 268 1.8 joerg static __printflike(3, 4) int 269 1.1 jmmv load(prop_dictionary_t props, bool fatal, const char *fmt, ...) 270 1.1 jmmv { 271 1.1 jmmv int err; 272 1.1 jmmv va_list ap; 273 1.1 jmmv char filename[MAXPATHLEN], *propsstr; 274 1.1 jmmv modctl_load_t ml; 275 1.1 jmmv 276 1.10 martin check_permission(); 277 1.1 jmmv if (props == NULL) { 278 1.1 jmmv props = prop_dictionary_create(); 279 1.1 jmmv propsstr = prop_dictionary_externalize(props); 280 1.1 jmmv ATF_CHECK(propsstr != NULL); 281 1.1 jmmv prop_object_release(props); 282 1.1 jmmv } else { 283 1.1 jmmv propsstr = prop_dictionary_externalize(props); 284 1.1 jmmv ATF_CHECK(propsstr != NULL); 285 1.1 jmmv } 286 1.1 jmmv 287 1.1 jmmv va_start(ap, fmt); 288 1.1 jmmv vsnprintf(filename, sizeof(filename), fmt, ap); 289 1.1 jmmv va_end(ap); 290 1.1 jmmv 291 1.1 jmmv ml.ml_filename = filename; 292 1.1 jmmv ml.ml_flags = 0; 293 1.1 jmmv ml.ml_props = propsstr; 294 1.1 jmmv ml.ml_propslen = strlen(propsstr); 295 1.1 jmmv 296 1.1 jmmv printf("Loading module %s\n", filename); 297 1.7 jruoho errno = err = 0; 298 1.7 jruoho 299 1.1 jmmv if (modctl(MODCTL_LOAD, &ml) == -1) { 300 1.1 jmmv err = errno; 301 1.1 jmmv fprintf(stderr, "modctl(MODCTL_LOAD, %s), failed: %s\n", 302 1.1 jmmv filename, strerror(err)); 303 1.1 jmmv if (fatal) 304 1.1 jmmv atf_tc_fail("Module load failed"); 305 1.1 jmmv } 306 1.1 jmmv 307 1.1 jmmv free(propsstr); 308 1.1 jmmv 309 1.1 jmmv return err; 310 1.1 jmmv } 311 1.1 jmmv 312 1.1 jmmv /* 313 1.1 jmmv * Unloads the specified module. If silent is true, nothing will be 314 1.1 jmmv * printed and no errors will be raised if the unload was unsuccessful. 315 1.1 jmmv */ 316 1.7 jruoho static int 317 1.1 jmmv unload(const char *name, bool fatal) 318 1.1 jmmv { 319 1.1 jmmv int err; 320 1.1 jmmv 321 1.10 martin check_permission(); 322 1.1 jmmv printf("Unloading module %s\n", name); 323 1.7 jruoho errno = err = 0; 324 1.7 jruoho 325 1.1 jmmv if (modctl(MODCTL_UNLOAD, __UNCONST(name)) == -1) { 326 1.1 jmmv err = errno; 327 1.1 jmmv fprintf(stderr, "modctl(MODCTL_UNLOAD, %s) failed: %s\n", 328 1.1 jmmv name, strerror(err)); 329 1.1 jmmv if (fatal) 330 1.1 jmmv atf_tc_fail("Module unload failed"); 331 1.1 jmmv } 332 1.1 jmmv return err; 333 1.1 jmmv } 334 1.1 jmmv 335 1.1 jmmv /* 336 1.1 jmmv * A silent version of unload, to be called as part of the cleanup 337 1.1 jmmv * process only. 338 1.1 jmmv */ 339 1.7 jruoho static void 340 1.1 jmmv unload_cleanup(const char *name) 341 1.1 jmmv { 342 1.1 jmmv 343 1.1 jmmv (void)modctl(MODCTL_UNLOAD, __UNCONST(name)); 344 1.1 jmmv } 345 1.1 jmmv 346 1.1 jmmv /* --------------------------------------------------------------------- */ 347 1.1 jmmv /* Test cases */ 348 1.1 jmmv /* --------------------------------------------------------------------- */ 349 1.1 jmmv 350 1.1 jmmv ATF_TC_WITH_CLEANUP(cmd_load); 351 1.1 jmmv ATF_TC_HEAD(cmd_load, tc) 352 1.1 jmmv { 353 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_LOAD command"); 354 1.1 jmmv atf_tc_set_md_var(tc, "require.user", "root"); 355 1.1 jmmv } 356 1.1 jmmv ATF_TC_BODY(cmd_load, tc) 357 1.1 jmmv { 358 1.1 jmmv char longname[MAXPATHLEN]; 359 1.1 jmmv size_t i; 360 1.1 jmmv 361 1.9 jruoho ATF_CHECK(load(NULL, false, " ") == ENOENT); 362 1.1 jmmv ATF_CHECK(load(NULL, false, "non-existent.o") == ENOENT); 363 1.1 jmmv 364 1.1 jmmv for (i = 0; i < MAXPATHLEN - 1; i++) 365 1.1 jmmv longname[i] = 'a'; 366 1.1 jmmv longname[MAXPATHLEN - 1] = '\0'; 367 1.8 joerg ATF_CHECK(load(NULL, false, "%s", longname) == ENAMETOOLONG); 368 1.1 jmmv 369 1.1 jmmv ATF_CHECK(!k_helper_is_present(stat_check)); 370 1.3 jmmv load(NULL, true, "%s/k_helper/k_helper.kmod", 371 1.3 jmmv atf_tc_get_config_var(tc, "srcdir")); 372 1.1 jmmv printf("Checking if load was successful\n"); 373 1.1 jmmv ATF_CHECK(k_helper_is_present(stat_check)); 374 1.1 jmmv } 375 1.1 jmmv ATF_TC_CLEANUP(cmd_load, tc) 376 1.1 jmmv { 377 1.1 jmmv unload_cleanup("k_helper"); 378 1.1 jmmv } 379 1.1 jmmv 380 1.1 jmmv ATF_TC_WITH_CLEANUP(cmd_load_props); 381 1.1 jmmv ATF_TC_HEAD(cmd_load_props, tc) 382 1.1 jmmv { 383 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_LOAD command, " 384 1.1 jmmv "providing extra load-time properties"); 385 1.1 jmmv atf_tc_set_md_var(tc, "require.user", "root"); 386 1.1 jmmv } 387 1.1 jmmv ATF_TC_BODY(cmd_load_props, tc) 388 1.1 jmmv { 389 1.1 jmmv prop_dictionary_t props; 390 1.1 jmmv 391 1.1 jmmv printf("Loading module without properties\n"); 392 1.1 jmmv props = prop_dictionary_create(); 393 1.3 jmmv load(props, true, "%s/k_helper/k_helper.kmod", 394 1.3 jmmv atf_tc_get_config_var(tc, "srcdir")); 395 1.1 jmmv prop_object_release(props); 396 1.1 jmmv { 397 1.1 jmmv int ok; 398 1.1 jmmv ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok", 399 1.1 jmmv &ok, sizeof(ok))); 400 1.1 jmmv ATF_CHECK(!ok); 401 1.1 jmmv } 402 1.1 jmmv unload("k_helper", true); 403 1.1 jmmv 404 1.1 jmmv printf("Loading module with a string property\n"); 405 1.1 jmmv props = prop_dictionary_create(); 406 1.1 jmmv prop_dictionary_set(props, "prop_str", 407 1.1 jmmv prop_string_create_cstring("1st string")); 408 1.3 jmmv load(props, true, "%s/k_helper/k_helper.kmod", 409 1.3 jmmv atf_tc_get_config_var(tc, "srcdir")); 410 1.1 jmmv prop_object_release(props); 411 1.1 jmmv { 412 1.1 jmmv int ok; 413 1.1 jmmv ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok", 414 1.1 jmmv &ok, sizeof(ok))); 415 1.1 jmmv ATF_CHECK(ok); 416 1.1 jmmv 417 1.1 jmmv char val[128]; 418 1.1 jmmv ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_val", 419 1.1 jmmv &val, sizeof(val))); 420 1.1 jmmv ATF_CHECK(strcmp(val, "1st string") == 0); 421 1.1 jmmv } 422 1.1 jmmv unload("k_helper", true); 423 1.1 jmmv 424 1.1 jmmv printf("Loading module with a different string property\n"); 425 1.1 jmmv props = prop_dictionary_create(); 426 1.1 jmmv prop_dictionary_set(props, "prop_str", 427 1.1 jmmv prop_string_create_cstring("2nd string")); 428 1.3 jmmv load(props, true, "%s/k_helper/k_helper.kmod", 429 1.3 jmmv atf_tc_get_config_var(tc, "srcdir")); 430 1.1 jmmv prop_object_release(props); 431 1.1 jmmv { 432 1.1 jmmv int ok; 433 1.1 jmmv ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok", 434 1.1 jmmv &ok, sizeof(ok))); 435 1.1 jmmv ATF_CHECK(ok); 436 1.1 jmmv 437 1.1 jmmv char val[128]; 438 1.1 jmmv ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_val", 439 1.1 jmmv &val, sizeof(val))); 440 1.1 jmmv ATF_CHECK(strcmp(val, "2nd string") == 0); 441 1.1 jmmv } 442 1.1 jmmv unload("k_helper", true); 443 1.1 jmmv } 444 1.1 jmmv ATF_TC_CLEANUP(cmd_load_props, tc) 445 1.1 jmmv { 446 1.1 jmmv unload_cleanup("k_helper"); 447 1.1 jmmv } 448 1.1 jmmv 449 1.4 pgoyette ATF_TC_WITH_CLEANUP(cmd_load_recurse); 450 1.4 pgoyette ATF_TC_HEAD(cmd_load_recurse, tc) 451 1.4 pgoyette { 452 1.4 pgoyette atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_LOAD command, " 453 1.4 pgoyette "with recursive module_load()"); 454 1.4 pgoyette atf_tc_set_md_var(tc, "require.user", "root"); 455 1.4 pgoyette } 456 1.4 pgoyette ATF_TC_BODY(cmd_load_recurse, tc) 457 1.4 pgoyette { 458 1.4 pgoyette prop_dictionary_t props; 459 1.4 pgoyette char filename[MAXPATHLEN]; 460 1.4 pgoyette 461 1.4 pgoyette printf("Loading module with request to load another module\n"); 462 1.4 pgoyette props = prop_dictionary_create(); 463 1.4 pgoyette snprintf(filename, sizeof(filename), "%s/k_helper2/k_helper2.kmod", 464 1.4 pgoyette atf_tc_get_config_var(tc, "srcdir")); 465 1.4 pgoyette prop_dictionary_set(props, "prop_recurse", 466 1.4 pgoyette prop_string_create_cstring(filename)); 467 1.4 pgoyette load(props, true, "%s/k_helper/k_helper.kmod", 468 1.4 pgoyette atf_tc_get_config_var(tc, "srcdir")); 469 1.4 pgoyette { 470 1.4 pgoyette int ok; 471 1.4 pgoyette ATF_CHECK(get_sysctl("vendor.k_helper.prop_int_load", 472 1.4 pgoyette &ok, sizeof(ok))); 473 1.4 pgoyette ATF_CHECK(ok == 0); 474 1.4 pgoyette ATF_CHECK(get_sysctl("vendor.k_helper2.present", 475 1.4 pgoyette &ok, sizeof(ok))); 476 1.4 pgoyette ATF_CHECK(ok); 477 1.4 pgoyette } 478 1.4 pgoyette unload("k_helper", true); 479 1.4 pgoyette unload("k_helper2", true); 480 1.4 pgoyette } 481 1.4 pgoyette ATF_TC_CLEANUP(cmd_load_recurse, tc) 482 1.4 pgoyette { 483 1.4 pgoyette unload_cleanup("k_helper"); 484 1.4 pgoyette unload_cleanup("k_helper2"); 485 1.4 pgoyette } 486 1.4 pgoyette 487 1.1 jmmv ATF_TC_WITH_CLEANUP(cmd_stat); 488 1.1 jmmv ATF_TC_HEAD(cmd_stat, tc) 489 1.1 jmmv { 490 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_STAT command"); 491 1.1 jmmv atf_tc_set_md_var(tc, "require.user", "root"); 492 1.1 jmmv } 493 1.1 jmmv ATF_TC_BODY(cmd_stat, tc) 494 1.1 jmmv { 495 1.16 pgoyette ATF_CHECK(!k_helper_is_present(all_checks)); 496 1.1 jmmv 497 1.3 jmmv load(NULL, true, "%s/k_helper/k_helper.kmod", 498 1.3 jmmv atf_tc_get_config_var(tc, "srcdir")); 499 1.16 pgoyette ATF_CHECK(k_helper_is_present(all_checks)); 500 1.1 jmmv { 501 1.1 jmmv modstat_t ms; 502 1.1 jmmv ATF_CHECK(get_modstat_info("k_helper", &ms)); 503 1.1 jmmv 504 1.1 jmmv ATF_CHECK(ms.ms_class == MODULE_CLASS_MISC); 505 1.1 jmmv ATF_CHECK(ms.ms_source == MODULE_SOURCE_FILESYS); 506 1.1 jmmv ATF_CHECK(ms.ms_refcnt == 0); 507 1.1 jmmv } 508 1.1 jmmv unload("k_helper", true); 509 1.1 jmmv 510 1.16 pgoyette ATF_CHECK(!k_helper_is_present(all_checks)); 511 1.1 jmmv } 512 1.1 jmmv ATF_TC_CLEANUP(cmd_stat, tc) 513 1.1 jmmv { 514 1.1 jmmv unload_cleanup("k_helper"); 515 1.1 jmmv } 516 1.1 jmmv 517 1.1 jmmv ATF_TC_WITH_CLEANUP(cmd_unload); 518 1.1 jmmv ATF_TC_HEAD(cmd_unload, tc) 519 1.1 jmmv { 520 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_UNLOAD command"); 521 1.1 jmmv atf_tc_set_md_var(tc, "require.user", "root"); 522 1.1 jmmv } 523 1.1 jmmv ATF_TC_BODY(cmd_unload, tc) 524 1.1 jmmv { 525 1.3 jmmv load(NULL, true, "%s/k_helper/k_helper.kmod", 526 1.3 jmmv atf_tc_get_config_var(tc, "srcdir")); 527 1.1 jmmv 528 1.1 jmmv ATF_CHECK(unload("", false) == ENOENT); 529 1.2 ad ATF_CHECK(unload("non-existent.kmod", false) == ENOENT); 530 1.2 ad ATF_CHECK(unload("k_helper.kmod", false) == ENOENT); 531 1.1 jmmv 532 1.1 jmmv ATF_CHECK(k_helper_is_present(stat_check)); 533 1.1 jmmv unload("k_helper", true); 534 1.1 jmmv printf("Checking if unload was successful\n"); 535 1.1 jmmv ATF_CHECK(!k_helper_is_present(stat_check)); 536 1.1 jmmv } 537 1.1 jmmv ATF_TC_CLEANUP(cmd_unload, tc) 538 1.1 jmmv { 539 1.1 jmmv unload_cleanup("k_helper"); 540 1.1 jmmv } 541 1.1 jmmv 542 1.1 jmmv /* --------------------------------------------------------------------- */ 543 1.1 jmmv /* Main */ 544 1.1 jmmv /* --------------------------------------------------------------------- */ 545 1.1 jmmv 546 1.1 jmmv ATF_TP_ADD_TCS(tp) 547 1.1 jmmv { 548 1.1 jmmv 549 1.1 jmmv ATF_TP_ADD_TC(tp, cmd_load); 550 1.1 jmmv ATF_TP_ADD_TC(tp, cmd_load_props); 551 1.1 jmmv ATF_TP_ADD_TC(tp, cmd_stat); 552 1.4 pgoyette ATF_TP_ADD_TC(tp, cmd_load_recurse); 553 1.1 jmmv ATF_TP_ADD_TC(tp, cmd_unload); 554 1.1 jmmv 555 1.1 jmmv return atf_no_error(); 556 1.1 jmmv } 557