150476Speter/*	$NetBSD: t_modcmd.c,v 1.10 2017/01/13 21:30:43 christos Exp $	*/
21987Swollman
31987Swollman/*
41987Swollman * Copyright (c) 2009 The NetBSD Foundation, Inc.
5100346Sru * All rights reserved.
6100346Sru *
7100346Sru * Redistribution and use in source and binary forms, with or without
8100346Sru * modification, are permitted provided that the following conditions
9100346Sru * are met:
10100346Sru * 1. Redistributions of source code must retain the above copyright
11100346Sru *    notice, this list of conditions and the following disclaimer.
12100346Sru * 2. Redistributions in binary form must reproduce the above copyright
13100346Sru *    notice, this list of conditions and the following disclaimer in the
14100346Sru *    documentation and/or other materials provided with the distribution.
15100346Sru *
16100346Sru * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17100346Sru * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18100346Sru * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19100346Sru * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20100346Sru * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21100346Sru * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22100346Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23100346Sru * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24100346Sru * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25100346Sru * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26100346Sru * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27100346Sru * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28100346Sru */
29100346Sru
30100346Sru#include <sys/types.h>
31100346Sru#include <sys/mount.h>
32100346Sru#include <sys/sysctl.h>
33100346Sru
34100346Sru#include <rump/rump.h>
35100346Sru#include <rump/rump_syscalls.h>
36100346Sru
374257Sphk#include <fs/tmpfs/tmpfs_args.h>
38100346Sru
39100346Sru#include <atf-c.h>
40100346Sru#include <dlfcn.h>
41100346Sru#include <err.h>
42100346Sru#include <errno.h>
43100346Sru#include <stdio.h>
44100346Sru#include <stdlib.h>
45100346Sru#include <string.h>
46100346Sru#include <unistd.h>
47100346Sru#include <util.h>
48100346Sru
49100346Sru#include "h_macros.h"
50100346Sru/*
51100346Sru * We verify that modules can be loaded and unloaded.
52100346Sru * tmpfs was chosen because it does not depend on an image.
53100346Sru */
54100346Sru
55100346SruATF_TC(cmsg_modcmd);
56100346SruATF_TC_HEAD(cmsg_modcmd, tc)
57100346Sru{
58100346Sru	atf_tc_set_md_var(tc, "descr", "Checks that loading and unloading "
59100346Sru	    "a module (vfs/tmpfs) is possible");
60100346Sru}
61100346Sru
62100346Srustatic int
63100346Srudisable_autoload(void)
64100346Sru{
65100346Sru	struct sysctlnode q, ans[256];
66100346Sru	int mib[3];
67100346Sru	size_t alen;
68100346Sru	unsigned i;
69100346Sru	bool no;
70100346Sru
71100346Sru	mib[0] = CTL_KERN;
72100346Sru	mib[1] = CTL_QUERY;
73100346Sru	alen = sizeof(ans);
74100346Sru
75100346Sru	memset(&q, 0, sizeof(q));
76100346Sru	q.sysctl_flags = SYSCTL_VERSION;
77100346Sru
78100346Sru	if (rump_sys___sysctl(mib, 2, ans, &alen, &q, sizeof(q)) == -1)
79100346Sru		return -1;
80100346Sru
81100346Sru	for (i = 0; i < __arraycount(ans); i++)
82100346Sru		if (strcmp("module", ans[i].sysctl_name) == 0)
83100346Sru			break;
84100346Sru	if (i == __arraycount(ans)) {
85100346Sru		errno = ENOENT;
86100346Sru		return -1;
87100346Sru	}
88100346Sru
89100346Sru	mib[1] = ans[i].sysctl_num;
90100346Sru	mib[2] = CTL_QUERY;
91100346Sru
92100346Sru	if (rump_sys___sysctl(mib, 3, ans, &alen, &q, sizeof(q)) == -1)
93100346Sru		return errno;
94100346Sru
95100346Sru	for (i = 0; i < __arraycount(ans); i++)
96100346Sru		if (strcmp("autoload", ans[i].sysctl_name) == 0)
97100346Sru			break;
98100346Sru	if (i == __arraycount(ans)) {
99100346Sru		errno = ENOENT;
100100346Sru		return -1;
101100346Sru	}
102100346Sru
103100346Sru	mib[2] = ans[i].sysctl_num;
104100346Sru
105100346Sru	no = false;
106100346Sru	alen = 0;
107100346Sru	if (rump_sys___sysctl(mib, 3, NULL, &alen, &no, sizeof(no)) == -1)
108100346Sru		return errno;
109100346Sru
110100346Sru	return 0;
111100346Sru
112100346Sru}
113100346Sru
114100346Sru#define TMPFSMODULE "librumpfs_tmpfs.so"
115100346SruATF_TC_BODY(cmsg_modcmd, tc)
116100346Sru{
117100346Sru	struct tmpfs_args args;
118100346Sru	const struct modinfo *const *mi_start, *const *mi_end;
119100346Sru	void *handle;
120100346Sru	int i, rv, loop = 0;
121100346Sru
122100346Sru	rump_init();
123100346Sru
124100346Sru	if (disable_autoload() == -1)
125100346Sru		atf_tc_fail_errno("count not disable module autoload");
126100346Sru
127100346Sru	memset(&args, 0, sizeof(args));
128100346Sru	args.ta_version = TMPFS_ARGS_VERSION;
129100346Sru	args.ta_root_mode = 0777;
130100346Sru
131100346Sru	if (rump_sys_mkdir("/mp", 0777) == -1)
132100346Sru		atf_tc_fail_errno("mkdir mountpoint");
133100346Sru	if (rump_sys_mount(MOUNT_TMPFS, "/mp", 0, &args, sizeof(args)) != -1)
134100346Sru		atf_tc_fail("mount unexpectedly succeeded");
135100346Sru
136100346Sru	handle = dlopen(TMPFSMODULE, RTLD_GLOBAL);
137100346Sru	if (handle == NULL) {
138100346Sru		const char *dlmsg = dlerror();
139100346Sru		atf_tc_fail("cannot open %s: %s", TMPFSMODULE, dlmsg);
140100346Sru	}
141100346Sru
142100346Sru again:
143100346Sru	mi_start = dlsym(handle, "__start_link_set_modules");
144100346Sru	mi_end = dlsym(handle, "__stop_link_set_modules");
145100346Sru	if (mi_start == NULL || mi_end == NULL)
146100346Sru		atf_tc_fail("cannot find module info");
147121580Semax	if ((rv = rump_pub_module_init(mi_start, (size_t)(mi_end-mi_start)))!=0)
148100346Sru		atf_tc_fail("module init failed: %d (%s)", rv, strerror(rv));
149100346Sru	if ((rv = rump_pub_module_init(mi_start, (size_t)(mi_end-mi_start)))==0)
150100346Sru		atf_tc_fail("module double init succeeded");
151100346Sru
152100346Sru	if (rump_sys_mount(MOUNT_TMPFS, "/mp", 0, &args, sizeof(args)) == -1)
153100346Sru		atf_tc_fail_errno("still cannot mount");
154100346Sru	if (rump_sys_unmount("/mp", 0) == -1)
155100346Sru		atf_tc_fail("cannot unmount");
156100346Sru	for (i = 0; i < (int)(mi_end-mi_start); i++) {
157100346Sru		if ((rv = rump_pub_module_fini(mi_start[i])) != 0)
158100346Sru			atf_tc_fail("module fini failed: %d (%s)",
159100346Sru			    rv, strerror(rv));
160100346Sru	}
161100346Sru	for (i = 0; i < (int)(mi_end-mi_start); i++) {
162100346Sru		if ((rv = rump_pub_module_fini(mi_start[i])) == 0)
163100346Sru			atf_tc_fail("module double fini succeeded");
164100346Sru	}
165100346Sru	if (loop++ == 0)
166100346Sru		goto again;
167100346Sru
168100346Sru	if (dlclose(handle)) {
169100346Sru		const char *dlmsg = dlerror();
170100346Sru		atf_tc_fail("cannot close %s: %s", TMPFSMODULE, dlmsg);
171100346Sru	}
172100346Sru
173100346Sru	if (rump_sys_mount(MOUNT_TMPFS, "/mp", 0, &args, sizeof(args)) != -1)
174100346Sru		atf_tc_fail("mount unexpectedly succeeded");
175100346Sru}
176100346Sru
177100346SruATF_TP_ADD_TCS(tp)
178100346Sru{
179100346Sru	ATF_TP_ADD_TC(tp, cmsg_modcmd);
180100346Sru
181100346Sru	return atf_no_error();
182100346Sru}
183100346Sru