xref: /netbsd-src/tests/modules/t_modctl.c (revision ea561c44e388b72b28993fcd5c85273bdf06a581)
1*ea561c44Spgoyette /*	$NetBSD: t_modctl.c,v 1.16 2020/02/22 19:54:34 pgoyette Exp $	*/
25a560143Sjmmv /*
35a560143Sjmmv  * Copyright (c) 2008 The NetBSD Foundation, Inc.
45a560143Sjmmv  * All rights reserved.
55a560143Sjmmv  *
65a560143Sjmmv  * Redistribution and use in source and binary forms, with or without
75a560143Sjmmv  * modification, are permitted provided that the following conditions
85a560143Sjmmv  * are met:
95a560143Sjmmv  * 1. Redistributions of source code must retain the above copyright
105a560143Sjmmv  *    notice, this list of conditions and the following disclaimer.
115a560143Sjmmv  * 2. Redistributions in binary form must reproduce the above copyright
125a560143Sjmmv  *    notice, this list of conditions and the following disclaimer in the
135a560143Sjmmv  *    documentation and/or other materials provided with the distribution.
145a560143Sjmmv  *
155a560143Sjmmv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
165a560143Sjmmv  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
175a560143Sjmmv  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185a560143Sjmmv  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
195a560143Sjmmv  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
205a560143Sjmmv  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215a560143Sjmmv  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
225a560143Sjmmv  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
235a560143Sjmmv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
245a560143Sjmmv  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
255a560143Sjmmv  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
265a560143Sjmmv  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275a560143Sjmmv  */
285a560143Sjmmv 
295a560143Sjmmv #include <sys/cdefs.h>
30*ea561c44Spgoyette __KERNEL_RCSID(0, "$NetBSD: t_modctl.c,v 1.16 2020/02/22 19:54:34 pgoyette Exp $");
315a560143Sjmmv 
325a560143Sjmmv #include <sys/module.h>
335a560143Sjmmv #include <sys/sysctl.h>
345a560143Sjmmv 
355a560143Sjmmv #include <assert.h>
365a560143Sjmmv #include <errno.h>
375a560143Sjmmv #include <stdarg.h>
385a560143Sjmmv #include <stdbool.h>
395a560143Sjmmv #include <stdio.h>
405a560143Sjmmv #include <stdlib.h>
415a560143Sjmmv #include <string.h>
42*ea561c44Spgoyette #include <sys/evcnt.h>
435a560143Sjmmv 
445a560143Sjmmv #include <prop/proplib.h>
455a560143Sjmmv 
465a560143Sjmmv #include <atf-c.h>
475a560143Sjmmv 
48*ea561c44Spgoyette enum presence_check { all_checks, stat_check, sysctl_check, evcnt_check };
495a560143Sjmmv 
5066c66d2dSmartin static void	check_permission(void);
5196d2b606Sjruoho static bool	get_modstat_info(const char *, modstat_t *);
5296d2b606Sjruoho static bool	get_sysctl(const char *, void *buf, const size_t);
5396d2b606Sjruoho static bool	k_helper_is_present_stat(void);
5496d2b606Sjruoho static bool	k_helper_is_present_sysctl(void);
55*ea561c44Spgoyette static bool	k_helper_is_present_evcnt(void);
5696d2b606Sjruoho static bool	k_helper_is_present(enum presence_check);
5796d2b606Sjruoho static int	load(prop_dictionary_t, bool, const char *, ...);
5896d2b606Sjruoho static int	unload(const char *, bool);
5996d2b606Sjruoho static void	unload_cleanup(const char *);
6096d2b606Sjruoho 
615a560143Sjmmv /* --------------------------------------------------------------------- */
625a560143Sjmmv /* Auxiliary functions                                                   */
635a560143Sjmmv /* --------------------------------------------------------------------- */
645a560143Sjmmv 
655a560143Sjmmv /*
66f93d6526Smaya  * A function checking whether we are allowed to load modules currently
6766c66d2dSmartin  * (either the kernel is not modular, or securelevel may prevent it)
685a560143Sjmmv  */
6966c66d2dSmartin static void
check_permission(void)7066c66d2dSmartin check_permission(void)
715a560143Sjmmv {
7266c66d2dSmartin 	int err;
7366c66d2dSmartin 
7466c66d2dSmartin 	err = modctl(MODCTL_EXISTS, 0);
75d0ba1a06Smartin 	if (err == 0) return;
76d0ba1a06Smartin 	if (errno == ENOSYS)
775a560143Sjmmv 		atf_tc_skip("Kernel does not have 'options MODULAR'.");
78d0ba1a06Smartin 	else if (errno == EPERM)
7966c66d2dSmartin 		atf_tc_skip("Module loading administratively forbidden");
80d0ba1a06Smartin 	ATF_REQUIRE_EQ_MSG(errno, 0, "unexpected error %d from "
81d0ba1a06Smartin 	    "modctl(MODCTL_EXISTS, 0)", errno);
825a560143Sjmmv }
835a560143Sjmmv 
8496d2b606Sjruoho static bool
get_modstat_info(const char * name,modstat_t * msdest)855a560143Sjmmv get_modstat_info(const char *name, modstat_t *msdest)
865a560143Sjmmv {
875a560143Sjmmv 	bool found;
885a560143Sjmmv 	size_t len;
89d91f98a8Spgoyette 	int count;
905a560143Sjmmv 	struct iovec iov;
915a560143Sjmmv 	modstat_t *ms;
9293226e2fSkamil 	modstat_t m;
935a560143Sjmmv 
9466c66d2dSmartin 	check_permission();
95d91f98a8Spgoyette 	for (len = 8192; ;) {
965a560143Sjmmv 		iov.iov_base = malloc(len);
975a560143Sjmmv 		iov.iov_len = len;
9896d2b606Sjruoho 
9996d2b606Sjruoho 		errno = 0;
10096d2b606Sjruoho 
1015a560143Sjmmv 		if (modctl(MODCTL_STAT, &iov) != 0) {
1025a560143Sjmmv 			int err = errno;
1035a560143Sjmmv 			fprintf(stderr, "modctl(MODCTL_STAT) failed: %s\n",
1045a560143Sjmmv 			    strerror(err));
1055a560143Sjmmv 			atf_tc_fail("Failed to query module status");
1065a560143Sjmmv 		}
1075a560143Sjmmv 		if (len >= iov.iov_len)
1085a560143Sjmmv 			break;
1095a560143Sjmmv 		free(iov.iov_base);
1105a560143Sjmmv 		len = iov.iov_len;
1115a560143Sjmmv 	}
1125a560143Sjmmv 
1135a560143Sjmmv 	found = false;
114d91f98a8Spgoyette 	count = *(int *)iov.iov_base;
115d91f98a8Spgoyette 	ms = (modstat_t *)((char *)iov.iov_base + sizeof(int));
116d91f98a8Spgoyette 	while ( count ) {
11793226e2fSkamil 		memcpy(&m, ms, sizeof(m));
11893226e2fSkamil 		if (strcmp(m.ms_name, name) == 0) {
1195a560143Sjmmv 			if (msdest != NULL)
12093226e2fSkamil 				memcpy(msdest, &m, sizeof(*msdest));
1215a560143Sjmmv 			found = true;
122d91f98a8Spgoyette 			break;
1235a560143Sjmmv 		}
124d91f98a8Spgoyette 		ms++;
125d91f98a8Spgoyette 		count--;
1265a560143Sjmmv 	}
1275a560143Sjmmv 
1285a560143Sjmmv 	free(iov.iov_base);
1295a560143Sjmmv 
1305a560143Sjmmv 	return found;
1315a560143Sjmmv }
1325a560143Sjmmv 
1335a560143Sjmmv /*
1345a560143Sjmmv  * Queries a sysctl property.
1355a560143Sjmmv  */
13696d2b606Sjruoho static bool
get_sysctl(const char * name,void * buf,const size_t len)1375a560143Sjmmv get_sysctl(const char *name, void *buf, const size_t len)
1385a560143Sjmmv {
1395a560143Sjmmv 	size_t len2 = len;
1405a560143Sjmmv 	printf("Querying sysctl variable: %s\n", name);
1415a560143Sjmmv 	int ret = sysctlbyname(name, buf, &len2, NULL, 0);
1425a560143Sjmmv 	if (ret == -1 && errno != ENOENT) {
1435a560143Sjmmv 		fprintf(stderr, "sysctlbyname(2) failed: %s\n",
1445a560143Sjmmv 		    strerror(errno));
1455a560143Sjmmv 		atf_tc_fail("Failed to query %s", name);
1465a560143Sjmmv 	}
1475a560143Sjmmv 	return ret != -1;
1485a560143Sjmmv }
1495a560143Sjmmv 
1505a560143Sjmmv /*
1515a560143Sjmmv  * Returns a boolean indicating if the k_helper module was loaded
1525a560143Sjmmv  * successfully.  This implementation uses modctl(2)'s MODCTL_STAT
1535a560143Sjmmv  * subcommand to do the check.
1545a560143Sjmmv  */
15596d2b606Sjruoho static bool
k_helper_is_present_stat(void)1565a560143Sjmmv k_helper_is_present_stat(void)
1575a560143Sjmmv {
1585a560143Sjmmv 
1595a560143Sjmmv 	return get_modstat_info("k_helper", NULL);
1605a560143Sjmmv }
1615a560143Sjmmv 
1625a560143Sjmmv /*
1635a560143Sjmmv  * Returns a boolean indicating if the k_helper module was loaded
1645a560143Sjmmv  * successfully.  This implementation uses the module's sysctl
1655a560143Sjmmv  * installed node to do the check.
1665a560143Sjmmv  */
16796d2b606Sjruoho static bool
k_helper_is_present_sysctl(void)1685a560143Sjmmv k_helper_is_present_sysctl(void)
1695a560143Sjmmv {
1705a560143Sjmmv 	size_t present;
1715a560143Sjmmv 
1725a560143Sjmmv 	return get_sysctl("vendor.k_helper.present", &present,
1735a560143Sjmmv 	    sizeof(present));
1745a560143Sjmmv }
1755a560143Sjmmv 
1765a560143Sjmmv /*
1775a560143Sjmmv  * Returns a boolean indicating if the k_helper module was loaded
178*ea561c44Spgoyette  * successfully.  This implementation uses the module's evcnt
179*ea561c44Spgoyette  * to do the check.
180*ea561c44Spgoyette  */
181*ea561c44Spgoyette static bool
k_helper_is_present_evcnt(void)182*ea561c44Spgoyette k_helper_is_present_evcnt(void)
183*ea561c44Spgoyette {
184*ea561c44Spgoyette 	const int mib[4] = {CTL_KERN, KERN_EVCNT, EVCNT_TYPE_ANY,
185*ea561c44Spgoyette 	    KERN_EVCNT_COUNT_ANY };
186*ea561c44Spgoyette 	int error;
187*ea561c44Spgoyette 	size_t newlen, buflen = 0;
188*ea561c44Spgoyette 	void *buf0, *buf = NULL;
189*ea561c44Spgoyette 	const struct evcnt_sysctl *evs, *last_evs;
190*ea561c44Spgoyette 
191*ea561c44Spgoyette 	for (;;) {
192*ea561c44Spgoyette 		if (buflen)
193*ea561c44Spgoyette 			buf = malloc(buflen);
194*ea561c44Spgoyette 		error = sysctl(mib, __arraycount(mib), buf, &newlen, NULL, 0);
195*ea561c44Spgoyette 		if (error) {
196*ea561c44Spgoyette 			if (buf)
197*ea561c44Spgoyette 				free(buf);
198*ea561c44Spgoyette 			return false;
199*ea561c44Spgoyette 		}
200*ea561c44Spgoyette 		if (newlen <= buflen) {
201*ea561c44Spgoyette 			buflen = newlen;
202*ea561c44Spgoyette 			break;
203*ea561c44Spgoyette 		}
204*ea561c44Spgoyette 		if (buf)
205*ea561c44Spgoyette 			free(buf);
206*ea561c44Spgoyette 		buflen = newlen;
207*ea561c44Spgoyette 	}
208*ea561c44Spgoyette 	evs = buf0 = buf;
209*ea561c44Spgoyette 	last_evs = (void *)((char *)buf + buflen);
210*ea561c44Spgoyette 	buflen /= sizeof(uint64_t);
211*ea561c44Spgoyette 	while (evs < last_evs
212*ea561c44Spgoyette 	    && buflen >= sizeof(*evs)/sizeof(uint64_t)
213*ea561c44Spgoyette 	    && buflen >= evs->ev_len) {
214*ea561c44Spgoyette 		if ( strncmp(evs->ev_strings, "k_helper", evs->ev_grouplen)
215*ea561c44Spgoyette 		    == 0) {
216*ea561c44Spgoyette 			free(buf);
217*ea561c44Spgoyette 			return true;
218*ea561c44Spgoyette 		}
219*ea561c44Spgoyette 		buflen -= evs->ev_len;
220*ea561c44Spgoyette 		evs = (const void *)((const uint64_t *)evs + evs->ev_len);
221*ea561c44Spgoyette 	}
222*ea561c44Spgoyette 	free(buf);
223*ea561c44Spgoyette 	return false;
224*ea561c44Spgoyette }
225*ea561c44Spgoyette 
226*ea561c44Spgoyette /*
227*ea561c44Spgoyette  * Returns a boolean indicating if the k_helper module was loaded
2285a560143Sjmmv  * successfully.  The 'how' parameter specifies the implementation to
2295a560143Sjmmv  * use to do the check.
2305a560143Sjmmv  */
23196d2b606Sjruoho static bool
k_helper_is_present(enum presence_check how)2325a560143Sjmmv k_helper_is_present(enum presence_check how)
2335a560143Sjmmv {
2345a560143Sjmmv 	bool found;
2355a560143Sjmmv 
2365a560143Sjmmv 	switch (how) {
237*ea561c44Spgoyette 	case all_checks:
2385a560143Sjmmv 		found = k_helper_is_present_stat();
2395a560143Sjmmv 		ATF_CHECK(k_helper_is_present_sysctl() == found);
240*ea561c44Spgoyette 		ATF_CHECK(k_helper_is_present_evcnt() == found);
2415a560143Sjmmv 		break;
2425a560143Sjmmv 
2435a560143Sjmmv 	case stat_check:
2445a560143Sjmmv 		found = k_helper_is_present_stat();
2455a560143Sjmmv 		break;
2465a560143Sjmmv 
2475a560143Sjmmv 	case sysctl_check:
2485a560143Sjmmv 		found = k_helper_is_present_sysctl();
2495a560143Sjmmv 		break;
2505a560143Sjmmv 
251*ea561c44Spgoyette 	case evcnt_check:
252*ea561c44Spgoyette 		found = k_helper_is_present_evcnt();
253*ea561c44Spgoyette 		break;
254*ea561c44Spgoyette 
2555a560143Sjmmv 	default:
2560f10aa9dSchristos 		found = false;
2570f10aa9dSchristos 		assert(found);
2585a560143Sjmmv 	}
2595a560143Sjmmv 
2605a560143Sjmmv 	return found;
2615a560143Sjmmv }
2625a560143Sjmmv 
2635a560143Sjmmv /*
2645a560143Sjmmv  * Loads the specified module from a file.  If fatal is set and an error
2655a560143Sjmmv  * occurs when loading the module, an error message is printed and the
2665a560143Sjmmv  * test case is aborted.
2675a560143Sjmmv  */
26866dd2755Sjoerg static __printflike(3, 4) int
load(prop_dictionary_t props,bool fatal,const char * fmt,...)2695a560143Sjmmv load(prop_dictionary_t props, bool fatal, const char *fmt, ...)
2705a560143Sjmmv {
2715a560143Sjmmv 	int err;
2725a560143Sjmmv 	va_list ap;
2735a560143Sjmmv 	char filename[MAXPATHLEN], *propsstr;
2745a560143Sjmmv 	modctl_load_t ml;
2755a560143Sjmmv 
27666c66d2dSmartin 	check_permission();
2775a560143Sjmmv 	if (props == NULL) {
2785a560143Sjmmv 		props = prop_dictionary_create();
2795a560143Sjmmv 		propsstr = prop_dictionary_externalize(props);
2805a560143Sjmmv 		ATF_CHECK(propsstr != NULL);
2815a560143Sjmmv 		prop_object_release(props);
2825a560143Sjmmv 	} else {
2835a560143Sjmmv 		propsstr = prop_dictionary_externalize(props);
2845a560143Sjmmv 		ATF_CHECK(propsstr != NULL);
2855a560143Sjmmv 	}
2865a560143Sjmmv 
2875a560143Sjmmv 	va_start(ap, fmt);
2885a560143Sjmmv 	vsnprintf(filename, sizeof(filename), fmt, ap);
2895a560143Sjmmv 	va_end(ap);
2905a560143Sjmmv 
2915a560143Sjmmv 	ml.ml_filename = filename;
2925a560143Sjmmv 	ml.ml_flags = 0;
2935a560143Sjmmv 	ml.ml_props = propsstr;
2945a560143Sjmmv 	ml.ml_propslen = strlen(propsstr);
2955a560143Sjmmv 
2965a560143Sjmmv 	printf("Loading module %s\n", filename);
29796d2b606Sjruoho 	errno = err = 0;
29896d2b606Sjruoho 
2995a560143Sjmmv 	if (modctl(MODCTL_LOAD, &ml) == -1) {
3005a560143Sjmmv 		err = errno;
3015a560143Sjmmv 		fprintf(stderr, "modctl(MODCTL_LOAD, %s), failed: %s\n",
3025a560143Sjmmv 		    filename, strerror(err));
3035a560143Sjmmv 		if (fatal)
3045a560143Sjmmv 			atf_tc_fail("Module load failed");
3055a560143Sjmmv 	}
3065a560143Sjmmv 
3075a560143Sjmmv 	free(propsstr);
3085a560143Sjmmv 
3095a560143Sjmmv 	return err;
3105a560143Sjmmv }
3115a560143Sjmmv 
3125a560143Sjmmv /*
3135a560143Sjmmv  * Unloads the specified module.  If silent is true, nothing will be
3145a560143Sjmmv  * printed and no errors will be raised if the unload was unsuccessful.
3155a560143Sjmmv  */
31696d2b606Sjruoho static int
unload(const char * name,bool fatal)3175a560143Sjmmv unload(const char *name, bool fatal)
3185a560143Sjmmv {
3195a560143Sjmmv 	int err;
3205a560143Sjmmv 
32166c66d2dSmartin 	check_permission();
3225a560143Sjmmv 	printf("Unloading module %s\n", name);
32396d2b606Sjruoho 	errno = err = 0;
32496d2b606Sjruoho 
3255a560143Sjmmv 	if (modctl(MODCTL_UNLOAD, __UNCONST(name)) == -1) {
3265a560143Sjmmv 		err = errno;
3275a560143Sjmmv 		fprintf(stderr, "modctl(MODCTL_UNLOAD, %s) failed: %s\n",
3285a560143Sjmmv 		    name, strerror(err));
3295a560143Sjmmv 		if (fatal)
3305a560143Sjmmv 			atf_tc_fail("Module unload failed");
3315a560143Sjmmv 	}
3325a560143Sjmmv 	return err;
3335a560143Sjmmv }
3345a560143Sjmmv 
3355a560143Sjmmv /*
3365a560143Sjmmv  * A silent version of unload, to be called as part of the cleanup
3375a560143Sjmmv  * process only.
3385a560143Sjmmv  */
33996d2b606Sjruoho static void
unload_cleanup(const char * name)3405a560143Sjmmv unload_cleanup(const char *name)
3415a560143Sjmmv {
3425a560143Sjmmv 
3435a560143Sjmmv 	(void)modctl(MODCTL_UNLOAD, __UNCONST(name));
3445a560143Sjmmv }
3455a560143Sjmmv 
3465a560143Sjmmv /* --------------------------------------------------------------------- */
3475a560143Sjmmv /* Test cases                                                            */
3485a560143Sjmmv /* --------------------------------------------------------------------- */
3495a560143Sjmmv 
3505a560143Sjmmv ATF_TC_WITH_CLEANUP(cmd_load);
ATF_TC_HEAD(cmd_load,tc)3515a560143Sjmmv ATF_TC_HEAD(cmd_load, tc)
3525a560143Sjmmv {
3535a560143Sjmmv 	atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_LOAD command");
3545a560143Sjmmv 	atf_tc_set_md_var(tc, "require.user", "root");
3555a560143Sjmmv }
ATF_TC_BODY(cmd_load,tc)3565a560143Sjmmv ATF_TC_BODY(cmd_load, tc)
3575a560143Sjmmv {
3585a560143Sjmmv 	char longname[MAXPATHLEN];
3595a560143Sjmmv 	size_t i;
3605a560143Sjmmv 
3615a560143Sjmmv 	ATF_CHECK(load(NULL, false, " ") == ENOENT);
3625a560143Sjmmv 	ATF_CHECK(load(NULL, false, "non-existent.o") == ENOENT);
3635a560143Sjmmv 
3645a560143Sjmmv 	for (i = 0; i < MAXPATHLEN - 1; i++)
3655a560143Sjmmv 		longname[i] = 'a';
3665a560143Sjmmv 	longname[MAXPATHLEN - 1] = '\0';
36766dd2755Sjoerg 	ATF_CHECK(load(NULL, false, "%s", longname) == ENAMETOOLONG);
3685a560143Sjmmv 
3695a560143Sjmmv 	ATF_CHECK(!k_helper_is_present(stat_check));
3706725d3eeSjmmv 	load(NULL, true, "%s/k_helper/k_helper.kmod",
3716725d3eeSjmmv 	    atf_tc_get_config_var(tc, "srcdir"));
3725a560143Sjmmv 	printf("Checking if load was successful\n");
3735a560143Sjmmv 	ATF_CHECK(k_helper_is_present(stat_check));
3745a560143Sjmmv }
ATF_TC_CLEANUP(cmd_load,tc)3755a560143Sjmmv ATF_TC_CLEANUP(cmd_load, tc)
3765a560143Sjmmv {
3775a560143Sjmmv 	unload_cleanup("k_helper");
3785a560143Sjmmv }
3795a560143Sjmmv 
3805a560143Sjmmv ATF_TC_WITH_CLEANUP(cmd_load_props);
ATF_TC_HEAD(cmd_load_props,tc)3815a560143Sjmmv ATF_TC_HEAD(cmd_load_props, tc)
3825a560143Sjmmv {
3835a560143Sjmmv 	atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_LOAD command, "
3845a560143Sjmmv 	    "providing extra load-time properties");
3855a560143Sjmmv 	atf_tc_set_md_var(tc, "require.user", "root");
3865a560143Sjmmv }
ATF_TC_BODY(cmd_load_props,tc)3875a560143Sjmmv ATF_TC_BODY(cmd_load_props, tc)
3885a560143Sjmmv {
3895a560143Sjmmv 	prop_dictionary_t props;
3905a560143Sjmmv 
3915a560143Sjmmv 	printf("Loading module without properties\n");
3925a560143Sjmmv 	props = prop_dictionary_create();
3936725d3eeSjmmv 	load(props, true, "%s/k_helper/k_helper.kmod",
3946725d3eeSjmmv 	    atf_tc_get_config_var(tc, "srcdir"));
3955a560143Sjmmv 	prop_object_release(props);
3965a560143Sjmmv 	{
3975a560143Sjmmv 		int ok;
3985a560143Sjmmv 		ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok",
3995a560143Sjmmv 		    &ok, sizeof(ok)));
4005a560143Sjmmv 		ATF_CHECK(!ok);
4015a560143Sjmmv 	}
4025a560143Sjmmv 	unload("k_helper", true);
4035a560143Sjmmv 
4045a560143Sjmmv 	printf("Loading module with a string property\n");
4055a560143Sjmmv 	props = prop_dictionary_create();
4065a560143Sjmmv 	prop_dictionary_set(props, "prop_str",
4075a560143Sjmmv 	    prop_string_create_cstring("1st string"));
4086725d3eeSjmmv 	load(props, true, "%s/k_helper/k_helper.kmod",
4096725d3eeSjmmv 	    atf_tc_get_config_var(tc, "srcdir"));
4105a560143Sjmmv 	prop_object_release(props);
4115a560143Sjmmv 	{
4125a560143Sjmmv 		int ok;
4135a560143Sjmmv 		ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok",
4145a560143Sjmmv 		    &ok, sizeof(ok)));
4155a560143Sjmmv 		ATF_CHECK(ok);
4165a560143Sjmmv 
4175a560143Sjmmv 		char val[128];
4185a560143Sjmmv 		ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_val",
4195a560143Sjmmv 		    &val, sizeof(val)));
4205a560143Sjmmv 		ATF_CHECK(strcmp(val, "1st string") == 0);
4215a560143Sjmmv 	}
4225a560143Sjmmv 	unload("k_helper", true);
4235a560143Sjmmv 
4245a560143Sjmmv 	printf("Loading module with a different string property\n");
4255a560143Sjmmv 	props = prop_dictionary_create();
4265a560143Sjmmv 	prop_dictionary_set(props, "prop_str",
4275a560143Sjmmv 	    prop_string_create_cstring("2nd string"));
4286725d3eeSjmmv 	load(props, true, "%s/k_helper/k_helper.kmod",
4296725d3eeSjmmv 	    atf_tc_get_config_var(tc, "srcdir"));
4305a560143Sjmmv 	prop_object_release(props);
4315a560143Sjmmv 	{
4325a560143Sjmmv 		int ok;
4335a560143Sjmmv 		ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_ok",
4345a560143Sjmmv 		    &ok, sizeof(ok)));
4355a560143Sjmmv 		ATF_CHECK(ok);
4365a560143Sjmmv 
4375a560143Sjmmv 		char val[128];
4385a560143Sjmmv 		ATF_CHECK(get_sysctl("vendor.k_helper.prop_str_val",
4395a560143Sjmmv 		    &val, sizeof(val)));
4405a560143Sjmmv 		ATF_CHECK(strcmp(val, "2nd string") == 0);
4415a560143Sjmmv 	}
4425a560143Sjmmv 	unload("k_helper", true);
4435a560143Sjmmv }
ATF_TC_CLEANUP(cmd_load_props,tc)4445a560143Sjmmv ATF_TC_CLEANUP(cmd_load_props, tc)
4455a560143Sjmmv {
4465a560143Sjmmv 	unload_cleanup("k_helper");
4475a560143Sjmmv }
4485a560143Sjmmv 
44960bf661bSpgoyette ATF_TC_WITH_CLEANUP(cmd_load_recurse);
ATF_TC_HEAD(cmd_load_recurse,tc)45060bf661bSpgoyette ATF_TC_HEAD(cmd_load_recurse, tc)
45160bf661bSpgoyette {
45260bf661bSpgoyette 	atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_LOAD command, "
45360bf661bSpgoyette 	    "with recursive module_load()");
45460bf661bSpgoyette 	atf_tc_set_md_var(tc, "require.user", "root");
45560bf661bSpgoyette }
ATF_TC_BODY(cmd_load_recurse,tc)45660bf661bSpgoyette ATF_TC_BODY(cmd_load_recurse, tc)
45760bf661bSpgoyette {
45860bf661bSpgoyette 	prop_dictionary_t props;
45960bf661bSpgoyette 	char filename[MAXPATHLEN];
46060bf661bSpgoyette 
46160bf661bSpgoyette 	printf("Loading module with request to load another module\n");
46260bf661bSpgoyette 	props = prop_dictionary_create();
46360bf661bSpgoyette 	snprintf(filename, sizeof(filename), "%s/k_helper2/k_helper2.kmod",
46460bf661bSpgoyette 	    atf_tc_get_config_var(tc, "srcdir"));
46560bf661bSpgoyette 	prop_dictionary_set(props, "prop_recurse",
46660bf661bSpgoyette 	    prop_string_create_cstring(filename));
46760bf661bSpgoyette 	load(props, true, "%s/k_helper/k_helper.kmod",
46860bf661bSpgoyette 	    atf_tc_get_config_var(tc, "srcdir"));
46960bf661bSpgoyette 	{
47060bf661bSpgoyette 		int ok;
47160bf661bSpgoyette 		ATF_CHECK(get_sysctl("vendor.k_helper.prop_int_load",
47260bf661bSpgoyette 		    &ok, sizeof(ok)));
47360bf661bSpgoyette 		ATF_CHECK(ok == 0);
47460bf661bSpgoyette 		ATF_CHECK(get_sysctl("vendor.k_helper2.present",
47560bf661bSpgoyette 		    &ok, sizeof(ok)));
47660bf661bSpgoyette 		ATF_CHECK(ok);
47760bf661bSpgoyette 	}
47860bf661bSpgoyette 	unload("k_helper", true);
47960bf661bSpgoyette 	unload("k_helper2", true);
48060bf661bSpgoyette }
ATF_TC_CLEANUP(cmd_load_recurse,tc)48160bf661bSpgoyette ATF_TC_CLEANUP(cmd_load_recurse, tc)
48260bf661bSpgoyette {
48360bf661bSpgoyette 	unload_cleanup("k_helper");
48460bf661bSpgoyette 	unload_cleanup("k_helper2");
48560bf661bSpgoyette }
48660bf661bSpgoyette 
4875a560143Sjmmv ATF_TC_WITH_CLEANUP(cmd_stat);
ATF_TC_HEAD(cmd_stat,tc)4885a560143Sjmmv ATF_TC_HEAD(cmd_stat, tc)
4895a560143Sjmmv {
4905a560143Sjmmv 	atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_STAT command");
4915a560143Sjmmv 	atf_tc_set_md_var(tc, "require.user", "root");
4925a560143Sjmmv }
ATF_TC_BODY(cmd_stat,tc)4935a560143Sjmmv ATF_TC_BODY(cmd_stat, tc)
4945a560143Sjmmv {
495*ea561c44Spgoyette 	ATF_CHECK(!k_helper_is_present(all_checks));
4965a560143Sjmmv 
4976725d3eeSjmmv 	load(NULL, true, "%s/k_helper/k_helper.kmod",
4986725d3eeSjmmv 	    atf_tc_get_config_var(tc, "srcdir"));
499*ea561c44Spgoyette 	ATF_CHECK(k_helper_is_present(all_checks));
5005a560143Sjmmv 	{
5015a560143Sjmmv 		modstat_t ms;
5025a560143Sjmmv 		ATF_CHECK(get_modstat_info("k_helper", &ms));
5035a560143Sjmmv 
5045a560143Sjmmv 		ATF_CHECK(ms.ms_class == MODULE_CLASS_MISC);
5055a560143Sjmmv 		ATF_CHECK(ms.ms_source == MODULE_SOURCE_FILESYS);
5065a560143Sjmmv 		ATF_CHECK(ms.ms_refcnt == 0);
5075a560143Sjmmv 	}
5085a560143Sjmmv 	unload("k_helper", true);
5095a560143Sjmmv 
510*ea561c44Spgoyette 	ATF_CHECK(!k_helper_is_present(all_checks));
5115a560143Sjmmv }
ATF_TC_CLEANUP(cmd_stat,tc)5125a560143Sjmmv ATF_TC_CLEANUP(cmd_stat, tc)
5135a560143Sjmmv {
5145a560143Sjmmv 	unload_cleanup("k_helper");
5155a560143Sjmmv }
5165a560143Sjmmv 
5175a560143Sjmmv ATF_TC_WITH_CLEANUP(cmd_unload);
ATF_TC_HEAD(cmd_unload,tc)5185a560143Sjmmv ATF_TC_HEAD(cmd_unload, tc)
5195a560143Sjmmv {
5205a560143Sjmmv 	atf_tc_set_md_var(tc, "descr", "Tests for the MODCTL_UNLOAD command");
5215a560143Sjmmv 	atf_tc_set_md_var(tc, "require.user", "root");
5225a560143Sjmmv }
ATF_TC_BODY(cmd_unload,tc)5235a560143Sjmmv ATF_TC_BODY(cmd_unload, tc)
5245a560143Sjmmv {
5256725d3eeSjmmv 	load(NULL, true, "%s/k_helper/k_helper.kmod",
5266725d3eeSjmmv 	    atf_tc_get_config_var(tc, "srcdir"));
5275a560143Sjmmv 
5285a560143Sjmmv 	ATF_CHECK(unload("", false) == ENOENT);
5293ba20983Sad 	ATF_CHECK(unload("non-existent.kmod", false) == ENOENT);
5303ba20983Sad 	ATF_CHECK(unload("k_helper.kmod", false) == ENOENT);
5315a560143Sjmmv 
5325a560143Sjmmv 	ATF_CHECK(k_helper_is_present(stat_check));
5335a560143Sjmmv 	unload("k_helper", true);
5345a560143Sjmmv 	printf("Checking if unload was successful\n");
5355a560143Sjmmv 	ATF_CHECK(!k_helper_is_present(stat_check));
5365a560143Sjmmv }
ATF_TC_CLEANUP(cmd_unload,tc)5375a560143Sjmmv ATF_TC_CLEANUP(cmd_unload, tc)
5385a560143Sjmmv {
5395a560143Sjmmv 	unload_cleanup("k_helper");
5405a560143Sjmmv }
5415a560143Sjmmv 
5425a560143Sjmmv /* --------------------------------------------------------------------- */
5435a560143Sjmmv /* Main                                                                  */
5445a560143Sjmmv /* --------------------------------------------------------------------- */
5455a560143Sjmmv 
ATF_TP_ADD_TCS(tp)5465a560143Sjmmv ATF_TP_ADD_TCS(tp)
5475a560143Sjmmv {
5485a560143Sjmmv 
5495a560143Sjmmv 	ATF_TP_ADD_TC(tp, cmd_load);
5505a560143Sjmmv 	ATF_TP_ADD_TC(tp, cmd_load_props);
5515a560143Sjmmv 	ATF_TP_ADD_TC(tp, cmd_stat);
55260bf661bSpgoyette 	ATF_TP_ADD_TC(tp, cmd_load_recurse);
5535a560143Sjmmv 	ATF_TP_ADD_TC(tp, cmd_unload);
5545a560143Sjmmv 
5555a560143Sjmmv 	return atf_no_error();
5565a560143Sjmmv }
557