xref: /netbsd/sys/compat/linux/common/linux_sysctl.c (revision c4a72b64)
1 /*	$NetBSD: linux_sysctl.c,v 1.6 2002/11/25 10:34:34 schmonz Exp $	*/
2 
3 /*-
4  * Copyright (c) 1982, 1986, 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Mike Karels at Berkeley Software Design, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)kern_sysctl.c	8.9 (Berkeley) 5/20/95
39  */
40 
41 /*
42  * sysctl system call.
43  */
44 
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: linux_sysctl.c,v 1.6 2002/11/25 10:34:34 schmonz Exp $");
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/errno.h>
51 #include <sys/proc.h>
52 #include <sys/mount.h>
53 #include <sys/sysctl.h>
54 #include <sys/syscallargs.h>
55 
56 #include <compat/linux/common/linux_types.h>
57 #include <compat/linux/common/linux_signal.h>
58 
59 #include <compat/linux/linux_syscallargs.h>
60 #include <compat/linux/common/linux_sysctl.h>
61 #include <compat/linux/common/linux_exec.h>
62 
63 int linux_kern_sysctl(int *, u_int, void *, size_t *, void *, size_t,
64     struct proc *);
65 int linux_vm_sysctl(int *, u_int, void *, size_t *, void *, size_t,
66     struct proc *);
67 int linux_net_sysctl(int *, u_int, void *, size_t *, void *, size_t,
68     struct proc *);
69 int linux_proc_sysctl(int *, u_int, void *, size_t *, void *, size_t,
70     struct proc *);
71 int linux_fs_sysctl(int *, u_int, void *, size_t *, void *, size_t,
72     struct proc *);
73 #ifdef DEBUG
74 int linux_debug_sysctl(int *, u_int, void *, size_t *, void *, size_t,
75     struct proc *);
76 #endif
77 int linux_dev_sysctl(int *, u_int, void *, size_t *, void *, size_t,
78     struct proc *);
79 int linux_bus_sysctl(int *, u_int, void *, size_t *, void *, size_t,
80     struct proc *);
81 
82 int
83 linux_sys___sysctl(struct proc *p, void *v, register_t *retval)
84 {
85 	struct linux_sys___sysctl_args /* {
86 		syscallarg(struct linux___sysctl *) lsp;
87 	} */ *uap = v;
88 	struct linux___sysctl ls;
89 	int error;
90 	size_t savelen = 0, oldlen = 0;
91 	sysctlfn *fn;
92 	int name[CTL_MAXNAME];
93 	size_t *oldlenp;
94 
95 
96 	if ((error = copyin(SCARG(uap, lsp), &ls, sizeof ls)))
97 		return error;
98 	/*
99 	 * all top-level sysctl names are non-terminal
100 	 */
101 	if (ls.nlen > CTL_MAXNAME || ls.nlen < 2)
102 		return (EINVAL);
103 	error = copyin(ls.name, &name, ls.nlen * sizeof(int));
104 	if (error)
105 		return (error);
106 
107 	/*
108 	 * For all but CTL_PROC, must be root to change a value.
109 	 * For CTL_PROC, must be root, or owner of the proc (and not suid),
110 	 * this is checked in proc_sysctl() (once we know the targer proc).
111 	 */
112 	if (ls.newval != NULL && name[0] != CTL_PROC &&
113 		    (error = suser(p->p_ucred, &p->p_acflag)))
114 			return error;
115 
116 	switch (name[0]) {
117 	case LINUX_CTL_KERN:
118 		fn = linux_kern_sysctl;
119 		break;
120 	case LINUX_CTL_VM:
121 		fn = linux_vm_sysctl;
122 		break;
123 	case LINUX_CTL_NET:
124 		fn = linux_net_sysctl;
125 		break;
126 	case LINUX_CTL_PROC:
127 		fn = linux_proc_sysctl;
128 		break;
129 	case LINUX_CTL_FS:
130 		fn = linux_fs_sysctl;
131 		break;
132 #ifdef DEBUG
133 	case LINUX_CTL_DEBUG:
134 		fn = linux_debug_sysctl;
135 		break;
136 #endif
137 	case LINUX_CTL_DEV:
138 		fn = linux_dev_sysctl;
139 		break;
140 	case LINUX_CTL_BUS:
141 		fn = linux_bus_sysctl;
142 		break;
143 	default:
144 		return (EOPNOTSUPP);
145 	}
146 
147 	/*
148 	 * XXX Hey, we wire `oldval', but what about `newval'?
149 	 */
150 	oldlenp = ls.oldlenp;
151 	if (oldlenp) {
152 		if ((error = copyin(oldlenp, &oldlen, sizeof(oldlen))))
153 			return (error);
154 		oldlenp = &oldlen;
155 	}
156 	if (ls.oldval != NULL) {
157 		error = uvm_vslock(p, ls.oldval, oldlen,
158 		    VM_PROT_READ|VM_PROT_WRITE);
159 		savelen = oldlen;
160 	}
161 	error = (*fn)(name + 1, ls.nlen - 1, ls.oldval, oldlenp, ls.newval,
162 	    ls.newlen, p);
163 	if (ls.oldval != NULL)
164 		uvm_vsunlock(p, ls.oldval, savelen);
165 	if (error)
166 		return (error);
167 	if (ls.oldlenp)
168 		error = copyout(&oldlen, ls.oldlenp, sizeof(oldlen));
169 	return (error);
170 }
171 
172 char linux_sysname[128] = "Linux";
173 #if defined(__i386__) || defined(__powerpc__)
174 char linux_release[128] = "2.4.18";
175 char linux_version[128] = "#0 Wed Feb 20 20:00:02 CET 2002";
176 #else
177 char linux_release[128] = "2.0.38";
178 char linux_version[128] = "#0 Sun Nov 11 11:11:11 MET 2000";
179 #endif
180 
181 /*
182  * kernel related system variables.
183  */
184 int
185 linux_kern_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
186     void *newp, size_t newlen, struct proc *p)
187 {
188 	/*
189 	 * Note that we allow writing into this, so that userland
190 	 * programs can setup things as they see fit. This is suboptimal.
191 	 */
192 	switch (name[0]) {
193 	case LINUX_KERN_OSTYPE:
194 		return sysctl_string(oldp, oldlenp, newp, newlen,
195 		    linux_sysname, sizeof(linux_sysname));
196 	case LINUX_KERN_OSRELEASE:
197 		return sysctl_string(oldp, oldlenp, newp, newlen,
198 		    linux_release, sizeof(linux_release));
199 	case LINUX_KERN_VERSION:
200 		return sysctl_string(oldp, oldlenp, newp, newlen,
201 		    linux_version, sizeof(linux_version));
202 	default:
203 		return EOPNOTSUPP;
204 	}
205 }
206 
207 /*
208  * kernel related system variables.
209  */
210 int
211 linux_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
212     void *newp, size_t newlen, struct proc *p)
213 {
214 	if (nlen != 2 || name[0] != EMUL_LINUX_KERN)
215 		return EOPNOTSUPP;
216 
217 	/*
218 	 * Note that we allow writing into this, so that userland
219 	 * programs can setup things as they see fit. This is suboptimal.
220 	 */
221 	switch (name[1]) {
222 	case EMUL_LINUX_KERN_OSTYPE:
223 		return sysctl_string(oldp, oldlenp, newp, newlen,
224 		    linux_sysname, sizeof(linux_sysname));
225 	case EMUL_LINUX_KERN_OSRELEASE:
226 		return sysctl_string(oldp, oldlenp, newp, newlen,
227 		    linux_release, sizeof(linux_release));
228 	case EMUL_LINUX_KERN_VERSION:
229 		return sysctl_string(oldp, oldlenp, newp, newlen,
230 		    linux_version, sizeof(linux_version));
231 	default:
232 		return EOPNOTSUPP;
233 	}
234 }
235 
236 /*
237  * hardware related system variables.
238  */
239 int
240 linux_vm_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
241     void *newp, size_t newlen, struct proc *p)
242 {
243 	return (EOPNOTSUPP);
244 }
245 
246 int
247 linux_net_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
248     void *newp, size_t newlen, struct proc *p)
249 {
250 	return (EOPNOTSUPP);
251 }
252 
253 int
254 linux_proc_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
255     void *newp, size_t newlen, struct proc *p)
256 {
257 	return (EOPNOTSUPP);
258 }
259 
260 int
261 linux_fs_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
262     void *newp, size_t newlen, struct proc *p)
263 {
264 	return (EOPNOTSUPP);
265 }
266 #ifdef DEBUG
267 int
268 linux_debug_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
269     void *newp, size_t newlen, struct proc *p)
270 {
271 	return (EOPNOTSUPP);
272 }
273 #endif /* DEBUG */
274 
275 int
276 linux_dev_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
277     void *newp, size_t newlen, struct proc *p)
278 {
279 	return (EOPNOTSUPP);
280 }
281 
282 int
283 linux_bus_sysctl(int *name, u_int nlen, void *oldp, size_t *oldlenp,
284     void *newp, size_t newlen, struct proc *p)
285 {
286 	return (EOPNOTSUPP);
287 }
288