xref: /freebsd/sys/kern/kern_sysctl.c (revision 0640d357f29fb1c0daaaffadd0416c5981413afd)
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.77 1998/09/05 17:13:27 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 && *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 			sprintf(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 integer, 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 an integer, 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 	if (arg1)
539 		error = SYSCTL_OUT(req, arg1, sizeof(long));
540 	else
541 		error = SYSCTL_OUT(req, &arg2, sizeof(long));
542 
543 	if (error || !req->newptr)
544 		return (error);
545 
546 	if (!arg1)
547 		error = EPERM;
548 	else
549 		error = SYSCTL_IN(req, arg1, sizeof(long));
550 	return (error);
551 }
552 
553 /*
554  * Handle an integer, signed or unsigned.
555  * Two cases:
556  *     a variable:  point arg1 at it.
557  *     a constant:  pass it in arg2.
558  */
559 
560 int
561 sysctl_handle_intptr SYSCTL_HANDLER_ARGS
562 {
563 	int error = 0;
564 
565 	if (arg1)
566 		error = SYSCTL_OUT(req, arg1, sizeof(intptr_t));
567 	else
568 		error = SYSCTL_OUT(req, &arg2, sizeof(intptr_t));
569 
570 	if (error || !req->newptr)
571 		return (error);
572 
573 	if (!arg1)
574 		error = EPERM;
575 	else
576 		error = SYSCTL_IN(req, arg1, sizeof(intptr_t));
577 	return (error);
578 }
579 
580 /*
581  * Handle our generic '\0' terminated 'C' string.
582  * Two cases:
583  * 	a variable string:  point arg1 at it, arg2 is max length.
584  * 	a constant string:  point arg1 at it, arg2 is zero.
585  */
586 
587 int
588 sysctl_handle_string SYSCTL_HANDLER_ARGS
589 {
590 	int error=0;
591 
592 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
593 
594 	if (error || !req->newptr || !arg2)
595 		return (error);
596 
597 	if ((req->newlen - req->newidx) > arg2) {
598 		error = E2BIG;
599 	} else {
600 		arg2 = (req->newlen - req->newidx);
601 		error = SYSCTL_IN(req, arg1, arg2);
602 		((char *)arg1)[arg2] = '\0';
603 	}
604 
605 	return (error);
606 }
607 
608 /*
609  * Handle any kind of opaque data.
610  * arg1 points to it, arg2 is the size.
611  */
612 
613 int
614 sysctl_handle_opaque SYSCTL_HANDLER_ARGS
615 {
616 	int error;
617 
618 	error = SYSCTL_OUT(req, arg1, arg2);
619 
620 	if (error || !req->newptr)
621 		return (error);
622 
623 	error = SYSCTL_IN(req, arg1, arg2);
624 
625 	return (error);
626 }
627 
628 /*
629  * Transfer functions to/from kernel space.
630  * XXX: rather untested at this point
631  */
632 static int
633 sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
634 {
635 	size_t i = 0;
636 
637 	if (req->oldptr) {
638 		i = l;
639 		if (i > req->oldlen - req->oldidx)
640 			i = req->oldlen - req->oldidx;
641 		if (i > 0)
642 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
643 	}
644 	req->oldidx += l;
645 	if (req->oldptr && i != l)
646 		return (ENOMEM);
647 	return (0);
648 }
649 
650 static int
651 sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
652 {
653 	if (!req->newptr)
654 		return 0;
655 	if (req->newlen - req->newidx < l)
656 		return (EINVAL);
657 	bcopy((char *)req->newptr + req->newidx, p, l);
658 	req->newidx += l;
659 	return (0);
660 }
661 
662 int
663 kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
664 {
665 	int error = 0;
666 	struct sysctl_req req;
667 
668 	bzero(&req, sizeof req);
669 
670 	req.p = p;
671 
672 	if (oldlenp) {
673 		req.oldlen = *oldlenp;
674 	}
675 
676 	if (old) {
677 		req.oldptr= old;
678 	}
679 
680 	if (newlen) {
681 		req.newlen = newlen;
682 		req.newptr = new;
683 	}
684 
685 	req.oldfunc = sysctl_old_kernel;
686 	req.newfunc = sysctl_new_kernel;
687 	req.lock = 1;
688 
689 	/* XXX this should probably be done in a general way */
690 	while (memlock.sl_lock) {
691 		memlock.sl_want = 1;
692 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
693 		memlock.sl_locked++;
694 	}
695 	memlock.sl_lock = 1;
696 
697 	error = sysctl_root(0, name, namelen, &req);
698 
699 	if (req.lock == 2)
700 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
701 
702 	memlock.sl_lock = 0;
703 
704 	if (memlock.sl_want) {
705 		memlock.sl_want = 0;
706 		wakeup((caddr_t)&memlock);
707 	}
708 
709 	if (error && error != ENOMEM)
710 		return (error);
711 
712 	if (retval) {
713 		if (req.oldptr && req.oldidx > req.oldlen)
714 			*retval = req.oldlen;
715 		else
716 			*retval = req.oldidx;
717 	}
718 	return (error);
719 }
720 
721 /*
722  * Transfer function to/from user space.
723  */
724 static int
725 sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
726 {
727 	int error = 0;
728 	size_t i = 0;
729 
730 	if (req->lock == 1 && req->oldptr) {
731 		vslock(req->oldptr, req->oldlen);
732 		req->lock = 2;
733 	}
734 	if (req->oldptr) {
735 		i = l;
736 		if (i > req->oldlen - req->oldidx)
737 			i = req->oldlen - req->oldidx;
738 		if (i > 0)
739 			error = copyout(p, (char *)req->oldptr + req->oldidx,
740 					i);
741 	}
742 	req->oldidx += l;
743 	if (error)
744 		return (error);
745 	if (req->oldptr && i < l)
746 		return (ENOMEM);
747 	return (0);
748 }
749 
750 static int
751 sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
752 {
753 	int error;
754 
755 	if (!req->newptr)
756 		return 0;
757 	if (req->newlen - req->newidx < l)
758 		return (EINVAL);
759 	error = copyin((char *)req->newptr + req->newidx, p, l);
760 	req->newidx += l;
761 	return (error);
762 }
763 
764 /*
765  * Traverse our tree, and find the right node, execute whatever it points
766  * at, and return the resulting error code.
767  */
768 
769 int
770 sysctl_root SYSCTL_HANDLER_ARGS
771 {
772 	int *name = (int *) arg1;
773 	u_int namelen = arg2;
774 	int indx, i, j;
775 	struct sysctl_oid **oidpp;
776 	struct linker_set *lsp = &sysctl_;
777 
778 	j = lsp->ls_length;
779 	oidpp = (struct sysctl_oid **) lsp->ls_items;
780 
781 	indx = 0;
782 	while (j-- && indx < CTL_MAXNAME) {
783 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
784 			indx++;
785 			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
786 				req->lock = 0;
787 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
788 				if ((*oidpp)->oid_handler)
789 					goto found;
790 				if (indx == namelen)
791 					return ENOENT;
792 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
793 				j = lsp->ls_length;
794 				oidpp = (struct sysctl_oid **)lsp->ls_items;
795 			} else {
796 				if (indx != namelen)
797 					return EISDIR;
798 				goto found;
799 			}
800 		} else {
801 			oidpp++;
802 		}
803 	}
804 	return ENOENT;
805 found:
806 	/* If writing isn't allowed */
807 	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
808 		return (EPERM);
809 
810 	/* Most likely only root can write */
811 	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
812 	    req->newptr && req->p &&
813 	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
814 		return (i);
815 
816 	if (!(*oidpp)->oid_handler)
817 		return EINVAL;
818 
819 	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
820 		i = ((*oidpp)->oid_handler) (*oidpp,
821 					name + indx, namelen - indx,
822 					req);
823 	} else {
824 		i = ((*oidpp)->oid_handler) (*oidpp,
825 					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
826 					req);
827 	}
828 	return (i);
829 }
830 
831 #ifndef _SYS_SYSPROTO_H_
832 struct sysctl_args {
833 	int	*name;
834 	u_int	namelen;
835 	void	*old;
836 	size_t	*oldlenp;
837 	void	*new;
838 	size_t	newlen;
839 };
840 #endif
841 
842 int
843 __sysctl(struct proc *p, struct sysctl_args *uap)
844 {
845 	int error, i, name[CTL_MAXNAME];
846 	size_t j;
847 
848 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
849 		return (EINVAL);
850 
851  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
852  	if (error)
853 		return (error);
854 
855 	error = userland_sysctl(p, name, uap->namelen,
856 		uap->old, uap->oldlenp, 0,
857 		uap->new, uap->newlen, &j);
858 	if (error && error != ENOMEM)
859 		return (error);
860 	if (uap->oldlenp) {
861 		i = copyout(&j, uap->oldlenp, sizeof(j));
862 		if (i)
863 			return (i);
864 	}
865 	return (error);
866 }
867 
868 /*
869  * This is used from various compatibility syscalls too.  That's why name
870  * must be in kernel space.
871  */
872 int
873 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)
874 {
875 	int error = 0;
876 	struct sysctl_req req, req2;
877 
878 	bzero(&req, sizeof req);
879 
880 	req.p = p;
881 
882 	if (oldlenp) {
883 		if (inkernel) {
884 			req.oldlen = *oldlenp;
885 		} else {
886 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
887 			if (error)
888 				return (error);
889 		}
890 	}
891 
892 	if (old) {
893 		if (!useracc(old, req.oldlen, B_WRITE))
894 			return (EFAULT);
895 		req.oldptr= old;
896 	}
897 
898 	if (newlen) {
899 		if (!useracc(new, req.newlen, B_READ))
900 			return (EFAULT);
901 		req.newlen = newlen;
902 		req.newptr = new;
903 	}
904 
905 	req.oldfunc = sysctl_old_user;
906 	req.newfunc = sysctl_new_user;
907 	req.lock = 1;
908 
909 	/* XXX this should probably be done in a general way */
910 	while (memlock.sl_lock) {
911 		memlock.sl_want = 1;
912 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
913 		memlock.sl_locked++;
914 	}
915 	memlock.sl_lock = 1;
916 
917 	do {
918 	    req2 = req;
919 	    error = sysctl_root(0, name, namelen, &req2);
920 	} while (error == EAGAIN);
921 
922 	req = req2;
923 	if (req.lock == 2)
924 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
925 
926 	memlock.sl_lock = 0;
927 
928 	if (memlock.sl_want) {
929 		memlock.sl_want = 0;
930 		wakeup((caddr_t)&memlock);
931 	}
932 
933 	if (error && error != ENOMEM)
934 		return (error);
935 
936 	if (retval) {
937 		if (req.oldptr && req.oldidx > req.oldlen)
938 			*retval = req.oldlen;
939 		else
940 			*retval = req.oldidx;
941 	}
942 	return (error);
943 }
944 
945 #ifdef COMPAT_43
946 #include <sys/socket.h>
947 #include <vm/vm_param.h>
948 
949 #define	KINFO_PROC		(0<<8)
950 #define	KINFO_RT		(1<<8)
951 #define	KINFO_VNODE		(2<<8)
952 #define	KINFO_FILE		(3<<8)
953 #define	KINFO_METER		(4<<8)
954 #define	KINFO_LOADAVG		(5<<8)
955 #define	KINFO_CLOCKRATE		(6<<8)
956 
957 /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
958 #define	KINFO_BSDI_SYSINFO	(101<<8)
959 
960 /*
961  * XXX this is bloat, but I hope it's better here than on the potentially
962  * limited kernel stack...  -Peter
963  */
964 
965 static struct {
966 	int	bsdi_machine;		/* "i386" on BSD/386 */
967 /*      ^^^ this is an offset to the string, relative to the struct start */
968 	char	*pad0;
969 	long	pad1;
970 	long	pad2;
971 	long	pad3;
972 	u_long	pad4;
973 	u_long	pad5;
974 	u_long	pad6;
975 
976 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
977 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
978 	long	pad7;
979 	long	pad8;
980 	char	*pad9;
981 
982 	long	pad10;
983 	long	pad11;
984 	int	pad12;
985 	long	pad13;
986 	quad_t	pad14;
987 	long	pad15;
988 
989 	struct	timeval pad16;
990 	/* we dont set this, because BSDI's uname used gethostname() instead */
991 	int	bsdi_hostname;		/* hostname on BSD/386 */
992 
993 	/* the actual string data is appended here */
994 
995 } bsdi_si;
996 /*
997  * this data is appended to the end of the bsdi_si structure during copyout.
998  * The "char *" offsets are relative to the base of the bsdi_si struct.
999  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1000  * should not exceed the length of the buffer here... (or else!! :-)
1001  */
1002 static char bsdi_strings[80];	/* It had better be less than this! */
1003 
1004 #ifndef _SYS_SYSPROTO_H_
1005 struct getkerninfo_args {
1006 	int	op;
1007 	char	*where;
1008 	size_t	*size;
1009 	int	arg;
1010 };
1011 #endif
1012 
1013 int
1014 ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
1015 {
1016 	int error, name[6];
1017 	size_t size;
1018 
1019 	switch (uap->op & 0xff00) {
1020 
1021 	case KINFO_RT:
1022 		name[0] = CTL_NET;
1023 		name[1] = PF_ROUTE;
1024 		name[2] = 0;
1025 		name[3] = (uap->op & 0xff0000) >> 16;
1026 		name[4] = uap->op & 0xff;
1027 		name[5] = uap->arg;
1028 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
1029 			0, 0, 0, &size);
1030 		break;
1031 
1032 	case KINFO_VNODE:
1033 		name[0] = CTL_KERN;
1034 		name[1] = KERN_VNODE;
1035 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1036 			0, 0, 0, &size);
1037 		break;
1038 
1039 	case KINFO_PROC:
1040 		name[0] = CTL_KERN;
1041 		name[1] = KERN_PROC;
1042 		name[2] = uap->op & 0xff;
1043 		name[3] = uap->arg;
1044 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
1045 			0, 0, 0, &size);
1046 		break;
1047 
1048 	case KINFO_FILE:
1049 		name[0] = CTL_KERN;
1050 		name[1] = KERN_FILE;
1051 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1052 			0, 0, 0, &size);
1053 		break;
1054 
1055 	case KINFO_METER:
1056 		name[0] = CTL_VM;
1057 		name[1] = VM_METER;
1058 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1059 			0, 0, 0, &size);
1060 		break;
1061 
1062 	case KINFO_LOADAVG:
1063 		name[0] = CTL_VM;
1064 		name[1] = VM_LOADAVG;
1065 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1066 			0, 0, 0, &size);
1067 		break;
1068 
1069 	case KINFO_CLOCKRATE:
1070 		name[0] = CTL_KERN;
1071 		name[1] = KERN_CLOCKRATE;
1072 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1073 			0, 0, 0, &size);
1074 		break;
1075 
1076 	case KINFO_BSDI_SYSINFO: {
1077 		/*
1078 		 * this is pretty crude, but it's just enough for uname()
1079 		 * from BSDI's 1.x libc to work.
1080 		 *
1081 		 * In particular, it doesn't return the same results when
1082 		 * the supplied buffer is too small.  BSDI's version apparently
1083 		 * will return the amount copied, and set the *size to how
1084 		 * much was needed.  The emulation framework here isn't capable
1085 		 * of that, so we just set both to the amount copied.
1086 		 * BSDI's 2.x product apparently fails with ENOMEM in this
1087 		 * scenario.
1088 		 */
1089 
1090 		u_int needed;
1091 		u_int left;
1092 		char *s;
1093 
1094 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1095 		bzero(bsdi_strings, sizeof(bsdi_strings));
1096 
1097 		s = bsdi_strings;
1098 
1099 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1100 		strcpy(s, ostype);
1101 		s += strlen(s) + 1;
1102 
1103 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1104 		strcpy(s, osrelease);
1105 		s += strlen(s) + 1;
1106 
1107 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1108 		strcpy(s, machine);
1109 		s += strlen(s) + 1;
1110 
1111 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1112 
1113 		if (uap->where == NULL) {
1114 			/* process is asking how much buffer to supply.. */
1115 			size = needed;
1116 			error = 0;
1117 			break;
1118 		}
1119 
1120 
1121 		/* if too much buffer supplied, trim it down */
1122 		if (size > needed)
1123 			size = needed;
1124 
1125 		/* how much of the buffer is remaining */
1126 		left = size;
1127 
1128 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1129 			break;
1130 
1131 		/* is there any point in continuing? */
1132 		if (left > sizeof(bsdi_si)) {
1133 			left -= sizeof(bsdi_si);
1134 			error = copyout(&bsdi_strings,
1135 					uap->where + sizeof(bsdi_si), left);
1136 		}
1137 		break;
1138 	}
1139 
1140 	default:
1141 		return (EOPNOTSUPP);
1142 	}
1143 	if (error)
1144 		return (error);
1145 	p->p_retval[0] = size;
1146 	if (uap->size)
1147 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1148 		    sizeof(size));
1149 	return (error);
1150 }
1151 #endif /* COMPAT_43 */
1152