[BACK]Return to t_modctl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / tests / modules

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>