Add tests for load-time parameter passing to modules, both at the syscall

level through modctl(2) and at the user level through the modload(8)
utility.
This commit is contained in:
jmmv 2008-03-02 11:22:10 +00:00
parent 9e8fd365e9
commit 256b5bd1a9
4 changed files with 356 additions and 23 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.1 2008/02/10 12:40:10 jmmv Exp $
# $NetBSD: Makefile,v 1.2 2008/03/02 11:22:10 jmmv Exp $
.include <bsd.own.mk>
@ -12,6 +12,9 @@ TESTSDIR= ${TESTSBASE}/modules
.if ${MKMODULAR} != no
TESTS_CXX= t_modctl
LDADD= -lprop
TESTS_SH= t_modload
SUBDIR= k_helper

View File

@ -1,4 +1,4 @@
/* $NetBSD: k_helper.c,v 1.1 2008/02/10 12:40:10 jmmv Exp $ */
/* $NetBSD: k_helper.c,v 1.2 2008/03/02 11:22:11 jmmv Exp $ */
/*
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
@ -34,24 +34,37 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: k_helper.c,v 1.1 2008/02/10 12:40:10 jmmv Exp $");
__KERNEL_RCSID(0, "$NetBSD: k_helper.c,v 1.2 2008/03/02 11:22:11 jmmv Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/sysctl.h>
#include <prop/proplib.h>
MODULE(MODULE_CLASS_MISC, k_helper, NULL);
/* --------------------------------------------------------------------- */
/* Sysctl interface to query information about the module. */
/* --------------------------------------------------------------------- */
/* TODO: Change the integer variables below that represent booleans to
* bools, once sysctl(8) supports CTLTYPE_BOOL nodes. */
static struct sysctllog *clog;
static int present = 1;
static int prop_str_ok;
static char prop_str_val[128];
static int prop_int_ok;
static int prop_int_val;
#define K_HELPER 0x12345678
#define K_HELPER_PRESENT 0
#define K_HELPER_PROP_STR_OK 1
#define K_HELPER_PROP_STR_VAL 2
#define K_HELPER_PROP_INT_OK 3
#define K_HELPER_PROP_INT_VAL 4
SYSCTL_SETUP(sysctl_k_helper_setup, "sysctl k_helper subtree setup")
{
@ -68,6 +81,34 @@ SYSCTL_SETUP(sysctl_k_helper_setup, "sysctl k_helper subtree setup")
SYSCTL_DESCR("Whether the module was loaded or not"),
NULL, 0, &present, 0,
CTL_VENDOR, K_HELPER, K_HELPER_PRESENT, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_INT, "prop_str_ok",
SYSCTL_DESCR("String property's validity"),
NULL, 0, &prop_str_ok, 0,
CTL_VENDOR, K_HELPER, K_HELPER_PROP_STR_OK, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "prop_str_val",
SYSCTL_DESCR("String property's value"),
NULL, 0, &prop_str_val, 0,
CTL_VENDOR, K_HELPER, K_HELPER_PROP_STR_VAL, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_INT, "prop_int_ok",
SYSCTL_DESCR("String property's validity"),
NULL, 0, &prop_int_ok, 0,
CTL_VENDOR, K_HELPER, K_HELPER_PROP_INT_OK, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_INT, "prop_int_val",
SYSCTL_DESCR("String property's value"),
NULL, 0, &prop_int_val, 0,
CTL_VENDOR, K_HELPER, K_HELPER_PROP_INT_VAL, CTL_EOL);
}
/* --------------------------------------------------------------------- */
@ -76,8 +117,38 @@ SYSCTL_SETUP(sysctl_k_helper_setup, "sysctl k_helper subtree setup")
static
int
k_helper_init(void *arg)
k_helper_init(prop_dictionary_t props)
{
prop_object_t p;
p = prop_dictionary_get(props, "prop_str");
if (p == NULL)
prop_str_ok = 0;
else if (prop_object_type(p) != PROP_TYPE_STRING)
prop_str_ok = 0;
else {
const char *msg = prop_string_cstring_nocopy(p);
if (msg == NULL)
prop_str_ok = 0;
else {
strlcpy(prop_str_val, msg, sizeof(prop_str_val));
prop_str_ok = 1;
}
}
if (!prop_str_ok)
strlcpy(prop_str_val, "", sizeof(prop_str_val));
p = prop_dictionary_get(props, "prop_int");
if (p == NULL)
prop_int_ok = 0;
else if (prop_object_type(p) != PROP_TYPE_NUMBER)
prop_int_ok = 0;
else {
prop_int_val = prop_number_integer_value(p);
prop_int_ok = 1;
}
if (!prop_int_ok)
prop_int_val = -1;
sysctl_k_helper_setup(&clog);

View File

@ -1,4 +1,4 @@
// $NetBSD: t_modctl.cpp,v 1.2 2008/02/10 16:02:24 jmmv Exp $
// $NetBSD: t_modctl.cpp,v 1.3 2008/03/02 11:22:10 jmmv Exp $
//
// Copyright (c) 2008 The NetBSD Foundation, Inc.
// All rights reserved.
@ -35,14 +35,17 @@
extern "C" {
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: t_modctl.cpp,v 1.2 2008/02/10 16:02:24 jmmv Exp $");
__KERNEL_RCSID(0, "$NetBSD: t_modctl.cpp,v 1.3 2008/03/02 11:22:10 jmmv Exp $");
#include <sys/module.h>
#include <sys/sysctl.h>
#include <prop/proplib.h>
}
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <iostream>
@ -135,6 +138,24 @@ get_modstat_info(const char *name, modstat_t *msdest)
return found;
}
/*
* Queries a sysctl property.
*/
static
bool
get_sysctl(const std::string& name, void *buf, const size_t len)
{
size_t len2 = len;
std::cout << "Querying sysctl variable: " << name << std::endl;
int ret = ::sysctlbyname(name.c_str(), buf, &len2, NULL, 0);
if (ret == -1 && errno != ENOENT) {
std::cerr << "sysctlbyname(2) failed: "
<< std::strerror(errno) << std::endl;
ATF_FAIL("Failed to query " + name);
}
return ret != -1;
}
/*
* Returns a boolean indicating if the k_helper module was loaded
* successfully. This implementation uses modctl(2)'s MODCTL_STAT
@ -157,19 +178,10 @@ static
bool
k_helper_is_present_sysctl(void)
{
size_t present, presentsize;
int ret;
size_t present;
presentsize = sizeof(present);
ret = ::sysctlbyname("vendor.k_helper.present", &present,
&presentsize, NULL, 0);
if (ret == -1 && errno != ENOENT) {
int err = errno;
std::cerr << "sysctlbyname(2) failed: " << std::strerror(err)
<< std::endl;
ATF_FAIL("Failed to query module status");
}
return ret == 0;
return get_sysctl("vendor.k_helper.present", &present,
sizeof(present));
}
/*
@ -211,13 +223,31 @@ k_helper_is_present(presence_check how)
*/
static
int
load(const std::string& filename, bool fatal = true)
load(const std::string& filename, prop_dictionary_t props = NULL,
bool fatal = true)
{
int err;
char *propsstr;
modctl_load_t ml;
if (props == NULL) {
props = prop_dictionary_create();
propsstr = prop_dictionary_externalize(props);
ATF_CHECK(propsstr != NULL);
prop_object_release(props);
} else {
propsstr = prop_dictionary_externalize(props);
ATF_CHECK(propsstr != NULL);
}
ml.ml_filename = filename.c_str();
ml.ml_flags = 0;
ml.ml_props = propsstr;
ml.ml_propslen = strlen(propsstr);
std::cout << "Loading module " << filename << std::endl;
err = 0;
if (::modctl(MODCTL_LOAD, __UNCONST(filename.c_str())) == -1) {
if (::modctl(MODCTL_LOAD, &ml) == -1) {
err = errno;
std::cerr << "modctl(MODCTL_LOAD, " << filename
<< ") failed: " << std::strerror(err)
@ -225,6 +255,9 @@ load(const std::string& filename, bool fatal = true)
if (fatal)
ATF_FAIL("Module load failed");
}
::free(propsstr);
return err;
}
@ -277,11 +310,11 @@ ATF_TEST_CASE_BODY(cmd_load)
{
require_modular();
ATF_CHECK(load("", false) == ENOENT);
ATF_CHECK(load("non-existent.o", false) == ENOENT);
ATF_CHECK(load("", NULL, false) == ENOENT);
ATF_CHECK(load("non-existent.o", NULL, false) == ENOENT);
std::string longname(MAXPATHLEN, 'a');
ATF_CHECK(load(longname.c_str(), false) == ENAMETOOLONG);
ATF_CHECK(load(longname.c_str(), NULL, false) == ENAMETOOLONG);
ATF_CHECK(!k_helper_is_present(stat_check));
load(get_srcdir() + "/k_helper.o");
@ -293,6 +326,75 @@ ATF_TEST_CASE_CLEANUP(cmd_load)
unload_cleanup("k_helper");
}
ATF_TEST_CASE_WITH_CLEANUP(cmd_load_props);
ATF_TEST_CASE_HEAD(cmd_load_props)
{
set("descr", "Tests for the MODCTL_LOAD command, providing extra "
"load-time properties");
set("require.user", "root");
}
ATF_TEST_CASE_BODY(cmd_load_props)
{
prop_dictionary_t props;
require_modular();
std::cout << "Loading module without properties" << std::endl;
props = prop_dictionary_create();
load(get_srcdir() + "/k_helper.o", props);
prop_object_release(props);
{
int ok;
ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok",
&ok, sizeof(ok)));
ATF_CHECK(!ok);
}
unload("k_helper");
std::cout << "Loading module with a string property" << std::endl;
props = prop_dictionary_create();
prop_dictionary_set(props, "prop_str",
prop_string_create_cstring("1st string"));
load(get_srcdir() + "/k_helper.o", props);
prop_object_release(props);
{
int ok;
ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok",
&ok, sizeof(ok)));
ATF_CHECK(ok);
char val[128];
ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_val",
&val, sizeof(val)));
ATF_CHECK(std::strcmp(val, "1st string") == 0);
}
unload("k_helper");
std::cout << "Loading module with a different string property"
<< std::endl;
props = prop_dictionary_create();
prop_dictionary_set(props, "prop_str",
prop_string_create_cstring("2nd string"));
load(get_srcdir() + "/k_helper.o", props);
prop_object_release(props);
{
int ok;
ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok",
&ok, sizeof(ok)));
ATF_CHECK(ok);
char val[128];
ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_val",
&val, sizeof(val)));
ATF_CHECK(std::strcmp(val, "2nd string") == 0);
}
unload("k_helper");
}
ATF_TEST_CASE_CLEANUP(cmd_load_props)
{
unload_cleanup("k_helper");
}
ATF_TEST_CASE_WITH_CLEANUP(cmd_stat);
ATF_TEST_CASE_HEAD(cmd_stat)
{
@ -359,6 +461,7 @@ ATF_INIT_TEST_CASES(tcs)
have_modular = check_modular();
ATF_ADD_TEST_CASE(tcs, cmd_load);
ATF_ADD_TEST_CASE(tcs, cmd_load_props);
ATF_ADD_TEST_CASE(tcs, cmd_stat);
ATF_ADD_TEST_CASE(tcs, cmd_unload);
}

