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