95c80ea991c2d279affe447ae88008f7216ca0e1
[dragonfly.git] / sys / emulation / linux / linux_mib.c
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: src/sys/compat/linux/linux_mib.c,v 1.7.2.2 2001/11/05 19:08:22 marcel Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_mib.c,v 1.3 2003/06/23 17:55:26 dillon Exp $
30  */
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
40 #include <machine/../linux/linux.h>
41 #include <compat/linux/linux_mib.h>
42
43 struct linux_prison {
44         char    pr_osname[LINUX_MAX_UTSNAME];
45         char    pr_osrelease[LINUX_MAX_UTSNAME];
46         int     pr_oss_version;
47 };
48
49 SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
50             "Linux mode");
51
52 static char     linux_osname[LINUX_MAX_UTSNAME] = "Linux";
53
54 static int
55 linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
56 {
57         char osname[LINUX_MAX_UTSNAME];
58         int error;
59
60         strcpy(osname, linux_get_osname(req->p));
61         error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
62         if (error || req->newptr == NULL)
63                 return (error);
64         error = linux_set_osname(req->p, osname);
65         return (error);
66 }
67
68 SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
69             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,
70             0, 0, linux_sysctl_osname, "A",
71             "Linux kernel OS name");
72
73 static char     linux_osrelease[LINUX_MAX_UTSNAME] = "2.4.2";
74
75 static int
76 linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
77 {
78         char osrelease[LINUX_MAX_UTSNAME];
79         int error;
80
81         strcpy(osrelease, linux_get_osrelease(req->p));
82         error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
83         if (error || req->newptr == NULL)
84                 return (error);
85         error = linux_set_osrelease(req->p, osrelease);
86         return (error);
87 }
88
89 SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
90             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON,
91             0, 0, linux_sysctl_osrelease, "A",
92             "Linux kernel OS release");
93
94 static int      linux_oss_version = 0x030600;
95
96 static int
97 linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
98 {
99         int oss_version;
100         int error;
101
102         oss_version = linux_get_oss_version(req->p);
103         error = sysctl_handle_int(oidp, &oss_version, 0, req);
104         if (error || req->newptr == NULL)
105                 return (error);
106         error = linux_set_oss_version(req->p, oss_version);
107         return (error);
108 }
109
110 SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
111             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON,
112             0, 0, linux_sysctl_oss_version, "I",
113             "Linux OSS version");
114
115 static struct linux_prison *
116 get_prison(struct proc *p)
117 {
118         struct prison *pr;
119         struct linux_prison *lpr;
120
121         pr = p->p_ucred->cr_prison;
122         if (pr == NULL)
123                 return (NULL);
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 */