156
tests/modules/t_modload.sh Normal file
View File

@ -0,0 +1,156 @@
# $NetBSD: t_modload.sh,v 1.1 2008/03/02 11:22:10 jmmv Exp $
#
# Copyright (c) 2008 The NetBSD Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# This product includes software developed by the NetBSD
# Foundation, Inc. and its contributors.
# 4. Neither the name of The NetBSD Foundation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
check_sysctl() {
echo "${1} = ${2}" >expout
atf_check "sysctl ${1}" 0 expout null
}
atf_test_case plain
plain_head() {
atf_set "descr" "Test load without arguments"
atf_set "require.user" "root"
}
plain_body() {
cat >experr <<EOF
modload: No such file or directory
EOF
atf_check "modload non-existent.o" 1 null experr
atf_check "modload $(atf_get_srcdir)/k_helper.o" 0 null null
check_sysctl vendor.k_helper.present 1
check_sysctl vendor.k_helper.prop_int_ok 0
check_sysctl vendor.k_helper.prop_str_ok 0
atf_check "modunload k_helper" 0 null null
}
plain_cleanup() {
modunload k_helper >/dev/null 2>&1
}
atf_test_case bflag
bflag_head() {
atf_set "descr" "Test the -b flag"
atf_set "require.user" "root"
}
bflag_body() {
echo "Checking error conditions"
atf_check "modload -b foo k_helper.o" 1 null stderr
atf_check "grep 'Invalid parameter.*foo' stderr" 0 ignore null
atf_check "modload -b foo= k_helper.o" 1 null stderr
atf_check "grep 'Invalid boolean value' stderr" 0 ignore null
atf_check "modload -b foo=bar k_helper.o" 1 null stderr
atf_check "grep 'Invalid boolean value.*bar' stderr" 0 ignore null
atf_check "modload -b foo=falsea k_helper.o" 1 null stderr
atf_check "grep 'Invalid boolean value.*falsea' stderr" 0 ignore null
atf_check "modload -b foo=truea k_helper.o" 1 null stderr
atf_check "grep 'Invalid boolean value.*truea' stderr" 0 ignore null
# TODO Once sysctl(8) supports CTLTYPE_BOOL nodes.
#echo "Checking valid values"
}
bflag_cleanup() {
modunload k_helper >/dev/null 2>&1
}
atf_test_case iflag
iflag_head() {
atf_set "descr" "Test the -i flag"
atf_set "require.user" "root"
}
iflag_body() {
echo "Checking error conditions"
atf_check "modload -i foo k_helper.o" 1 null stderr
atf_check "grep 'Invalid parameter.*foo' stderr" 0 ignore null
atf_check "modload -i foo= k_helper.o" 1 null stderr
atf_check "grep 'Invalid integer value' stderr" 0 ignore null
atf_check "modload -i foo=bar k_helper.o" 1 null stderr
atf_check "grep 'Invalid integer value.*bar' stderr" 0 ignore null
atf_check "modload -i foo=123a k_helper.o" 1 null stderr
atf_check "grep 'Invalid integer value.*123a' stderr" 0 ignore null
echo "Checking valid values"
for v in 5 10; do
atf_check "modload -i prop_int='${v}' \
$(atf_get_srcdir)/k_helper.o" 0 null null
check_sysctl vendor.k_helper.prop_int_ok 1
check_sysctl vendor.k_helper.prop_int_val "${v}"
atf_check "modunload k_helper" 0 null null
done
}
iflag_cleanup() {
modunload k_helper >/dev/null 2>&1
}
atf_test_case sflag
sflag_head() {
atf_set "descr" "Test the -s flag"
atf_set "require.user" "root"
}
sflag_body() {
echo "Checking error conditions"
atf_check "modload -s foo k_helper.o" 1 null stderr
atf_check "grep 'Invalid parameter.*foo' stderr" 0 ignore null
echo "Checking valid values"
for v in '1st string' '2nd string'; do
atf_check "modload -s prop_str='${v}' \
$(atf_get_srcdir)/k_helper.o" 0 null null
check_sysctl vendor.k_helper.prop_str_ok 1
check_sysctl vendor.k_helper.prop_str_val "${v}"
atf_check "modunload k_helper" 0 null null
done
}
sflag_cleanup() {
modunload k_helper >/dev/null 2>&1
}
atf_init_test_cases()
{
atf_add_test_case plain
atf_add_test_case bflag
atf_add_test_case iflag
atf_add_test_case sflag
}