kern_sysctl.c revision 41728
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.79 1998/12/04 22:54:51 archie 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
56static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
57
58/*
59 * Locking and stats
60 */
61static struct sysctl_lock {
62	int	sl_lock;
63	int	sl_want;
64	int	sl_locked;
65} memlock;
66
67static int sysctl_root SYSCTL_HANDLER_ARGS;
68
69extern struct linker_set sysctl_;
70
71/*
72 * Initialization of the MIB tree.
73 *
74 * Order by number in each linker_set.
75 */
76
77static int
78sysctl_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
94static void
95sysctl_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
137SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
138
139void
140sysctl_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
163static void
164sysctl_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
206static int
207sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
208{
209	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
210	return ENOENT;
211}
212
213SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
214	0, 0, sysctl_sysctl_debug, "-", "");
215
216static int
217sysctl_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
270SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
271
272static int
273sysctl_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
333static int
334sysctl_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
350SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
351
352static int
353name2oid (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
413static int
414sysctl_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
444SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
445	sysctl_sysctl_name2oid, "I", "");
446
447static int
448sysctl_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;
481found:
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
493SYSCTL_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
506int
507sysctl_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
533int
534sysctl_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
560int
561sysctl_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
587int
588sysctl_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
613int
614sysctl_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 */
632static int
633sysctl_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
650static int
651sysctl_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
662int
663kernel_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 */
724static int
725sysctl_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
750static int
751sysctl_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
769int
770sysctl_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;
805found:
806	/* If writing isn't allowed */
807	if (req->newptr && (!((*oidpp)->oid_kind & CTLFLAG_WR) ||
808	    (((*oidpp)->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
809		return (EPERM);
810
811	/* Most likely only root can write */
812	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
813	    req->newptr && req->p &&
814	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
815		return (i);
816
817	if (!(*oidpp)->oid_handler)
818		return EINVAL;
819
820	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
821		i = ((*oidpp)->oid_handler) (*oidpp,
822					name + indx, namelen - indx,
823					req);
824	} else {
825		i = ((*oidpp)->oid_handler) (*oidpp,
826					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
827					req);
828	}
829	return (i);
830}
831
832#ifndef _SYS_SYSPROTO_H_
833struct sysctl_args {
834	int	*name;
835	u_int	namelen;
836	void	*old;
837	size_t	*oldlenp;
838	void	*new;
839	size_t	newlen;
840};
841#endif
842
843int
844__sysctl(struct proc *p, struct sysctl_args *uap)
845{
846	int error, i, name[CTL_MAXNAME];
847	size_t j;
848
849	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
850		return (EINVAL);
851
852 	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
853 	if (error)
854		return (error);
855
856	error = userland_sysctl(p, name, uap->namelen,
857		uap->old, uap->oldlenp, 0,
858		uap->new, uap->newlen, &j);
859	if (error && error != ENOMEM)
860		return (error);
861	if (uap->oldlenp) {
862		i = copyout(&j, uap->oldlenp, sizeof(j));
863		if (i)
864			return (i);
865	}
866	return (error);
867}
868
869/*
870 * This is used from various compatibility syscalls too.  That's why name
871 * must be in kernel space.
872 */
873int
874userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
875{
876	int error = 0;
877	struct sysctl_req req, req2;
878
879	bzero(&req, sizeof req);
880
881	req.p = p;
882
883	if (oldlenp) {
884		if (inkernel) {
885			req.oldlen = *oldlenp;
886		} else {
887			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
888			if (error)
889				return (error);
890		}
891	}
892
893	if (old) {
894		if (!useracc(old, req.oldlen, B_WRITE))
895			return (EFAULT);
896		req.oldptr= old;
897	}
898
899	if (newlen) {
900		if (!useracc(new, req.newlen, B_READ))
901			return (EFAULT);
902		req.newlen = newlen;
903		req.newptr = new;
904	}
905
906	req.oldfunc = sysctl_old_user;
907	req.newfunc = sysctl_new_user;
908	req.lock = 1;
909
910	/* XXX this should probably be done in a general way */
911	while (memlock.sl_lock) {
912		memlock.sl_want = 1;
913		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
914		memlock.sl_locked++;
915	}
916	memlock.sl_lock = 1;
917
918	do {
919	    req2 = req;
920	    error = sysctl_root(0, name, namelen, &req2);
921	} while (error == EAGAIN);
922
923	req = req2;
924	if (req.lock == 2)
925		vsunlock(req.oldptr, req.oldlen, B_WRITE);
926
927	memlock.sl_lock = 0;
928
929	if (memlock.sl_want) {
930		memlock.sl_want = 0;
931		wakeup((caddr_t)&memlock);
932	}
933
934	if (error && error != ENOMEM)
935		return (error);
936
937	if (retval) {
938		if (req.oldptr && req.oldidx > req.oldlen)
939			*retval = req.oldlen;
940		else
941			*retval = req.oldidx;
942	}
943	return (error);
944}
945
946#ifdef COMPAT_43
947#include <sys/socket.h>
948#include <vm/vm_param.h>
949
950#define	KINFO_PROC		(0<<8)
951#define	KINFO_RT		(1<<8)
952#define	KINFO_VNODE		(2<<8)
953#define	KINFO_FILE		(3<<8)
954#define	KINFO_METER		(4<<8)
955#define	KINFO_LOADAVG		(5<<8)
956#define	KINFO_CLOCKRATE		(6<<8)
957
958/* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
959#define	KINFO_BSDI_SYSINFO	(101<<8)
960
961/*
962 * XXX this is bloat, but I hope it's better here than on the potentially
963 * limited kernel stack...  -Peter
964 */
965
966static struct {
967	int	bsdi_machine;		/* "i386" on BSD/386 */
968/*      ^^^ this is an offset to the string, relative to the struct start */
969	char	*pad0;
970	long	pad1;
971	long	pad2;
972	long	pad3;
973	u_long	pad4;
974	u_long	pad5;
975	u_long	pad6;
976
977	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
978	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
979	long	pad7;
980	long	pad8;
981	char	*pad9;
982
983	long	pad10;
984	long	pad11;
985	int	pad12;
986	long	pad13;
987	quad_t	pad14;
988	long	pad15;
989
990	struct	timeval pad16;
991	/* we dont set this, because BSDI's uname used gethostname() instead */
992	int	bsdi_hostname;		/* hostname on BSD/386 */
993
994	/* the actual string data is appended here */
995
996} bsdi_si;
997/*
998 * this data is appended to the end of the bsdi_si structure during copyout.
999 * The "char *" offsets are relative to the base of the bsdi_si struct.
1000 * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
1001 * should not exceed the length of the buffer here... (or else!! :-)
1002 */
1003static char bsdi_strings[80];	/* It had better be less than this! */
1004
1005#ifndef _SYS_SYSPROTO_H_
1006struct getkerninfo_args {
1007	int	op;
1008	char	*where;
1009	size_t	*size;
1010	int	arg;
1011};
1012#endif
1013
1014int
1015ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
1016{
1017	int error, name[6];
1018	size_t size;
1019
1020	switch (uap->op & 0xff00) {
1021
1022	case KINFO_RT:
1023		name[0] = CTL_NET;
1024		name[1] = PF_ROUTE;
1025		name[2] = 0;
1026		name[3] = (uap->op & 0xff0000) >> 16;
1027		name[4] = uap->op & 0xff;
1028		name[5] = uap->arg;
1029		error = userland_sysctl(p, name, 6, uap->where, uap->size,
1030			0, 0, 0, &size);
1031		break;
1032
1033	case KINFO_VNODE:
1034		name[0] = CTL_KERN;
1035		name[1] = KERN_VNODE;
1036		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1037			0, 0, 0, &size);
1038		break;
1039
1040	case KINFO_PROC:
1041		name[0] = CTL_KERN;
1042		name[1] = KERN_PROC;
1043		name[2] = uap->op & 0xff;
1044		name[3] = uap->arg;
1045		error = userland_sysctl(p, name, 4, uap->where, uap->size,
1046			0, 0, 0, &size);
1047		break;
1048
1049	case KINFO_FILE:
1050		name[0] = CTL_KERN;
1051		name[1] = KERN_FILE;
1052		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1053			0, 0, 0, &size);
1054		break;
1055
1056	case KINFO_METER:
1057		name[0] = CTL_VM;
1058		name[1] = VM_METER;
1059		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1060			0, 0, 0, &size);
1061		break;
1062
1063	case KINFO_LOADAVG:
1064		name[0] = CTL_VM;
1065		name[1] = VM_LOADAVG;
1066		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1067			0, 0, 0, &size);
1068		break;
1069
1070	case KINFO_CLOCKRATE:
1071		name[0] = CTL_KERN;
1072		name[1] = KERN_CLOCKRATE;
1073		error = userland_sysctl(p, name, 2, uap->where, uap->size,
1074			0, 0, 0, &size);
1075		break;
1076
1077	case KINFO_BSDI_SYSINFO: {
1078		/*
1079		 * this is pretty crude, but it's just enough for uname()
1080		 * from BSDI's 1.x libc to work.
1081		 *
1082		 * In particular, it doesn't return the same results when
1083		 * the supplied buffer is too small.  BSDI's version apparently
1084		 * will return the amount copied, and set the *size to how
1085		 * much was needed.  The emulation framework here isn't capable
1086		 * of that, so we just set both to the amount copied.
1087		 * BSDI's 2.x product apparently fails with ENOMEM in this
1088		 * scenario.
1089		 */
1090
1091		u_int needed;
1092		u_int left;
1093		char *s;
1094
1095		bzero((char *)&bsdi_si, sizeof(bsdi_si));
1096		bzero(bsdi_strings, sizeof(bsdi_strings));
1097
1098		s = bsdi_strings;
1099
1100		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
1101		strcpy(s, ostype);
1102		s += strlen(s) + 1;
1103
1104		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
1105		strcpy(s, osrelease);
1106		s += strlen(s) + 1;
1107
1108		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
1109		strcpy(s, machine);
1110		s += strlen(s) + 1;
1111
1112		needed = sizeof(bsdi_si) + (s - bsdi_strings);
1113
1114		if (uap->where == NULL) {
1115			/* process is asking how much buffer to supply.. */
1116			size = needed;
1117			error = 0;
1118			break;
1119		}
1120
1121
1122		/* if too much buffer supplied, trim it down */
1123		if (size > needed)
1124			size = needed;
1125
1126		/* how much of the buffer is remaining */
1127		left = size;
1128
1129		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
1130			break;
1131
1132		/* is there any point in continuing? */
1133		if (left > sizeof(bsdi_si)) {
1134			left -= sizeof(bsdi_si);
1135			error = copyout(&bsdi_strings,
1136					uap->where + sizeof(bsdi_si), left);
1137		}
1138		break;
1139	}
1140
1141	default:
1142		return (EOPNOTSUPP);
1143	}
1144	if (error)
1145		return (error);
1146	p->p_retval[0] = size;
1147	if (uap->size)
1148		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1149		    sizeof(size));
1150	return (error);
1151}
1152#endif /* COMPAT_43 */
1153