xref: /freebsd/sys/kern/kern_sysctl.c (revision a14a0223ae1b172e96dd2a1d849e22026a98b692)
1 /*-
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Mike Karels at Berkeley Software Design, Inc.
7  *
8  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
9  * project, to make these variables more userfriendly.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
40  * $FreeBSD$
41  */
42 
43 #include "opt_compat.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/buf.h>
49 #include <sys/sysctl.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52 #include <sys/sysproto.h>
53 #include <vm/vm.h>
54 #include <vm/vm_extern.h>
55 
56 static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
57 
58 /*
59  * Locking and stats
60  */
61 static struct sysctl_lock {
62 	int	sl_lock;
63 	int	sl_want;
64 	int	sl_locked;
65 } memlock;
66 
67 static int sysctl_root SYSCTL_HANDLER_ARGS;
68 
69 struct sysctl_oid_list sysctl__children; /* root list */
70 
71 /*
72  * Initialization of the MIB tree.
73  *
74  * Order by number in each list.
75  */
76 
77 void sysctl_register_oid(struct sysctl_oid *oidp)
78 {
79 	struct sysctl_oid_list *parent = oidp->oid_parent;
80 	struct sysctl_oid *p;
81 	struct sysctl_oid *q;
82 	int n;
83 
84 	/*
85 	 * If this oid has a number OID_AUTO, give it a number which
86 	 * is greater than any current oid.  Make sure it is at least
87 	 * 100 to leave space for pre-assigned oid numbers.
88 	 */
89 	if (oidp->oid_number == OID_AUTO) {
90 		/* First, find the highest oid in the parent list >99 */
91 		n = 99;
92 		SLIST_FOREACH(p, parent, oid_link) {
93 			if (p->oid_number > n)
94 				n = p->oid_number;
95 		}
96 		oidp->oid_number = n + 1;
97 	}
98 
99 	/*
100 	 * Insert the oid into the parent's list in order.
101 	 */
102 	q = NULL;
103 	SLIST_FOREACH(p, parent, oid_link) {
104 		if (oidp->oid_number < p->oid_number)
105 			break;
106 		q = p;
107 	}
108 	if (q)
109 		SLIST_INSERT_AFTER(q, oidp, oid_link);
110 	else
111 		SLIST_INSERT_HEAD(parent, oidp, oid_link);
112 }
113 
114 void sysctl_unregister_oid(struct sysctl_oid *oidp)
115 {
116 	SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
117 }
118 
119 /*
120  * Bulk-register all the oids in a linker_set.
121  */
122 void sysctl_register_set(struct linker_set *lsp)
123 {
124 	int count = lsp->ls_length;
125 	int i;
126 	for (i = 0; i < count; i++)
127 		sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
128 }
129 
130 void sysctl_unregister_set(struct linker_set *lsp)
131 {
132 	int count = lsp->ls_length;
133 	int i;
134 	for (i = 0; i < count; i++)
135 		sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
136 }
137 
138 /*
139  * Register the kernel's oids on startup.
140  */
141 extern struct linker_set sysctl_set;
142 
143 static void sysctl_register_all(void *arg)
144 {
145 	sysctl_register_set(&sysctl_set);
146 }
147 
148 SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
149 
150 /*
151  * "Staff-functions"
152  *
153  * These functions implement a presently undocumented interface
154  * used by the sysctl program to walk the tree, and get the type
155  * so it can print the value.
156  * This interface is under work and consideration, and should probably
157  * be killed with a big axe by the first person who can find the time.
158  * (be aware though, that the proper interface isn't as obvious as it
159  * may seem, there are various conflicting requirements.
160  *
161  * {0,0}	printf the entire MIB-tree.
162  * {0,1,...}	return the name of the "..." OID.
163  * {0,2,...}	return the next OID.
164  * {0,3}	return the OID of the name in "new"
165  * {0,4,...}	return the kind & format info for the "..." OID.
166  */
167 
168 static void
169 sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
170 {
171 	int k;
172 	struct sysctl_oid *oidp;
173 
174 	SLIST_FOREACH(oidp, l, oid_link) {
175 
176 		for (k=0; k<i; k++)
177 			printf(" ");
178 
179 		printf("%d %s ", oidp->oid_number, oidp->oid_name);
180 
181 		printf("%c%c",
182 			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
183 			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
184 
185 		if (oidp->oid_handler)
186 			printf(" *Handler");
187 
188 		switch (oidp->oid_kind & CTLTYPE) {
189 			case CTLTYPE_NODE:
190 				printf(" Node\n");
191 				if (!oidp->oid_handler) {
192 					sysctl_sysctl_debug_dump_node(
193 						oidp->oid_arg1, i+2);
194 				}
195 				break;
196 			case CTLTYPE_INT:    printf(" Int\n"); break;
197 			case CTLTYPE_STRING: printf(" String\n"); break;
198 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
199 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
200 			default:	     printf("\n");
201 		}
202 
203 	}
204 }
205 
206 static int
207 sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
208 {
209 	sysctl_sysctl_debug_dump_node(&sysctl__children, 0);
210 	return ENOENT;
211 }
212 
213 SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
214 	0, 0, sysctl_sysctl_debug, "-", "");
215 
216 static int
217 sysctl_sysctl_name SYSCTL_HANDLER_ARGS
218 {
219 	int *name = (int *) arg1;
220 	u_int namelen = arg2;
221 	int error = 0;
222 	struct sysctl_oid *oid;
223 	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
224 	char buf[10];
225 
226 	while (namelen) {
227 		if (!lsp) {
228 			snprintf(buf,sizeof(buf),"%d",*name);
229 			if (req->oldidx)
230 				error = SYSCTL_OUT(req, ".", 1);
231 			if (!error)
232 				error = SYSCTL_OUT(req, buf, strlen(buf));
233 			if (error)
234 				return (error);
235 			namelen--;
236 			name++;
237 			continue;
238 		}
239 		lsp2 = 0;
240 		SLIST_FOREACH(oid, lsp, oid_link) {
241 			if (oid->oid_number != *name)
242 				continue;
243 
244 			if (req->oldidx)
245 				error = SYSCTL_OUT(req, ".", 1);
246 			if (!error)
247 				error = SYSCTL_OUT(req, oid->oid_name,
248 					strlen(oid->oid_name));
249 			if (error)
250 				return (error);
251 
252 			namelen--;
253 			name++;
254 
255 			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
256 				break;
257 
258 			if (oid->oid_handler)
259 				break;
260 
261 			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
262 			break;
263 		}
264 		lsp = lsp2;
265 	}
266 	return (SYSCTL_OUT(req, "", 1));
267 }
268 
269 SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
270 
271 static int
272 sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen,
273 	int *next, int *len, int level, struct sysctl_oid **oidpp)
274 {
275 	struct sysctl_oid *oidp;
276 
277 	*len = level;
278 	SLIST_FOREACH(oidp, lsp, oid_link) {
279 		*next = oidp->oid_number;
280 		*oidpp = oidp;
281 
282 		if (!namelen) {
283 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
284 				return 0;
285 			if (oidp->oid_handler)
286 				/* We really should call the handler here...*/
287 				return 0;
288 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
289 			if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
290 				len, level+1, oidpp))
291 				return 0;
292 			goto next;
293 		}
294 
295 		if (oidp->oid_number < *name)
296 			continue;
297 
298 		if (oidp->oid_number > *name) {
299 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
300 				return 0;
301 			if (oidp->oid_handler)
302 				return 0;
303 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
304 			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
305 				next+1, len, level+1, oidpp))
306 				return (0);
307 			goto next;
308 		}
309 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
310 			continue;
311 
312 		if (oidp->oid_handler)
313 			continue;
314 
315 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
316 		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
317 			len, level+1, oidpp))
318 			return (0);
319 	next:
320 		namelen = 1;
321 		*len = level;
322 	}
323 	return 1;
324 }
325 
326 static int
327 sysctl_sysctl_next SYSCTL_HANDLER_ARGS
328 {
329 	int *name = (int *) arg1;
330 	u_int namelen = arg2;
331 	int i, j, error;
332 	struct sysctl_oid *oid;
333 	struct sysctl_oid_list *lsp = &sysctl__children;
334 	int newoid[CTL_MAXNAME];
335 
336 	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
337 	if (i)
338 		return ENOENT;
339 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
340 	return (error);
341 }
342 
343 SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
344 
345 static int
346 name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
347 {
348 	int i;
349 	struct sysctl_oid *oidp;
350 	struct sysctl_oid_list *lsp = &sysctl__children;
351 	char *p;
352 
353 	if (!*name)
354 		return ENOENT;
355 
356 	p = name + strlen(name) - 1 ;
357 	if (*p == '.')
358 		*p = '\0';
359 
360 	*len = 0;
361 
362 	for (p = name; *p && *p != '.'; p++)
363 		;
364 	i = *p;
365 	if (i == '.')
366 		*p = '\0';
367 
368 	oidp = SLIST_FIRST(lsp);
369 
370 	while (oidp && *len < CTL_MAXNAME) {
371 		if (strcmp(name, oidp->oid_name)) {
372 			oidp = SLIST_NEXT(oidp, oid_link);
373 			continue;
374 		}
375 		*oid++ = oidp->oid_number;
376 		(*len)++;
377 
378 		if (!i) {
379 			if (oidpp)
380 				*oidpp = oidp;
381 			return (0);
382 		}
383 
384 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
385 			break;
386 
387 		if (oidp->oid_handler)
388 			break;
389 
390 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
391 		oidp = SLIST_FIRST(lsp);
392 		name = p+1;
393 		for (p = name; *p && *p != '.'; p++)
394 				;
395 		i = *p;
396 		if (i == '.')
397 			*p = '\0';
398 	}
399 	return ENOENT;
400 }
401 
402 static int
403 sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
404 {
405 	char *p;
406 	int error, oid[CTL_MAXNAME], len;
407 	struct sysctl_oid *op = 0;
408 
409 	if (!req->newlen)
410 		return ENOENT;
411 	if (req->newlen >= MAXPATHLEN)	/* XXX arbitrary, undocumented */
412 		return (ENAMETOOLONG);
413 
414 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
415 
416 	error = SYSCTL_IN(req, p, req->newlen);
417 	if (error) {
418 		free(p, M_SYSCTL);
419 		return (error);
420 	}
421 
422 	p [req->newlen] = '\0';
423 
424 	error = name2oid(p, oid, &len, &op);
425 
426 	free(p, M_SYSCTL);
427 
428 	if (error)
429 		return (error);
430 
431 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
432 	return (error);
433 }
434 
435 SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
436 	sysctl_sysctl_name2oid, "I", "");
437 
438 static int
439 sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
440 {
441 	int *name = (int *) arg1, error;
442 	u_int namelen = arg2;
443 	int indx;
444 	struct sysctl_oid *oid;
445 	struct sysctl_oid_list *lsp = &sysctl__children;
446 
447 	oid = SLIST_FIRST(lsp);
448 
449 	indx = 0;
450 	while (oid && indx < CTL_MAXNAME) {
451 		if (oid->oid_number == name[indx]) {
452 			indx++;
453 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
454 				if (oid->oid_handler)
455 					goto found;
456 				if (indx == namelen)
457 					goto found;
458 				lsp = (struct sysctl_oid_list *)oid->oid_arg1;
459 				oid = SLIST_FIRST(lsp);
460 			} else {
461 				if (indx != namelen)
462 					return EISDIR;
463 				goto found;
464 			}
465 		} else {
466 			oid = SLIST_NEXT(oid, oid_link);
467 		}
468 	}
469 	return ENOENT;
470 found:
471 	if (!oid->oid_fmt)
472 		return ENOENT;
473 	error = SYSCTL_OUT(req,
474 		&oid->oid_kind, sizeof(oid->oid_kind));
475 	if (!error)
476 		error = SYSCTL_OUT(req, oid->oid_fmt,
477 			strlen(oid->oid_fmt)+1);
478 	return (error);
479 }
480 
481 
482 SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
483 
484 /*
485  * Default "handler" functions.
486  */
487 
488 /*
489  * Handle an int, signed or unsigned.
490  * Two cases:
491  *     a variable:  point arg1 at it.
492  *     a constant:  pass it in arg2.
493  */
494 
495 int
496 sysctl_handle_int SYSCTL_HANDLER_ARGS
497 {
498 	int error = 0;
499 
500 	if (arg1)
501 		error = SYSCTL_OUT(req, arg1, sizeof(int));
502 	else
503 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
504 
505 	if (error || !req->newptr)
506 		return (error);
507 
508 	if (!arg1)
509 		error = EPERM;
510 	else
511 		error = SYSCTL_IN(req, arg1, sizeof(int));
512 	return (error);
513 }
514 
515 /*
516  * Handle a long, signed or unsigned.  arg1 points to it.
517  */
518 
519 int
520 sysctl_handle_long SYSCTL_HANDLER_ARGS
521 {
522 	int error = 0;
523 
524 	if (!arg1)
525 		return (EINVAL);
526 	error = SYSCTL_OUT(req, arg1, sizeof(long));
527 
528 	if (error || !req->newptr)
529 		return (error);
530 
531 	error = SYSCTL_IN(req, arg1, sizeof(long));
532 	return (error);
533 }
534 
535 /*
536  * Handle our generic '\0' terminated 'C' string.
537  * Two cases:
538  * 	a variable string:  point arg1 at it, arg2 is max length.
539  * 	a constant string:  point arg1 at it, arg2 is zero.
540  */
541 
542 int
543 sysctl_handle_string SYSCTL_HANDLER_ARGS
544 {
545 	int error=0;
546 
547 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
548 
549 	if (error || !req->newptr)
550 		return (error);
551 
552 	if ((req->newlen - req->newidx) >= arg2) {
553 		error = EINVAL;
554 	} else {
555 		arg2 = (req->newlen - req->newidx);
556 		error = SYSCTL_IN(req, arg1, arg2);
557 		((char *)arg1)[arg2] = '\0';
558 	}
559 
560 	return (error);
561 }
562 
563 /*
564  * Handle any kind of opaque data.
565  * arg1 points to it, arg2 is the size.
566  */
567 
568 int
569 sysctl_handle_opaque SYSCTL_HANDLER_ARGS
570 {
571 	int error;
572 
573 	error = SYSCTL_OUT(req, arg1, arg2);
574 
575 	if (error || !req->newptr)
576 		return (error);
577 
578 	error = SYSCTL_IN(req, arg1, arg2);
579 
580 	return (error);
581 }
582 
583 /*
584  * Transfer functions to/from kernel space.
585  * XXX: rather untested at this point
586  */
587 static int
588 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
589 {
590 	size_t i = 0;
591 
592 	if (req->oldptr) {
593 		i = l;
594 		if (i > req->oldlen - req->oldidx)
595 			i = req->oldlen - req->oldidx;
596 		if (i > 0)
597 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
598 	}
599 	req->oldidx += l;
600 	if (req->oldptr && i != l)
601 		return (ENOMEM);
602 	return (0);
603 }
604 
605 static int
606 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
607 {
608 	if (!req->newptr)
609 		return 0;
610 	if (req->newlen - req->newidx < l)
611 		return (EINVAL);
612 	bcopy((char *)req->newptr + req->newidx, p, l);
613 	req->newidx += l;
614 	return (0);
615 }
616 
617 int
618 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
619 {
620 	int error = 0;
621 	struct sysctl_req req;
622 
623 	bzero(&req, sizeof req);
624 
625 	req.p = p;
626 
627 	if (oldlenp) {
628 		req.oldlen = *oldlenp;
629 	}
630 
631 	if (old) {
632 		req.oldptr= old;
633 	}
634 
635 	if (newlen) {
636 		req.newlen = newlen;
637 		req.newptr = new;
638 	}
639 
640 	req.oldfunc = sysctl_old_kernel;
641 	req.newfunc = sysctl_new_kernel;
642 	req.lock = 1;
643 
644 	/* XXX this should probably be done in a general way */
645 	while (memlock.sl_lock) {
646 		memlock.sl_want = 1;
647 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
648 		memlock.sl_locked++;
649 	}
650 	memlock.sl_lock = 1;
651 
652 	error = sysctl_root(0, name, namelen, &req);
653 
654 	if (req.lock == 2)
655 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
656 
657 	memlock.sl_lock = 0;
658 
659 	if (memlock.sl_want) {
660 		memlock.sl_want = 0;
661 		wakeup((caddr_t)&memlock);
662 	}
663 
664 	if (error && error != ENOMEM)
665 		return (error);
666 
667 	if (retval) {
668 		if (req.oldptr && req.oldidx > req.oldlen)
669 			*retval = req.oldlen;
670 		else
671 			*retval = req.oldidx;
672 	}
673 	return (error);
674 }
675 
676 /*
677  * Transfer function to/from user space.
678  */
679 static int
680 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
681 {
682 	int error = 0;
683 	size_t i = 0;
684 
685 	if (req->lock == 1 && req->oldptr) {
686 		vslock(req->oldptr, req->oldlen);
687 		req->lock = 2;
688 	}
689 	if (req->oldptr) {
690 		i = l;
691 		if (i > req->oldlen - req->oldidx)
692 			i = req->oldlen - req->oldidx;
693 		if (i > 0)
694 			error = copyout(p, (char *)req->oldptr + req->oldidx,
695 					i);
696 	}
697 	req->oldidx += l;
698 	if (error)
699 		return (error);
700 	if (req->oldptr && i < l)
701 		return (ENOMEM);
702 	return (0);
703 }
704 
705 static int
706 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
707 {
708 	int error;
709 
710 	if (!req->newptr)
711 		return 0;
712 	if (req->newlen - req->newidx < l)
713 		return (EINVAL);
714 	error = copyin((char *)req->newptr + req->newidx, p, l);
715 	req->newidx += l;
716 	return (error);
717 }
718 
719 /*
720  * Traverse our tree, and find the right node, execute whatever it points
721  * at, and return the resulting error code.
722  */
723 
724 int
725 sysctl_root SYSCTL_HANDLER_ARGS
726 {
727 	int *name = (int *) arg1;
728 	u_int namelen = arg2;
729 	int indx, i;
730 	struct sysctl_oid *oid;
731 	struct sysctl_oid_list *lsp = &sysctl__children;
732 
733 	oid = SLIST_FIRST(lsp);
734 
735 	indx = 0;
736 	while (oid && indx < CTL_MAXNAME) {
737 		if (oid->oid_number == name[indx]) {
738 			indx++;
739 			if (oid->oid_kind & CTLFLAG_NOLOCK)
740 				req->lock = 0;
741 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
742 				if (oid->oid_handler)
743 					goto found;
744 				if (indx == namelen)
745 					return ENOENT;
746 				lsp = (struct sysctl_oid_list *)oid->oid_arg1;
747 				oid = SLIST_FIRST(lsp);
748 			} else {
749 				if (indx != namelen)
750 					return EISDIR;
751 				goto found;
752 			}
753 		} else {
754 			oid = SLIST_NEXT(oid, oid_link);
755 		}
756 	}
757 	return ENOENT;
758 found:
759 	/* If writing isn't allowed */
760 	if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
761 	    ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
762 		return (EPERM);
763 
764 	/* Most likely only root can write */
765 	if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
766 	    req->newptr && req->p &&
767 	    (i = suser_xxx(0, req->p,
768 	    (oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0)))
769 		return (i);
770 
771 	if (!oid->oid_handler)
772 		return EINVAL;
773 
774 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
775 		i = (oid->oid_handler) (oid,
776 					name + indx, namelen - indx,
777 					req);
778 	} else {
779 		i = (oid->oid_handler) (oid,
780 					oid->oid_arg1, oid->oid_arg2,
781 					req);
782 	}
783 	return (i);
784 }
785 
786 #ifndef _SYS_SYSPROTO_H_
787 struct sysctl_args {
788 	int	*name;
789 	u_int	namelen;
790 	void	*old;
791 	size_t	*oldlenp;
792 	void	*new;
793 	size_t	newlen;
794 };
795 #endif
796 
797 int
798 __sysctl(struct proc *p, struct sysctl_args *uap)
799 {
800 	int error, i, name[CTL_MAXNAME];
801 	size_t j;
802 
803 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
804 		return (EINVAL);
805 
806  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
807  	if (error)
808 		return (error);
809 
810 	error = userland_sysctl(p, name, uap->namelen,
811 		uap->old, uap->oldlenp, 0,
812 		uap->new, uap->newlen, &j);
813 	if (error && error != ENOMEM)
814 		return (error);
815 	if (uap->oldlenp) {
816 		i = copyout(&j, uap->oldlenp, sizeof(j));
817 		if (i)
818 			return (i);
819 	}
820 	return (error);
821 }
822 
823 /*
824  * This is used from various compatibility syscalls too.  That's why name
825  * must be in kernel space.
826  */
827 int
828 userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
829 {
830 	int error = 0;
831 	struct sysctl_req req, req2;
832 
833 	bzero(&req, sizeof req);
834 
835 	req.p = p;
836 
837 	if (oldlenp) {
838 		if (inkernel) {
839 			req.oldlen = *oldlenp;
840 		} else {
841 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
842 			if (error)
843 				return (error);
844 		}
845 	}
846 
847 	if (old) {
848 		if (!useracc(old, req.oldlen, VM_PROT_WRITE))
849 			return (EFAULT);
850 		req.oldptr= old;
851 	}
852 
853 	if (newlen) {
854 		if (!useracc(new, req.newlen, VM_PROT_READ))
855 			return (EFAULT);
856 		req.newlen = newlen;
857 		req.newptr = new;
858 	}
859 
860 	req.oldfunc = sysctl_old_user;
861 	req.newfunc = sysctl_new_user;
862 	req.lock = 1;
863 
864 	/* XXX this should probably be done in a general way */
865 	while (memlock.sl_lock) {
866 		memlock.sl_want = 1;
867 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
868 		memlock.sl_locked++;
869 	}
870 	memlock.sl_lock = 1;
871 
872 	do {
873 	    req2 = req;
874 	    error = sysctl_root(0, name, namelen, &req2);
875 	} while (error == EAGAIN);
876 
877 	req = req2;
878 	if (req.lock == 2)
879 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
880 
881 	memlock.sl_lock = 0;
882 
883 	if (memlock.sl_want) {
884 		memlock.sl_want = 0;
885 		wakeup((caddr_t)&memlock);
886 	}
887 
888 	if (error && error != ENOMEM)
889 		return (error);
890 
891 	if (retval) {
892 		if (req.oldptr && req.oldidx > req.oldlen)
893 			*retval = req.oldlen;
894 		else
895 			*retval = req.oldidx;
896 	}
897 	return (error);
898 }
899 
900 #ifdef COMPAT_43
901 #include <sys/socket.h>
902 #include <vm/vm_param.h>
903 
904 #define	KINFO_PROC		(0<<8)
905 #define	KINFO_RT		(1<<8)
906 #define	KINFO_VNODE		(2<<8)
907 #define	KINFO_FILE		(3<<8)
908 #define	KINFO_METER		(4<<8)
909 #define	KINFO_LOADAVG		(5<<8)
910 #define	KINFO_CLOCKRATE		(6<<8)
911 
912 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
913 #define	KINFO_BSDI_SYSINFO	(101<<8)
914 
915 /*
916  * XXX this is bloat, but I hope it's better here than on the potentially
917  * limited kernel stack...  -Peter
918  */
919 
920 static struct {
921 	int	bsdi_machine;		/* "i386" on BSD/386 */
922 /*      ^^^ this is an offset to the string, relative to the struct start */
923 	char	*pad0;
924 	long	pad1;
925 	long	pad2;
926 	long	pad3;
927 	u_long	pad4;
928 	u_long	pad5;
929 	u_long	pad6;
930 
931 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
932 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
933 	long	pad7;
934 	long	pad8;
935 	char	*pad9;
936 
937 	long	pad10;
938 	long	pad11;
939 	int	pad12;
940 	long	pad13;
941 	quad_t	pad14;
942 	long	pad15;
943 
944 	struct	timeval pad16;
945 	/* we dont set this, because BSDI's uname used gethostname() instead */
946 	int	bsdi_hostname;		/* hostname on BSD/386 */
947 
948 	/* the actual string data is appended here */
949 
950 } bsdi_si;
951 /*
952  * this data is appended to the end of the bsdi_si structure during copyout.
953  * The "char *" offsets are relative to the base of the bsdi_si struct.
954  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
955  * should not exceed the length of the buffer here... (or else!! :-)
956  */
957 static char bsdi_strings[80];	/* It had better be less than this! */
958 
959 #ifndef _SYS_SYSPROTO_H_
960 struct getkerninfo_args {
961 	int	op;
962 	char	*where;
963 	size_t	*size;
964 	int	arg;
965 };
966 #endif
967 
968 int
969 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
970 {
971 	int error, name[6];
972 	size_t size;
973 
974 	switch (uap->op & 0xff00) {
975 
976 	case KINFO_RT:
977 		name[0] = CTL_NET;
978 		name[1] = PF_ROUTE;
979 		name[2] = 0;
980 		name[3] = (uap->op & 0xff0000) >> 16;
981 		name[4] = uap->op & 0xff;
982 		name[5] = uap->arg;
983 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
984 			0, 0, 0, &size);
985 		break;
986 
987 	case KINFO_VNODE:
988 		name[0] = CTL_KERN;
989 		name[1] = KERN_VNODE;
990 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
991 			0, 0, 0, &size);
992 		break;
993 
994 	case KINFO_PROC:
995 		name[0] = CTL_KERN;
996 		name[1] = KERN_PROC;
997 		name[2] = uap->op & 0xff;
998 		name[3] = uap->arg;
999 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
1000 			0, 0, 0, &size);
1001 		break;
1002 
1003 	case KINFO_FILE:
1004 		name[0] = CTL_KERN;
1005 		name[1] = KERN_FILE;
1006 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1007 			0, 0, 0, &size);
1008 		break;
1009 
1010 	case KINFO_METER:
1011 		name[0] = CTL_VM;
1012 		name[1] = VM_METER;
1013 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1014 			0, 0, 0, &size);
1015 		break;
1016 
1017 	case KINFO_LOADAVG:
1018 		name[0] = CTL_VM;
1019 		name[1] = VM_LOADAVG;
1020 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1021 			0, 0, 0, &size);
1022 		break;
1023 
1024 	case KINFO_CLOCKRATE:
1025 		name[0] = CTL_KERN;
1026 		name[1] = KERN_CLOCKRATE;
1027 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1028 			0, 0, 0, &size);
1029 		break;
1030 
1031 	case KINFO_BSDI_SYSINFO: {
1032 		/*
1033 		 * this is pretty crude, but it's just enough for uname()
1034 		 * from BSDI's 1.x libc to work.
1035 		 *
1036 		 * In particular, it doesn't return the same results when
1037 		 * the supplied buffer is too small.  BSDI's version apparently
1038 		 * will return the amount copied, and set the *size to how
1039 		 * much was needed.  The emulation framework here isn't capable
1040 		 * of that, so we just set both to the amount copied.
1041 		 * BSDI's 2.x product apparently fails with ENOMEM in this
1042 		 * scenario.
1043 		 */
1044 
1045 		u_int needed;
1046 		u_int left;
1047 		char *s;
1048 
1049 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1050 		bzero(bsdi_strings, sizeof(bsdi_strings));
1051 
1052 		s = bsdi_strings;
1053 
1054 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1055 		strcpy(s, ostype);
1056 		s += strlen(s) + 1;
1057 
1058 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1059 		strcpy(s, osrelease);
1060 		s += strlen(s) + 1;
1061 
1062 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1063 		strcpy(s, machine);
1064 		s += strlen(s) + 1;
1065 
1066 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1067 
1068 		if (uap->where == NULL) {
1069 			/* process is asking how much buffer to supply.. */
1070 			size = needed;
1071 			error = 0;
1072 			break;
1073 		}
1074 
1075 
1076 		/* if too much buffer supplied, trim it down */
1077 		if (size > needed)
1078 			size = needed;
1079 
1080 		/* how much of the buffer is remaining */
1081 		left = size;
1082 
1083 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1084 			break;
1085 
1086 		/* is there any point in continuing? */
1087 		if (left > sizeof(bsdi_si)) {
1088 			left -= sizeof(bsdi_si);
1089 			error = copyout(&bsdi_strings,
1090 					uap->where + sizeof(bsdi_si), left);
1091 		}
1092 		break;
1093 	}
1094 
1095 	default:
1096 		return (EOPNOTSUPP);
1097 	}
1098 	if (error)
1099 		return (error);
1100 	p->p_retval[0] = size;
1101 	if (uap->size)
1102 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1103 		    sizeof(size));
1104 	return (error);
1105 }
1106 #endif /* COMPAT_43 */
1107