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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: releng/6.0/sys/compat/linux/linux_mib.c 140214 2005-01-14 04:44:56Z obrien $");
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/sysctl.h>
36 #include <sys/proc.h>
37 #include <sys/malloc.h>
38 #include <sys/jail.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41
42 #include "opt_compat.h"
43
44 #ifdef COMPAT_LINUX32
45 #include <machine/../linux32/linux.h>
46 #else
47 #include <machine/../linux/linux.h>
48 #endif
49 #include <compat/linux/linux_mib.h>
50
51 struct linux_prison {
52 char pr_osname[LINUX_MAX_UTSNAME];
53 char pr_osrelease[LINUX_MAX_UTSNAME];
54 int pr_oss_version;
55 };
56
57 SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
58 "Linux mode");
59
60 static struct mtx osname_lock;
61 MTX_SYSINIT(linux_osname, &osname_lock, "linux osname", MTX_DEF);
62
63 static char linux_osname[LINUX_MAX_UTSNAME] = "Linux";
64
65 static int
66 linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
67 {
68 char osname[LINUX_MAX_UTSNAME];
69 int error;
70
71 linux_get_osname(req->td, osname);
72 error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
73 if (error || req->newptr == NULL)
74 return (error);
75 error = linux_set_osname(req->td, osname);
76 return (error);
77 }
78
79 SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
80 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,
81 0, 0, linux_sysctl_osname, "A",
82 "Linux kernel OS name");
83
84 static char linux_osrelease[LINUX_MAX_UTSNAME] = "2.4.2";
85
86 static int
87 linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
88 {
89 char osrelease[LINUX_MAX_UTSNAME];
90 int error;
91
92 linux_get_osrelease(req->td, osrelease);
93 error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
94 if (error || req->newptr == NULL)
95 return (error);
96 error = linux_set_osrelease(req->td, osrelease);
97 return (error);
98 }
99
100 SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
101 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,
102 0, 0, linux_sysctl_osrelease, "A",
103 "Linux kernel OS release");
104
105 static int linux_oss_version = 0x030600;
106
107 static int
108 linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
109 {
110 int oss_version;
111 int error;
112
113 oss_version = linux_get_oss_version(req->td);
114 error = sysctl_handle_int(oidp, &oss_version, 0, req);
115 if (error || req->newptr == NULL)
116 return (error);
117 error = linux_set_oss_version(req->td, oss_version);
118 return (error);
119 }
120
121 SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
122 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON,
123 0, 0, linux_sysctl_oss_version, "I",
124 "Linux OSS version");
125
126 /*
127 * Returns holding the prison mutex if return non-NULL.
128 */
129 static struct prison *
130 linux_get_prison(struct thread *td)
131 {
132 register struct prison *pr;
133 register struct linux_prison *lpr;
134
135 KASSERT(td == curthread, ("linux_get_prison() called on !curthread"));
136 if (!jailed(td->td_ucred))
137 return (NULL);
138 pr = td->td_ucred->cr_prison;
139 mtx_lock(&pr->pr_mtx);
140 if (pr->pr_linux == NULL) {
141 /*
142 * If we don't have a linux prison structure yet, allocate
143 * one. We have to handle the race where another thread
144 * could be adding a linux prison to this process already.
145 */
146 mtx_unlock(&pr->pr_mtx);
147 lpr = malloc(sizeof(struct linux_prison), M_PRISON,
148 M_WAITOK | M_ZERO);
149 mtx_lock(&pr->pr_mtx);
150 if (pr->pr_linux == NULL)
151 pr->pr_linux = lpr;
152 else
153 free(lpr, M_PRISON);
154 }
155 return (pr);
156 }
157
158 void
159 linux_mib_destroy(void)
160 {
161
162 mtx_destroy(&osname_lock);
163 }
164
165 void
166 linux_get_osname(struct thread *td, char *dst)
167 {
168 register struct prison *pr;
169 register struct linux_prison *lpr;
170
171 pr = td->td_ucred->cr_prison;
172 if (pr != NULL) {
173 mtx_lock(&pr->pr_mtx);
174 if (pr->pr_linux != NULL) {
175 lpr = (struct linux_prison *)pr->pr_linux;
176 if (lpr->pr_osname[0]) {
177 bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
178 mtx_unlock(&pr->pr_mtx);
179 return;
180 }
181 }
182 mtx_unlock(&pr->pr_mtx);
183 }
184
185 mtx_lock(&osname_lock);
186 bcopy(linux_osname, dst, LINUX_MAX_UTSNAME);
187 mtx_unlock(&osname_lock);
188 }
189
190 int
191 linux_set_osname(struct thread *td, char *osname)
192 {
193 struct prison *pr;
194 struct linux_prison *lpr;
195
196 pr = linux_get_prison(td);
197 if (pr != NULL) {
198 lpr = (struct linux_prison *)pr->pr_linux;
199 strcpy(lpr->pr_osname, osname);
200 mtx_unlock(&pr->pr_mtx);
201 } else {
202 mtx_lock(&osname_lock);
203 strcpy(linux_osname, osname);
204 mtx_unlock(&osname_lock);
205 }
206
207 return (0);
208 }
209
210 void
211 linux_get_osrelease(struct thread *td, char *dst)
212 {
213 register struct prison *pr;
214 struct linux_prison *lpr;
215
216 pr = td->td_ucred->cr_prison;
217 if (pr != NULL) {
218 mtx_lock(&pr->pr_mtx);
219 if (pr->pr_linux != NULL) {
220 lpr = (struct linux_prison *)pr->pr_linux;
221 if (lpr->pr_osrelease[0]) {
222 bcopy(lpr->pr_osrelease, dst,
223 LINUX_MAX_UTSNAME);
224 mtx_unlock(&pr->pr_mtx);
225 return;
226 }
227 }
228 mtx_unlock(&pr->pr_mtx);
229 }
230
231 mtx_lock(&osname_lock);
232 bcopy(linux_osrelease, dst, LINUX_MAX_UTSNAME);
233 mtx_unlock(&osname_lock);
234 }
235
236 int
237 linux_set_osrelease(struct thread *td, char *osrelease)
238 {
239 struct prison *pr;
240 struct linux_prison *lpr;
241
242 pr = linux_get_prison(td);
243 if (pr != NULL) {
244 lpr = (struct linux_prison *)pr->pr_linux;
245 strcpy(lpr->pr_osrelease, osrelease);
246 mtx_unlock(&pr->pr_mtx);
247 } else {
248 mtx_lock(&osname_lock);
249 strcpy(linux_osrelease, osrelease);
250 mtx_unlock(&osname_lock);
251 }
252
253 return (0);
254 }
255
256 int
257 linux_get_oss_version(struct thread *td)
258 {
259 register struct prison *pr;
260 register struct linux_prison *lpr;
261 int version;
262
263 pr = td->td_ucred->cr_prison;
264 if (pr != NULL) {
265 mtx_lock(&pr->pr_mtx);
266 if (pr->pr_linux != NULL) {
267 lpr = (struct linux_prison *)pr->pr_linux;
268 if (lpr->pr_oss_version) {
269 version = lpr->pr_oss_version;
270 mtx_unlock(&pr->pr_mtx);
271 return (version);
272 }
273 }
274 mtx_unlock(&pr->pr_mtx);
275 }
276
277 mtx_lock(&osname_lock);
278 version = linux_oss_version;
279 mtx_unlock(&osname_lock);
280 return (version);
281 }
282
283 int
284 linux_set_oss_version(struct thread *td, int oss_version)
285 {
286 struct prison *pr;
287 struct linux_prison *lpr;
288
289 pr = linux_get_prison(td);
290 if (pr != NULL) {
291 lpr = (struct linux_prison *)pr->pr_linux;
292 lpr->pr_oss_version = oss_version;
293 mtx_unlock(&pr->pr_mtx);
294 } else {
295 mtx_lock(&osname_lock);
296 linux_oss_version = oss_version;
297 mtx_unlock(&osname_lock);
298 }
299
300 return (0);
301 }
302
303 #ifdef DEBUG
304
305 u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
306
307 static int
308 linux_debug(int syscall, int toggle, int global)
309 {
310
311 if (global) {
312 char c = toggle ? 0 : 0xff;
313
314 memset(linux_debug_map, c, sizeof(linux_debug_map));
315 return (0);
316 }
317 if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
318 return (EINVAL);
319 if (toggle)
320 clrbit(linux_debug_map, syscall);
321 else
322 setbit(linux_debug_map, syscall);
323 return (0);
324 }
325
326 /*
327 * Usage: sysctl linux.debug=<syscall_nr>.<0/1>
328 *
329 * E.g.: sysctl linux.debug=21.0
330 *
331 * As a special case, syscall "all" will apply to all syscalls globally.
332 */
333 #define LINUX_MAX_DEBUGSTR 16
334 static int
335 linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
336 {
337 char value[LINUX_MAX_DEBUGSTR], *p;
338 int error, sysc, toggle;
339 int global = 0;
340
341 value[0] = '\0';
342 error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
343 if (error || req->newptr == NULL)
344 return (error);
345 for (p = value; *p != '\0' && *p != '.'; p++);
346 if (*p == '\0')
347 return (EINVAL);
348 *p++ = '\0';
349 sysc = strtol(value, NULL, 0);
350 toggle = strtol(p, NULL, 0);
351 if (strcmp(value, "all") == 0)
352 global = 1;
353 error = linux_debug(sysc, toggle, global);
354 return (error);
355 }
356
357 SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
358 CTLTYPE_STRING | CTLFLAG_RW,
359 0, 0, linux_sysctl_debug, "A",
360 "Linux debugging control");
361
362 #endif /* DEBUG */
Cache object: f0bdebddbaf85affd6f74401396ca5b4
|