[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

1.2     ! ad          1: /*     $NetBSD: t_modctl.c,v 1.1 2008/05/01 15:38:17 jmmv Exp $        */
1.1       jmmv        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>
1.2     ! ad         30: __KERNEL_RCSID(0, "$NetBSD: t_modctl.c,v 1.1 2008/05/01 15:38:17 jmmv Exp $");
1.1       jmmv       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));
1.2     ! ad        319:        load(NULL, true, "%s/k_helper.kmod", atf_tc_get_config_var(tc, "srcdir"));
1.1       jmmv      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();
1.2     ! ad        343:        load(props, true, "%s/k_helper.kmod", atf_tc_get_config_var(tc, "srcdir"));
1.1       jmmv      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"));
1.2     ! ad        357:        load(props, true, "%s/k_helper.kmod", atf_tc_get_config_var(tc, "srcdir"));
1.1       jmmv      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"));
1.2     ! ad        376:        load(props, true, "%s/k_helper.kmod", atf_tc_get_config_var(tc, "srcdir"));
1.1       jmmv      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:
1.2     ! ad        408:        load(NULL, true, "%s/k_helper.kmod", atf_tc_get_config_var(tc, "srcdir"));
1.1       jmmv      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:
1.2     ! ad        437:        load(NULL, true, "%s/k_helper.kmod", atf_tc_get_config_var(tc, "srcdir"));
1.1       jmmv      438:
                    439:        ATF_CHECK(unload("", false) == ENOENT);
1.2     ! ad        440:        ATF_CHECK(unload("non-existent.kmod", false) == ENOENT);
        !           441:        ATF_CHECK(unload("k_helper.kmod", false) == ENOENT);
1.1       jmmv      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>