sbin/hammer: Directly access volume in volume list
[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  */
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 <arch_linux/linux.h>
40 #include "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->td));
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->td, 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.6.16";
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->td));
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->td, 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->td);
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->td, 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 thread *td)
116 {
117         struct prison *pr;
118         struct linux_prison *lpr;
119
120         KKASSERT(td->td_proc);
121         pr = td->td_proc->p_ucred->cr_prison;
122         if (pr == NULL)
123                 return (NULL);
124
125         if (pr->pr_linux == NULL) {
126                 lpr = kmalloc(sizeof *lpr, M_PRISON, M_WAITOK | M_ZERO);
127                 pr->pr_linux = lpr;
128         }
129
130         return (pr->pr_linux);
131 }
132
133 char *
134 linux_get_osname(struct thread *td)
135 {
136         struct prison *pr;
137         struct linux_prison *lpr;
138
139         KKASSERT(td->td_proc);
140         pr = td->td_proc->p_ucred->cr_prison;
141         if (pr != NULL && pr->pr_linux != NULL) {
142                 lpr = pr->pr_linux;
143                 if (lpr->pr_osname[0])
144                         return (lpr->pr_osname);
145         }
146
147         return (linux_osname);
148 }
149
150 int
151 linux_set_osname(struct thread *td, char *osname)
152 {
153         struct linux_prison *lpr;
154
155         KKASSERT(td->td_proc);
156         lpr = get_prison(td);
157         if (lpr != NULL)
158                 strcpy(lpr->pr_osname, osname);
159         else
160                 strcpy(linux_osname, osname);
161
162         return (0);
163 }
164
165 char *
166 linux_get_osrelease(struct thread *td)
167 {
168         struct prison *pr;
169         struct linux_prison *lpr;
170
171         KKASSERT(td->td_proc);
172         pr = td->td_proc->p_ucred->cr_prison;
173         if (pr != NULL && pr->pr_linux != NULL) {
174                 lpr = pr->pr_linux;
175                 if (lpr->pr_osrelease[0])
176                         return (lpr->pr_osrelease);
177         }
178
179         return (linux_osrelease);
180 }
181
182 int
183 linux_set_osrelease(struct thread *td, char *osrelease)
184 {
185         struct linux_prison *lpr;
186
187         lpr = get_prison(td);
188         if (lpr != NULL)
189                 strcpy(lpr->pr_osrelease, osrelease);
190         else
191                 strcpy(linux_osrelease, osrelease);
192
193         return (0);
194 }
195
196 int
197 linux_get_oss_version(struct thread *td)
198 {
199         struct prison *pr;
200         struct linux_prison *lpr;
201
202         KKASSERT(td->td_proc);
203         pr = td->td_proc->p_ucred->cr_prison;
204         if (pr != NULL && pr->pr_linux != NULL) {
205                 lpr = pr->pr_linux;
206                 if (lpr->pr_oss_version)
207                         return (lpr->pr_oss_version);
208         }
209
210         return (linux_oss_version);
211 }
212
213 int
214 linux_set_oss_version(struct thread *td, int oss_version)
215 {
216         struct linux_prison *lpr;
217
218         lpr = get_prison(td);
219         if (lpr != NULL)
220                 lpr->pr_oss_version = oss_version;
221         else
222                 linux_oss_version = oss_version;
223
224         return (0);
225 }
226
227 #ifdef DEBUG
228
229 u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
230
231 static int
232 linux_debug(int syscall, int toggle, int global)
233 {
234
235         if (global) {
236                 char c = toggle ? 0 : 0xff;
237
238                 memset(linux_debug_map, c, sizeof(linux_debug_map));
239                 return (0);
240         }
241         if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
242                 return (EINVAL);
243         if (toggle)
244                 clrbit(linux_debug_map, syscall);
245         else
246                 setbit(linux_debug_map, syscall);
247         return (0);
248 }
249
250 /*
251  * Usage: sysctl -w linux.debug=<syscall_nr>.<0/1>
252  *
253  *    E.g.: sysctl -w linux.debug=21.0
254  *
255  * As a special case, syscall "all" will apply to all syscalls globally.
256  */
257 #define LINUX_MAX_DEBUGSTR      16
258 static int
259 linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
260 {
261         char value[LINUX_MAX_DEBUGSTR], *p;
262         int error, sysc, toggle;
263         int global = 0;
264
265         value[0] = '\0';
266         error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
267         if (error || req->newptr == NULL)
268                 return (error);
269         for (p = value; *p != '\0' && *p != '.'; p++);
270         if (*p == '\0')
271                 return (EINVAL);
272         *p++ = '\0';
273         sysc = strtol(value, NULL, 0);
274         toggle = strtol(p, NULL, 0);
275         if (strcmp(value, "all") == 0)
276                 global = 1;
277         error = linux_debug(sysc, toggle, global);
278         return (error);
279 }
280
281 SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
282             CTLTYPE_STRING | CTLFLAG_RW,
283             0, 0, linux_sysctl_debug, "A",
284             "Linux debugging control");
285
286 #endif /* DEBUG */