xref: /freebsd/sys/compat/linux/linux_mib.c (revision 84a8cad0f605effaf96a207e0c8d2f6a9a77dbbd)
1c6dfea0eSMarcel Moolenaar /*-
2c6dfea0eSMarcel Moolenaar  * Copyright (c) 1999 Marcel Moolenaar
3c6dfea0eSMarcel Moolenaar  * All rights reserved.
4c6dfea0eSMarcel Moolenaar  *
5c6dfea0eSMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
6c6dfea0eSMarcel Moolenaar  * modification, are permitted provided that the following conditions
7c6dfea0eSMarcel Moolenaar  * are met:
8c6dfea0eSMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
9c6dfea0eSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer
10c6dfea0eSMarcel Moolenaar  *    in this position and unchanged.
11c6dfea0eSMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
12c6dfea0eSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
13c6dfea0eSMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
14c6dfea0eSMarcel Moolenaar  * 3. The name of the author may not be used to endorse or promote products
15bc34729cSMarcel Moolenaar  *    derived from this software without specific prior written permission.
16c6dfea0eSMarcel Moolenaar  *
17c6dfea0eSMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18c6dfea0eSMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19c6dfea0eSMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20c6dfea0eSMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21c6dfea0eSMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22c6dfea0eSMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23c6dfea0eSMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24c6dfea0eSMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25c6dfea0eSMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26c6dfea0eSMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27c6dfea0eSMarcel Moolenaar  */
28c6dfea0eSMarcel Moolenaar 
2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h>
3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$");
3116dbc7f2SDavid E. O'Brien 
32c6dfea0eSMarcel Moolenaar #include <sys/param.h>
33c6dfea0eSMarcel Moolenaar #include <sys/kernel.h>
34c6dfea0eSMarcel Moolenaar #include <sys/systm.h>
35c6dfea0eSMarcel Moolenaar #include <sys/sysctl.h>
36c6dfea0eSMarcel Moolenaar #include <sys/proc.h>
37c6dfea0eSMarcel Moolenaar #include <sys/malloc.h>
38c6dfea0eSMarcel Moolenaar #include <sys/jail.h>
3901137630SRobert Watson #include <sys/lock.h>
4001137630SRobert Watson #include <sys/mutex.h>
41c6dfea0eSMarcel Moolenaar 
42aefce619SRuslan Ermilov #include "opt_compat.h"
43aefce619SRuslan Ermilov 
441997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
454af27623STim J. Robbins #include <machine/../linux32/linux.h>
461997c537SDavid E. O'Brien #else
471997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
484af27623STim J. Robbins #endif
49607d46efSMarcel Moolenaar #include <compat/linux/linux_mib.h>
50c6dfea0eSMarcel Moolenaar 
51c6dfea0eSMarcel Moolenaar struct linux_prison {
52c6dfea0eSMarcel Moolenaar 	char	pr_osname[LINUX_MAX_UTSNAME];
53c6dfea0eSMarcel Moolenaar 	char	pr_osrelease[LINUX_MAX_UTSNAME];
54c6dfea0eSMarcel Moolenaar 	int	pr_oss_version;
559ce8f9bcSAlexander Leidinger 	int	pr_use_linux26;	/* flag to determine whether to use 2.6 emulation */
56c6dfea0eSMarcel Moolenaar };
57c6dfea0eSMarcel Moolenaar 
58c6dfea0eSMarcel Moolenaar SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
59c6dfea0eSMarcel Moolenaar 	    "Linux mode");
60c6dfea0eSMarcel Moolenaar 
61b62f75cfSJohn Baldwin static struct mtx osname_lock;
62b62f75cfSJohn Baldwin MTX_SYSINIT(linux_osname, &osname_lock, "linux osname", MTX_DEF);
63b62f75cfSJohn Baldwin 
64c6dfea0eSMarcel Moolenaar static char	linux_osname[LINUX_MAX_UTSNAME] = "Linux";
65c6dfea0eSMarcel Moolenaar 
66c6dfea0eSMarcel Moolenaar static int
6782d9ae4eSPoul-Henning Kamp linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
68c6dfea0eSMarcel Moolenaar {
69c6dfea0eSMarcel Moolenaar 	char osname[LINUX_MAX_UTSNAME];
70c6dfea0eSMarcel Moolenaar 	int error;
71c6dfea0eSMarcel Moolenaar 
72b62f75cfSJohn Baldwin 	linux_get_osname(req->td, osname);
73c6dfea0eSMarcel Moolenaar 	error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
74c6dfea0eSMarcel Moolenaar 	if (error || req->newptr == NULL)
75c6dfea0eSMarcel Moolenaar 		return (error);
76b62f75cfSJohn Baldwin 	error = linux_set_osname(req->td, osname);
77c6dfea0eSMarcel Moolenaar 	return (error);
78c6dfea0eSMarcel Moolenaar }
79c6dfea0eSMarcel Moolenaar 
80c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
8184a8cad0SJamie Gritton 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
82c6dfea0eSMarcel Moolenaar 	    0, 0, linux_sysctl_osname, "A",
83c6dfea0eSMarcel Moolenaar 	    "Linux kernel OS name");
84c6dfea0eSMarcel Moolenaar 
85a47444d5SRoman Divacky static char	linux_osrelease[LINUX_MAX_UTSNAME] = "2.6.16";
86a47444d5SRoman Divacky static int	linux_use_linux26 = 1;
87c6dfea0eSMarcel Moolenaar 
88c6dfea0eSMarcel Moolenaar static int
8982d9ae4eSPoul-Henning Kamp linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
90c6dfea0eSMarcel Moolenaar {
91c6dfea0eSMarcel Moolenaar 	char osrelease[LINUX_MAX_UTSNAME];
92c6dfea0eSMarcel Moolenaar 	int error;
93c6dfea0eSMarcel Moolenaar 
94b62f75cfSJohn Baldwin 	linux_get_osrelease(req->td, osrelease);
95c6dfea0eSMarcel Moolenaar 	error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
96c6dfea0eSMarcel Moolenaar 	if (error || req->newptr == NULL)
97c6dfea0eSMarcel Moolenaar 		return (error);
98b62f75cfSJohn Baldwin 	error = linux_set_osrelease(req->td, osrelease);
99c6dfea0eSMarcel Moolenaar 	return (error);
100c6dfea0eSMarcel Moolenaar }
101c6dfea0eSMarcel Moolenaar 
102c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
10384a8cad0SJamie Gritton 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
104c6dfea0eSMarcel Moolenaar 	    0, 0, linux_sysctl_osrelease, "A",
105c6dfea0eSMarcel Moolenaar 	    "Linux kernel OS release");
106c6dfea0eSMarcel Moolenaar 
107c6dfea0eSMarcel Moolenaar static int	linux_oss_version = 0x030600;
108c6dfea0eSMarcel Moolenaar 
109c6dfea0eSMarcel Moolenaar static int
11082d9ae4eSPoul-Henning Kamp linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
111c6dfea0eSMarcel Moolenaar {
112c6dfea0eSMarcel Moolenaar 	int oss_version;
113c6dfea0eSMarcel Moolenaar 	int error;
114c6dfea0eSMarcel Moolenaar 
115b62f75cfSJohn Baldwin 	oss_version = linux_get_oss_version(req->td);
116c6dfea0eSMarcel Moolenaar 	error = sysctl_handle_int(oidp, &oss_version, 0, req);
117c6dfea0eSMarcel Moolenaar 	if (error || req->newptr == NULL)
118c6dfea0eSMarcel Moolenaar 		return (error);
119b62f75cfSJohn Baldwin 	error = linux_set_oss_version(req->td, oss_version);
120c6dfea0eSMarcel Moolenaar 	return (error);
121c6dfea0eSMarcel Moolenaar }
122c6dfea0eSMarcel Moolenaar 
123c6dfea0eSMarcel Moolenaar SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
12484a8cad0SJamie Gritton 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
125c6dfea0eSMarcel Moolenaar 	    0, 0, linux_sysctl_oss_version, "I",
126c6dfea0eSMarcel Moolenaar 	    "Linux OSS version");
127c6dfea0eSMarcel Moolenaar 
12801137630SRobert Watson /*
12901137630SRobert Watson  * Returns holding the prison mutex if return non-NULL.
13001137630SRobert Watson  */
131b62f75cfSJohn Baldwin static struct prison *
132b62f75cfSJohn Baldwin linux_get_prison(struct thread *td)
133c6dfea0eSMarcel Moolenaar {
134c6dfea0eSMarcel Moolenaar 	register struct prison *pr;
135c6dfea0eSMarcel Moolenaar 	register struct linux_prison *lpr;
136c6dfea0eSMarcel Moolenaar 
137b62f75cfSJohn Baldwin 	KASSERT(td == curthread, ("linux_get_prison() called on !curthread"));
138b62f75cfSJohn Baldwin 	if (!jailed(td->td_ucred))
139c6dfea0eSMarcel Moolenaar 		return (NULL);
140b62f75cfSJohn Baldwin 	pr = td->td_ucred->cr_prison;
141b62f75cfSJohn Baldwin 	mtx_lock(&pr->pr_mtx);
142b62f75cfSJohn Baldwin 	if (pr->pr_linux == NULL) {
14301137630SRobert Watson 		/*
144b62f75cfSJohn Baldwin 		 * If we don't have a linux prison structure yet, allocate
145b62f75cfSJohn Baldwin 		 * one.  We have to handle the race where another thread
146b62f75cfSJohn Baldwin 		 * could be adding a linux prison to this process already.
14701137630SRobert Watson 		 */
14801137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
149b62f75cfSJohn Baldwin 		lpr = malloc(sizeof(struct linux_prison), M_PRISON,
150b62f75cfSJohn Baldwin 		    M_WAITOK | M_ZERO);
15101137630SRobert Watson 		mtx_lock(&pr->pr_mtx);
152b62f75cfSJohn Baldwin 		if (pr->pr_linux == NULL)
153c6dfea0eSMarcel Moolenaar 			pr->pr_linux = lpr;
154b62f75cfSJohn Baldwin 		else
155b62f75cfSJohn Baldwin 			free(lpr, M_PRISON);
15601137630SRobert Watson 	}
157b62f75cfSJohn Baldwin 	return (pr);
158c6dfea0eSMarcel Moolenaar }
159c6dfea0eSMarcel Moolenaar 
16001137630SRobert Watson void
161b62f75cfSJohn Baldwin linux_get_osname(struct thread *td, char *dst)
162c6dfea0eSMarcel Moolenaar {
163c6dfea0eSMarcel Moolenaar 	register struct prison *pr;
164c6dfea0eSMarcel Moolenaar 	register struct linux_prison *lpr;
165c6dfea0eSMarcel Moolenaar 
166b62f75cfSJohn Baldwin 	pr = td->td_ucred->cr_prison;
167b62f75cfSJohn Baldwin 	if (pr != NULL) {
16801137630SRobert Watson 		mtx_lock(&pr->pr_mtx);
16901137630SRobert Watson 		if (pr->pr_linux != NULL) {
17001137630SRobert Watson 			lpr = (struct linux_prison *)pr->pr_linux;
17101137630SRobert Watson 			if (lpr->pr_osname[0]) {
17201137630SRobert Watson 				bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
17301137630SRobert Watson 				mtx_unlock(&pr->pr_mtx);
17401137630SRobert Watson 				return;
17501137630SRobert Watson 			}
17601137630SRobert Watson 		}
17701137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
178b62f75cfSJohn Baldwin 	}
179b62f75cfSJohn Baldwin 
180b62f75cfSJohn Baldwin 	mtx_lock(&osname_lock);
18101137630SRobert Watson 	bcopy(linux_osname, dst, LINUX_MAX_UTSNAME);
182b62f75cfSJohn Baldwin 	mtx_unlock(&osname_lock);
183c6dfea0eSMarcel Moolenaar }
184c6dfea0eSMarcel Moolenaar 
185c6dfea0eSMarcel Moolenaar int
186b62f75cfSJohn Baldwin linux_set_osname(struct thread *td, char *osname)
187c6dfea0eSMarcel Moolenaar {
188b62f75cfSJohn Baldwin 	struct prison *pr;
189b62f75cfSJohn Baldwin 	struct linux_prison *lpr;
190c6dfea0eSMarcel Moolenaar 
191b62f75cfSJohn Baldwin 	pr = linux_get_prison(td);
192b62f75cfSJohn Baldwin 	if (pr != NULL) {
193b62f75cfSJohn Baldwin 		lpr = (struct linux_prison *)pr->pr_linux;
194c6dfea0eSMarcel Moolenaar 		strcpy(lpr->pr_osname, osname);
195b62f75cfSJohn Baldwin 		mtx_unlock(&pr->pr_mtx);
19601137630SRobert Watson 	} else {
197b62f75cfSJohn Baldwin 		mtx_lock(&osname_lock);
198c6dfea0eSMarcel Moolenaar 		strcpy(linux_osname, osname);
199b62f75cfSJohn Baldwin 		mtx_unlock(&osname_lock);
20001137630SRobert Watson 	}
201c6dfea0eSMarcel Moolenaar 
202c6dfea0eSMarcel Moolenaar 	return (0);
203c6dfea0eSMarcel Moolenaar }
204c6dfea0eSMarcel Moolenaar 
20501137630SRobert Watson void
206b62f75cfSJohn Baldwin linux_get_osrelease(struct thread *td, char *dst)
207c6dfea0eSMarcel Moolenaar {
208c6dfea0eSMarcel Moolenaar 	register struct prison *pr;
20901137630SRobert Watson 	struct linux_prison *lpr;
210c6dfea0eSMarcel Moolenaar 
211b62f75cfSJohn Baldwin 	pr = td->td_ucred->cr_prison;
212b62f75cfSJohn Baldwin 	if (pr != NULL) {
21301137630SRobert Watson 		mtx_lock(&pr->pr_mtx);
21401137630SRobert Watson 		if (pr->pr_linux != NULL) {
21501137630SRobert Watson 			lpr = (struct linux_prison *)pr->pr_linux;
21601137630SRobert Watson 			if (lpr->pr_osrelease[0]) {
217b62f75cfSJohn Baldwin 				bcopy(lpr->pr_osrelease, dst,
218b62f75cfSJohn Baldwin 				    LINUX_MAX_UTSNAME);
21901137630SRobert Watson 				mtx_unlock(&pr->pr_mtx);
22001137630SRobert Watson 				return;
22101137630SRobert Watson 			}
22201137630SRobert Watson 		}
22301137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
224b62f75cfSJohn Baldwin 	}
225b62f75cfSJohn Baldwin 
226b62f75cfSJohn Baldwin 	mtx_lock(&osname_lock);
22701137630SRobert Watson 	bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME);
228b62f75cfSJohn Baldwin 	mtx_unlock(&osname_lock);
229c6dfea0eSMarcel Moolenaar }
230c6dfea0eSMarcel Moolenaar 
231c6dfea0eSMarcel Moolenaar int
2329ce8f9bcSAlexander Leidinger linux_use26(struct thread *td)
2339ce8f9bcSAlexander Leidinger {
2349ce8f9bcSAlexander Leidinger 	struct prison *pr;
2359ce8f9bcSAlexander Leidinger 	struct linux_prison *lpr;
23631becc76SAlexander Leidinger 	int use26 = linux_use_linux26;
2379ce8f9bcSAlexander Leidinger 
2389ce8f9bcSAlexander Leidinger 	pr = td->td_ucred->cr_prison;
2399ce8f9bcSAlexander Leidinger 	if (pr != NULL) {
2409ce8f9bcSAlexander Leidinger 		if (pr->pr_linux != NULL) {
2419ce8f9bcSAlexander Leidinger 			lpr = (struct linux_prison *)pr->pr_linux;
2429ce8f9bcSAlexander Leidinger 			use26 = lpr->pr_use_linux26;
2439ce8f9bcSAlexander Leidinger 		}
24431becc76SAlexander Leidinger 	}
2459ce8f9bcSAlexander Leidinger 
2469ce8f9bcSAlexander Leidinger 	return (use26);
2479ce8f9bcSAlexander Leidinger }
2489ce8f9bcSAlexander Leidinger 
2499ce8f9bcSAlexander Leidinger int
250b62f75cfSJohn Baldwin linux_set_osrelease(struct thread *td, char *osrelease)
251c6dfea0eSMarcel Moolenaar {
252b62f75cfSJohn Baldwin 	struct prison *pr;
253b62f75cfSJohn Baldwin 	struct linux_prison *lpr;
2549ce8f9bcSAlexander Leidinger 	int use26;
2559ce8f9bcSAlexander Leidinger 
2569ce8f9bcSAlexander Leidinger 	use26 = (strlen(osrelease) >= 3 && osrelease[2] == '6');
257c6dfea0eSMarcel Moolenaar 
258b62f75cfSJohn Baldwin 	pr = linux_get_prison(td);
259b62f75cfSJohn Baldwin 	if (pr != NULL) {
260b62f75cfSJohn Baldwin 		lpr = (struct linux_prison *)pr->pr_linux;
261c6dfea0eSMarcel Moolenaar 		strcpy(lpr->pr_osrelease, osrelease);
2629ce8f9bcSAlexander Leidinger 		lpr->pr_use_linux26 = use26;
263b62f75cfSJohn Baldwin 		mtx_unlock(&pr->pr_mtx);
26401137630SRobert Watson 	} else {
265b62f75cfSJohn Baldwin 		mtx_lock(&osname_lock);
266c6dfea0eSMarcel Moolenaar 		strcpy(linux_osrelease, osrelease);
2679ce8f9bcSAlexander Leidinger 		linux_use_linux26 = use26;
268b62f75cfSJohn Baldwin 		mtx_unlock(&osname_lock);
26901137630SRobert Watson 	}
270c6dfea0eSMarcel Moolenaar 
271c6dfea0eSMarcel Moolenaar 	return (0);
272c6dfea0eSMarcel Moolenaar }
273c6dfea0eSMarcel Moolenaar 
274c6dfea0eSMarcel Moolenaar int
275b62f75cfSJohn Baldwin linux_get_oss_version(struct thread *td)
276c6dfea0eSMarcel Moolenaar {
277c6dfea0eSMarcel Moolenaar 	register struct prison *pr;
278c6dfea0eSMarcel Moolenaar 	register struct linux_prison *lpr;
27901137630SRobert Watson 	int version;
28001137630SRobert Watson 
281b62f75cfSJohn Baldwin 	pr = td->td_ucred->cr_prison;
282b62f75cfSJohn Baldwin 	if (pr != NULL) {
28301137630SRobert Watson 		mtx_lock(&pr->pr_mtx);
28401137630SRobert Watson 		if (pr->pr_linux != NULL) {
28501137630SRobert Watson 			lpr = (struct linux_prison *)pr->pr_linux;
28601137630SRobert Watson 			if (lpr->pr_oss_version) {
28701137630SRobert Watson 				version = lpr->pr_oss_version;
288b62f75cfSJohn Baldwin 				mtx_unlock(&pr->pr_mtx);
289b62f75cfSJohn Baldwin 				return (version);
29001137630SRobert Watson 			}
29101137630SRobert Watson 		}
29201137630SRobert Watson 		mtx_unlock(&pr->pr_mtx);
293b62f75cfSJohn Baldwin 	}
29401137630SRobert Watson 
295b62f75cfSJohn Baldwin 	mtx_lock(&osname_lock);
296b62f75cfSJohn Baldwin 	version = linux_oss_version;
297b62f75cfSJohn Baldwin 	mtx_unlock(&osname_lock);
29801137630SRobert Watson 	return (version);
299c6dfea0eSMarcel Moolenaar }
300c6dfea0eSMarcel Moolenaar 
301c6dfea0eSMarcel Moolenaar int
302b62f75cfSJohn Baldwin linux_set_oss_version(struct thread *td, int oss_version)
303c6dfea0eSMarcel Moolenaar {
304b62f75cfSJohn Baldwin 	struct prison *pr;
305b62f75cfSJohn Baldwin 	struct linux_prison *lpr;
306c6dfea0eSMarcel Moolenaar 
307b62f75cfSJohn Baldwin 	pr = linux_get_prison(td);
308b62f75cfSJohn Baldwin 	if (pr != NULL) {
309b62f75cfSJohn Baldwin 		lpr = (struct linux_prison *)pr->pr_linux;
310c6dfea0eSMarcel Moolenaar 		lpr->pr_oss_version = oss_version;
311b62f75cfSJohn Baldwin 		mtx_unlock(&pr->pr_mtx);
31201137630SRobert Watson 	} else {
313b62f75cfSJohn Baldwin 		mtx_lock(&osname_lock);
314c6dfea0eSMarcel Moolenaar 		linux_oss_version = oss_version;
315b62f75cfSJohn Baldwin 		mtx_unlock(&osname_lock);
31601137630SRobert Watson 	}
317c6dfea0eSMarcel Moolenaar 
318c6dfea0eSMarcel Moolenaar 	return (0);
319c6dfea0eSMarcel Moolenaar }
32024593369SJonathan Lemon 
32124593369SJonathan Lemon #ifdef DEBUG
32224593369SJonathan Lemon 
32367b60513SPeter Wemm u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
32424593369SJonathan Lemon 
325ec0b1e67SPeter Wemm static int
32624593369SJonathan Lemon linux_debug(int syscall, int toggle, int global)
32724593369SJonathan Lemon {
32824593369SJonathan Lemon 
32924593369SJonathan Lemon 	if (global) {
33024593369SJonathan Lemon 		char c = toggle ? 0 : 0xff;
33124593369SJonathan Lemon 
33224593369SJonathan Lemon 		memset(linux_debug_map, c, sizeof(linux_debug_map));
33324593369SJonathan Lemon 		return (0);
33424593369SJonathan Lemon 	}
33524593369SJonathan Lemon 	if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
33624593369SJonathan Lemon 		return (EINVAL);
33724593369SJonathan Lemon 	if (toggle)
33824593369SJonathan Lemon 		clrbit(linux_debug_map, syscall);
33924593369SJonathan Lemon 	else
34024593369SJonathan Lemon 		setbit(linux_debug_map, syscall);
34124593369SJonathan Lemon 	return (0);
34224593369SJonathan Lemon }
34324593369SJonathan Lemon 
34424593369SJonathan Lemon /*
345b90faaf3SDima Dorfman  * Usage: sysctl linux.debug=<syscall_nr>.<0/1>
34624593369SJonathan Lemon  *
347b90faaf3SDima Dorfman  *    E.g.: sysctl linux.debug=21.0
34824593369SJonathan Lemon  *
34924593369SJonathan Lemon  * As a special case, syscall "all" will apply to all syscalls globally.
35024593369SJonathan Lemon  */
35124593369SJonathan Lemon #define LINUX_MAX_DEBUGSTR	16
35224593369SJonathan Lemon static int
35324593369SJonathan Lemon linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
35424593369SJonathan Lemon {
35524593369SJonathan Lemon 	char value[LINUX_MAX_DEBUGSTR], *p;
35624593369SJonathan Lemon 	int error, sysc, toggle;
35724593369SJonathan Lemon 	int global = 0;
35824593369SJonathan Lemon 
35924593369SJonathan Lemon 	value[0] = '\0';
36024593369SJonathan Lemon 	error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
36124593369SJonathan Lemon 	if (error || req->newptr == NULL)
36224593369SJonathan Lemon 		return (error);
36324593369SJonathan Lemon 	for (p = value; *p != '\0' && *p != '.'; p++);
36424593369SJonathan Lemon 	if (*p == '\0')
36524593369SJonathan Lemon 		return (EINVAL);
36624593369SJonathan Lemon 	*p++ = '\0';
36724593369SJonathan Lemon 	sysc = strtol(value, NULL, 0);
36824593369SJonathan Lemon 	toggle = strtol(p, NULL, 0);
36924593369SJonathan Lemon 	if (strcmp(value, "all") == 0)
37024593369SJonathan Lemon 		global = 1;
37124593369SJonathan Lemon 	error = linux_debug(sysc, toggle, global);
37224593369SJonathan Lemon 	return (error);
37324593369SJonathan Lemon }
37424593369SJonathan Lemon 
37524593369SJonathan Lemon SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
37624593369SJonathan Lemon             CTLTYPE_STRING | CTLFLAG_RW,
37724593369SJonathan Lemon             0, 0, linux_sysctl_debug, "A",
37824593369SJonathan Lemon             "Linux debugging control");
37924593369SJonathan Lemon 
38024593369SJonathan Lemon #endif /* DEBUG */
381