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