xref: /freebsd/sys/compat/linux/linux_mib.c (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
1 /*-
2  * Copyright (c) 1999 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
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  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/sysctl.h>
35 #include <sys/proc.h>
36 #include <sys/malloc.h>
37 #include <sys/jail.h>
38 
39 #include <machine/../linux/linux.h>
40 #include <compat/linux/linux_mib.h>
41 
42 struct linux_prison {
43 	char	pr_osname[LINUX_MAX_UTSNAME];
44 	char	pr_osrelease[LINUX_MAX_UTSNAME];
45 	int	pr_oss_version;
46 };
47 
48 SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
49 	    "Linux mode");
50 
51 static char	linux_osname[LINUX_MAX_UTSNAME] = "Linux";
52 
53 static int
54 linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
55 {
56 	char osname[LINUX_MAX_UTSNAME];
57 	int error;
58 
59 	strcpy(osname, linux_get_osname(req->p));
60 	error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
61 	if (error || req->newptr == NULL)
62 		return (error);
63 	error = linux_set_osname(req->p, osname);
64 	return (error);
65 }
66 
67 SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
68 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,
69 	    0, 0, linux_sysctl_osname, "A",
70 	    "Linux kernel OS name");
71 
72 static char	linux_osrelease[LINUX_MAX_UTSNAME] = "2.4.2";
73 
74 static int
75 linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
76 {
77 	char osrelease[LINUX_MAX_UTSNAME];
78 	int error;
79 
80 	strcpy(osrelease, linux_get_osrelease(req->p));
81 	error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
82 	if (error || req->newptr == NULL)
83 		return (error);
84 	error = linux_set_osrelease(req->p, osrelease);
85 	return (error);
86 }
87 
88 SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
89 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,
90 	    0, 0, linux_sysctl_osrelease, "A",
91 	    "Linux kernel OS release");
92 
93 static int	linux_oss_version = 0x030600;
94 
95 static int
96 linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
97 {
98 	int oss_version;
99 	int error;
100 
101 	oss_version = linux_get_oss_version(req->p);
102 	error = sysctl_handle_int(oidp, &oss_version, 0, req);
103 	if (error || req->newptr == NULL)
104 		return (error);
105 	error = linux_set_oss_version(req->p, oss_version);
106 	return (error);
107 }
108 
109 SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
110 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON,
111 	    0, 0, linux_sysctl_oss_version, "I",
112 	    "Linux OSS version");
113 
114 static struct linux_prison *
115 get_prison(struct proc *p)
116 {
117 	register struct prison *pr;
118 	register struct linux_prison *lpr;
119 
120 	if (!jailed(p->p_ucred))
121 		return (NULL);
122 
123 	pr = p->p_ucred->cr_prison;
124 
125 	if (pr->pr_linux == NULL) {
126 		MALLOC(lpr, struct linux_prison *, sizeof *lpr,
127 		    M_PRISON, M_WAITOK|M_ZERO);
128 		pr->pr_linux = lpr;
129 	}
130 
131 	return (pr->pr_linux);
132 }
133 
134 char *
135 linux_get_osname(p)
136 	struct proc *p;
137 {
138 	register struct prison *pr;
139 	register struct linux_prison *lpr;
140 
141 	pr = p->p_ucred->cr_prison;
142 	if (pr != NULL && pr->pr_linux != NULL) {
143 		lpr = pr->pr_linux;
144 		if (lpr->pr_osname[0])
145 			return (lpr->pr_osname);
146 	}
147 
148 	return (linux_osname);
149 }
150 
151 int
152 linux_set_osname(p, osname)
153 	struct proc *p;
154 	char *osname;
155 {
156 	register struct linux_prison *lpr;
157 
158 	lpr = get_prison(p);
159 	if (lpr != NULL)
160 		strcpy(lpr->pr_osname, osname);
161 	else
162 		strcpy(linux_osname, osname);
163 
164 	return (0);
165 }
166 
167 char *
168 linux_get_osrelease(p)
169 	struct proc *p;
170 {
171 	register struct prison *pr;
172 	register struct linux_prison *lpr;
173 
174 	pr = p->p_ucred->cr_prison;
175 	if (pr != NULL && pr->pr_linux != NULL) {
176 		lpr = pr->pr_linux;
177 		if (lpr->pr_osrelease[0])
178 			return (lpr->pr_osrelease);
179 	}
180 
181 	return (linux_osrelease);
182 }
183 
184 int
185 linux_set_osrelease(p, osrelease)
186 	struct proc *p;
187 	char *osrelease;
188 {
189 	register struct linux_prison *lpr;
190 
191 	lpr = get_prison(p);
192 	if (lpr != NULL)
193 		strcpy(lpr->pr_osrelease, osrelease);
194 	else
195 		strcpy(linux_osrelease, osrelease);
196 
197 	return (0);
198 }
199 
200 int
201 linux_get_oss_version(p)
202 	struct proc *p;
203 {
204 	register struct prison *pr;
205 	register struct linux_prison *lpr;
206 
207 	pr = p->p_ucred->cr_prison;
208 	if (pr != NULL && pr->pr_linux != NULL) {
209 		lpr = pr->pr_linux;
210 		if (lpr->pr_oss_version)
211 			return (lpr->pr_oss_version);
212 	}
213 
214 	return (linux_oss_version);
215 }
216 
217 int
218 linux_set_oss_version(p, oss_version)
219 	struct proc *p;
220 	int oss_version;
221 {
222 	register struct linux_prison *lpr;
223 
224 	lpr = get_prison(p);
225 	if (lpr != NULL)
226 		lpr->pr_oss_version = oss_version;
227 	else
228 		linux_oss_version = oss_version;
229 
230 	return (0);
231 }
232 
233 #ifdef DEBUG
234 
235 u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
236 
237 static int
238 linux_debug(int syscall, int toggle, int global)
239 {
240 
241 	if (global) {
242 		char c = toggle ? 0 : 0xff;
243 
244 		memset(linux_debug_map, c, sizeof(linux_debug_map));
245 		return (0);
246 	}
247 	if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
248 		return (EINVAL);
249 	if (toggle)
250 		clrbit(linux_debug_map, syscall);
251 	else
252 		setbit(linux_debug_map, syscall);
253 	return (0);
254 }
255 
256 /*
257  * Usage: sysctl -w linux.debug=<syscall_nr>.<0/1>
258  *
259  *    E.g.: sysctl -w linux.debug=21.0
260  *
261  * As a special case, syscall "all" will apply to all syscalls globally.
262  */
263 #define LINUX_MAX_DEBUGSTR	16
264 static int
265 linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
266 {
267 	char value[LINUX_MAX_DEBUGSTR], *p;
268 	int error, sysc, toggle;
269 	int global = 0;
270 
271 	value[0] = '\0';
272 	error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
273 	if (error || req->newptr == NULL)
274 		return (error);
275 	for (p = value; *p != '\0' && *p != '.'; p++);
276 	if (*p == '\0')
277 		return (EINVAL);
278 	*p++ = '\0';
279 	sysc = strtol(value, NULL, 0);
280 	toggle = strtol(p, NULL, 0);
281 	if (strcmp(value, "all") == 0)
282 		global = 1;
283 	error = linux_debug(sysc, toggle, global);
284 	return (error);
285 }
286 
287 SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
288             CTLTYPE_STRING | CTLFLAG_RW,
289             0, 0, linux_sysctl_debug, "A",
290             "Linux debugging control");
291 
292 #endif /* DEBUG */
293