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