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