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