kern_sysctl.c revision 40435
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
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			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
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		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_
832struct 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
842int
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 */
872int
873userland_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
965static 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 */
1002static char bsdi_strings[80];	/* It had better be less than this! */
1003
1004#ifndef _SYS_SYSPROTO_H_
1005struct getkerninfo_args {
1006	int	op;
1007	char	*where;
1008	size_t	*size;
1009	int	arg;
1010};
1011#endif
1012
1013int
1014ogetkerninfo(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