kern_sysctl.c revision 38869
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
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)
86		return (1);
87	if (*pb == NULL)
88		return (-1);
89	return ((*pa)->oid_number - (*pb)->oid_number);
90}
91
92static void
93sysctl_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
135SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
136
137void
138sysctl_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
161static void
162sysctl_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
204static int
205sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
206{
207	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
208	return ENOENT;
209}
210
211SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
212	0, 0, sysctl_sysctl_debug, "-", "");
213
214static int
215sysctl_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
268SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
269
270static int
271sysctl_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
331static int
332sysctl_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
348SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
349
350static int
351name2oid (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
411static int
412sysctl_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
442SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
443	sysctl_sysctl_name2oid, "I", "");
444
445static int
446sysctl_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;
479found:
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
491SYSCTL_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
504int
505sysctl_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
531int
532sysctl_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
558int
559sysctl_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
585int
586sysctl_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
611int
612sysctl_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 */
630static int
631sysctl_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
648static int
649sysctl_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
660int
661kernel_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 */
722static int
723sysctl_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
748static int
749sysctl_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
767int
768sysctl_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;
803found:
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_
830struct 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
840int
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 */
870int
871userland_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
963static 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 */
1000static char bsdi_strings[80];	/* It had better be less than this! */
1001
1002#ifndef _SYS_SYSPROTO_H_
1003struct getkerninfo_args {
1004	int	op;
1005	char	*where;
1006	size_t	*size;
1007	int	arg;
1008};
1009#endif
1010
1011int
1012ogetkerninfo(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