xref: /freebsd/sys/kern/kern_sysctl.c (revision 2127f26023a9be443e05b592b35c77b454ba8f77)
1df8bae1dSRodney W. Grimes /*-
2df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1989, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
6df8bae1dSRodney W. Grimes  * Mike Karels at Berkeley Software Design, Inc.
7df8bae1dSRodney W. Grimes  *
8946bb7a2SPoul-Henning Kamp  * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD
9946bb7a2SPoul-Henning Kamp  * project, to make these variables more userfriendly.
10946bb7a2SPoul-Henning Kamp  *
11df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
12df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
13df8bae1dSRodney W. Grimes  * are met:
14df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
16df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
18df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
20df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
21df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
22df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
23df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  *
39df8bae1dSRodney W. Grimes  *	@(#)kern_sysctl.c	8.4 (Berkeley) 4/14/94
402127f260SArchie Cobbs  * $Id: kern_sysctl.c,v 1.78 1998/10/16 03:55:00 peter Exp $
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
435591b823SEivind Eklund #include "opt_compat.h"
445591b823SEivind Eklund 
45df8bae1dSRodney W. Grimes #include <sys/param.h>
464e750649SBruce Evans #include <sys/buf.h>
47df8bae1dSRodney W. Grimes #include <sys/kernel.h>
48df8bae1dSRodney W. Grimes #include <sys/sysctl.h>
49946bb7a2SPoul-Henning Kamp #include <sys/malloc.h>
50efeaf95aSDavid Greenman #include <sys/proc.h>
5145ec3b38SPoul-Henning Kamp #include <sys/systm.h>
5245ec3b38SPoul-Henning Kamp #include <sys/sysproto.h>
534cb03b1bSBruce Evans #include <vm/vm.h>
54efeaf95aSDavid Greenman #include <vm/vm_extern.h>
554cb03b1bSBruce Evans 
56a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_SYSCTL, "sysctl", "sysctl internal magic");
5755166637SPoul-Henning Kamp 
584b2af45fSPoul-Henning Kamp /*
594b2af45fSPoul-Henning Kamp  * Locking and stats
604b2af45fSPoul-Henning Kamp  */
614b2af45fSPoul-Henning Kamp static struct sysctl_lock {
624b2af45fSPoul-Henning Kamp 	int	sl_lock;
634b2af45fSPoul-Henning Kamp 	int	sl_want;
644b2af45fSPoul-Henning Kamp 	int	sl_locked;
654b2af45fSPoul-Henning Kamp } memlock;
664b2af45fSPoul-Henning Kamp 
674b2af45fSPoul-Henning Kamp static int sysctl_root SYSCTL_HANDLER_ARGS;
684b2af45fSPoul-Henning Kamp 
69787d58f2SPoul-Henning Kamp extern struct linker_set sysctl_;
70787d58f2SPoul-Henning Kamp 
71946bb7a2SPoul-Henning Kamp /*
72946bb7a2SPoul-Henning Kamp  * Initialization of the MIB tree.
73946bb7a2SPoul-Henning Kamp  *
74946bb7a2SPoul-Henning Kamp  * Order by number in each linker_set.
75946bb7a2SPoul-Henning Kamp  */
764b2af45fSPoul-Henning Kamp 
77787d58f2SPoul-Henning Kamp static int
783c8e79ddSBruce Evans sysctl_order_cmp(const void *a, const void *b)
79787d58f2SPoul-Henning Kamp {
803f6a052aSBruce Evans 	struct sysctl_oid const * const *pa;
813f6a052aSBruce Evans 	struct sysctl_oid const * const *pb;
823c8e79ddSBruce Evans 
833f6a052aSBruce Evans 	pa = (struct sysctl_oid const * const *)a;
843f6a052aSBruce Evans 	pb = (struct sysctl_oid const * const *)b;
85aa855a59SPeter Wemm 	if (*pa == NULL && *pb == NULL)
86aa855a59SPeter Wemm 		return 0;
873c8e79ddSBruce Evans 	if (*pa == NULL)
883c8e79ddSBruce Evans 		return (1);
893c8e79ddSBruce Evans 	if (*pb == NULL)
903c8e79ddSBruce Evans 		return (-1);
91787d58f2SPoul-Henning Kamp 	return ((*pa)->oid_number - (*pb)->oid_number);
92787d58f2SPoul-Henning Kamp }
93787d58f2SPoul-Henning Kamp 
94787d58f2SPoul-Henning Kamp static void
95787d58f2SPoul-Henning Kamp sysctl_order(void *arg)
96787d58f2SPoul-Henning Kamp {
97946bb7a2SPoul-Henning Kamp 	int j, k;
98787d58f2SPoul-Henning Kamp 	struct linker_set *l = (struct linker_set *) arg;
99787d58f2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
100787d58f2SPoul-Henning Kamp 
101946bb7a2SPoul-Henning Kamp 	/* First, find the highest oid we have */
102946bb7a2SPoul-Henning Kamp 	j = l->ls_length;
103946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
10461220614SPoul-Henning Kamp 	for (k = 0; j--; oidpp++) {
105e99ea9ecSBruce Evans 		if (!*oidpp)
106e99ea9ecSBruce Evans 			continue;
10761220614SPoul-Henning Kamp 		if ((*oidpp)->oid_arg1 == arg) {
10861220614SPoul-Henning Kamp 			*oidpp = 0;
10961220614SPoul-Henning Kamp 			continue;
11061220614SPoul-Henning Kamp 		}
111e99ea9ecSBruce Evans 		if ((*oidpp)->oid_number > k)
112946bb7a2SPoul-Henning Kamp 			k = (*oidpp)->oid_number;
11361220614SPoul-Henning Kamp 	}
114946bb7a2SPoul-Henning Kamp 
115946bb7a2SPoul-Henning Kamp 	/* Next, replace all OID_AUTO oids with new numbers */
116946bb7a2SPoul-Henning Kamp 	j = l->ls_length;
117946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
118946bb7a2SPoul-Henning Kamp 	k += 100;
119946bb7a2SPoul-Henning Kamp 	for (; j--; oidpp++)
120946bb7a2SPoul-Henning Kamp 		if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
121946bb7a2SPoul-Henning Kamp 			(*oidpp)->oid_number = k++;
122946bb7a2SPoul-Henning Kamp 
123946bb7a2SPoul-Henning Kamp 	/* Finally: sort by oid */
124787d58f2SPoul-Henning Kamp 	j = l->ls_length;
125787d58f2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
126787d58f2SPoul-Henning Kamp 	for (; j--; oidpp++) {
127787d58f2SPoul-Henning Kamp 		if (!*oidpp)
128787d58f2SPoul-Henning Kamp 			continue;
129787d58f2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
130787d58f2SPoul-Henning Kamp 			if (!(*oidpp)->oid_handler)
131787d58f2SPoul-Henning Kamp 				sysctl_order((*oidpp)->oid_arg1);
132787d58f2SPoul-Henning Kamp 	}
133787d58f2SPoul-Henning Kamp 	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
134787d58f2SPoul-Henning Kamp 		sysctl_order_cmp);
135787d58f2SPoul-Henning Kamp }
136787d58f2SPoul-Henning Kamp 
137787d58f2SPoul-Henning Kamp SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
138787d58f2SPoul-Henning Kamp 
139e99ea9ecSBruce Evans void
140e99ea9ecSBruce Evans sysctl_order_all(void)
141e99ea9ecSBruce Evans {
142e99ea9ecSBruce Evans 	sysctl_order(&sysctl_);
143e99ea9ecSBruce Evans }
144e99ea9ecSBruce Evans 
145946bb7a2SPoul-Henning Kamp /*
146946bb7a2SPoul-Henning Kamp  * "Staff-functions"
147946bb7a2SPoul-Henning Kamp  *
14865d0bc13SPoul-Henning Kamp  * These functions implement a presently undocumented interface
14965d0bc13SPoul-Henning Kamp  * used by the sysctl program to walk the tree, and get the type
15065d0bc13SPoul-Henning Kamp  * so it can print the value.
15165d0bc13SPoul-Henning Kamp  * This interface is under work and consideration, and should probably
15265d0bc13SPoul-Henning Kamp  * be killed with a big axe by the first person who can find the time.
15365d0bc13SPoul-Henning Kamp  * (be aware though, that the proper interface isn't as obvious as it
15465d0bc13SPoul-Henning Kamp  * may seem, there are various conflicting requirements.
15565d0bc13SPoul-Henning Kamp  *
156946bb7a2SPoul-Henning Kamp  * {0,0}	printf the entire MIB-tree.
157946bb7a2SPoul-Henning Kamp  * {0,1,...}	return the name of the "..." OID.
158946bb7a2SPoul-Henning Kamp  * {0,2,...}	return the next OID.
159946bb7a2SPoul-Henning Kamp  * {0,3}	return the OID of the name in "new"
16065d0bc13SPoul-Henning Kamp  * {0,4,...}	return the kind & format info for the "..." OID.
161946bb7a2SPoul-Henning Kamp  */
162946bb7a2SPoul-Henning Kamp 
163787d58f2SPoul-Henning Kamp static void
164787d58f2SPoul-Henning Kamp sysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
165787d58f2SPoul-Henning Kamp {
166787d58f2SPoul-Henning Kamp 	int j, k;
167787d58f2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
168787d58f2SPoul-Henning Kamp 
169787d58f2SPoul-Henning Kamp 	j = l->ls_length;
170787d58f2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
171787d58f2SPoul-Henning Kamp 	for (; j--; oidpp++) {
172787d58f2SPoul-Henning Kamp 
173787d58f2SPoul-Henning Kamp 		if (!*oidpp)
174787d58f2SPoul-Henning Kamp 			continue;
175787d58f2SPoul-Henning Kamp 
176787d58f2SPoul-Henning Kamp 		for (k=0; k<i; k++)
177787d58f2SPoul-Henning Kamp 			printf(" ");
178787d58f2SPoul-Henning Kamp 
179787d58f2SPoul-Henning Kamp 		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
180787d58f2SPoul-Henning Kamp 
181787d58f2SPoul-Henning Kamp 		printf("%c%c",
182787d58f2SPoul-Henning Kamp 			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
183787d58f2SPoul-Henning Kamp 			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
184787d58f2SPoul-Henning Kamp 
18561220614SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
18661220614SPoul-Henning Kamp 			printf(" *Handler");
18761220614SPoul-Henning Kamp 
188787d58f2SPoul-Henning Kamp 		switch ((*oidpp)->oid_kind & CTLTYPE) {
189787d58f2SPoul-Henning Kamp 			case CTLTYPE_NODE:
190787d58f2SPoul-Henning Kamp 				printf(" Node\n");
19161220614SPoul-Henning Kamp 				if (!(*oidpp)->oid_handler) {
192787d58f2SPoul-Henning Kamp 					sysctl_sysctl_debug_dump_node(
193787d58f2SPoul-Henning Kamp 						(*oidpp)->oid_arg1, i+2);
194787d58f2SPoul-Henning Kamp 				}
195787d58f2SPoul-Henning Kamp 				break;
196787d58f2SPoul-Henning Kamp 			case CTLTYPE_INT:    printf(" Int\n"); break;
197787d58f2SPoul-Henning Kamp 			case CTLTYPE_STRING: printf(" String\n"); break;
198787d58f2SPoul-Henning Kamp 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
199787d58f2SPoul-Henning Kamp 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
200787d58f2SPoul-Henning Kamp 			default:	     printf("\n");
201787d58f2SPoul-Henning Kamp 		}
202787d58f2SPoul-Henning Kamp 
203787d58f2SPoul-Henning Kamp 	}
204787d58f2SPoul-Henning Kamp }
205787d58f2SPoul-Henning Kamp 
206787d58f2SPoul-Henning Kamp static int
207787d58f2SPoul-Henning Kamp sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
208787d58f2SPoul-Henning Kamp {
209787d58f2SPoul-Henning Kamp 	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
210787d58f2SPoul-Henning Kamp 	return ENOENT;
211787d58f2SPoul-Henning Kamp }
212787d58f2SPoul-Henning Kamp 
213787d58f2SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
214946bb7a2SPoul-Henning Kamp 	0, 0, sysctl_sysctl_debug, "-", "");
2152e210993SPoul-Henning Kamp 
216946bb7a2SPoul-Henning Kamp static int
217946bb7a2SPoul-Henning Kamp sysctl_sysctl_name SYSCTL_HANDLER_ARGS
218946bb7a2SPoul-Henning Kamp {
219946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
220946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
221946bb7a2SPoul-Henning Kamp 	int i, j, error = 0;
222946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
223946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
224946bb7a2SPoul-Henning Kamp 	char buf[10];
2252e210993SPoul-Henning Kamp 
226946bb7a2SPoul-Henning Kamp 	while (namelen) {
227946bb7a2SPoul-Henning Kamp 		if (!lsp) {
2282127f260SArchie Cobbs 			snprintf(buf,sizeof(buf),"%d",*name);
229946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
230946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
231946bb7a2SPoul-Henning Kamp 			if (!error)
232946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, buf, strlen(buf));
233946bb7a2SPoul-Henning Kamp 			if (error)
234946bb7a2SPoul-Henning Kamp 				return (error);
235946bb7a2SPoul-Henning Kamp 			namelen--;
236946bb7a2SPoul-Henning Kamp 			name++;
237946bb7a2SPoul-Henning Kamp 			continue;
238946bb7a2SPoul-Henning Kamp 		}
239946bb7a2SPoul-Henning Kamp 		oidpp = (struct sysctl_oid **) lsp->ls_items;
240946bb7a2SPoul-Henning Kamp 		j = lsp->ls_length;
241946bb7a2SPoul-Henning Kamp 		lsp = 0;
242946bb7a2SPoul-Henning Kamp 		for (i = 0; i < j; i++, oidpp++) {
243946bb7a2SPoul-Henning Kamp 			if (*oidpp && ((*oidpp)->oid_number != *name))
244946bb7a2SPoul-Henning Kamp 				continue;
245946bb7a2SPoul-Henning Kamp 
246946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
247946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
248946bb7a2SPoul-Henning Kamp 			if (!error)
249946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, (*oidpp)->oid_name,
250946bb7a2SPoul-Henning Kamp 					strlen((*oidpp)->oid_name));
251946bb7a2SPoul-Henning Kamp 			if (error)
252946bb7a2SPoul-Henning Kamp 				return (error);
253946bb7a2SPoul-Henning Kamp 
254946bb7a2SPoul-Henning Kamp 			namelen--;
255946bb7a2SPoul-Henning Kamp 			name++;
256946bb7a2SPoul-Henning Kamp 
257946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
258946bb7a2SPoul-Henning Kamp 				break;
259946bb7a2SPoul-Henning Kamp 
260946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
261946bb7a2SPoul-Henning Kamp 				break;
262946bb7a2SPoul-Henning Kamp 
263946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
264946bb7a2SPoul-Henning Kamp 			break;
265946bb7a2SPoul-Henning Kamp 		}
266946bb7a2SPoul-Henning Kamp 	}
267946bb7a2SPoul-Henning Kamp 	return (SYSCTL_OUT(req, "", 1));
268946bb7a2SPoul-Henning Kamp }
269946bb7a2SPoul-Henning Kamp 
270946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
271946bb7a2SPoul-Henning Kamp 
272946bb7a2SPoul-Henning Kamp static int
273946bb7a2SPoul-Henning Kamp sysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen,
274946bb7a2SPoul-Henning Kamp 	int *next, int *len, int level, struct sysctl_oid **oidp)
275946bb7a2SPoul-Henning Kamp {
276946bb7a2SPoul-Henning Kamp 	int i, j;
277946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
278946bb7a2SPoul-Henning Kamp 
279946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
280946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
281946bb7a2SPoul-Henning Kamp 	*len = level;
282946bb7a2SPoul-Henning Kamp 	for (i = 0; i < j; i++, oidpp++) {
283946bb7a2SPoul-Henning Kamp 		if (!*oidpp)
284946bb7a2SPoul-Henning Kamp 			continue;
285946bb7a2SPoul-Henning Kamp 
286946bb7a2SPoul-Henning Kamp 		*next = (*oidpp)->oid_number;
287946bb7a2SPoul-Henning Kamp 		*oidp = *oidpp;
288946bb7a2SPoul-Henning Kamp 
289946bb7a2SPoul-Henning Kamp 		if (!namelen) {
290946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
291946bb7a2SPoul-Henning Kamp 				return 0;
292946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
293946bb7a2SPoul-Henning Kamp 				/* We really should call the handler here...*/
294946bb7a2SPoul-Henning Kamp 				return 0;
295946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
29661220614SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
29761220614SPoul-Henning Kamp 				len, level+1, oidp))
29861220614SPoul-Henning Kamp 				return 0;
29961220614SPoul-Henning Kamp 			goto next;
300946bb7a2SPoul-Henning Kamp 		}
301946bb7a2SPoul-Henning Kamp 
302946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_number < *name)
303946bb7a2SPoul-Henning Kamp 			continue;
304946bb7a2SPoul-Henning Kamp 
305946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_number > *name) {
306946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
307946bb7a2SPoul-Henning Kamp 				return 0;
308946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
309946bb7a2SPoul-Henning Kamp 				return 0;
310946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
311946bb7a2SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
312946bb7a2SPoul-Henning Kamp 				next+1, len, level+1, oidp))
313946bb7a2SPoul-Henning Kamp 				return (0);
31461220614SPoul-Henning Kamp 			goto next;
315946bb7a2SPoul-Henning Kamp 		}
316946bb7a2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
317946bb7a2SPoul-Henning Kamp 			continue;
318946bb7a2SPoul-Henning Kamp 
319946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
320946bb7a2SPoul-Henning Kamp 			continue;
321946bb7a2SPoul-Henning Kamp 
322946bb7a2SPoul-Henning Kamp 		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
323946bb7a2SPoul-Henning Kamp 		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
324946bb7a2SPoul-Henning Kamp 			len, level+1, oidp))
325946bb7a2SPoul-Henning Kamp 			return (0);
32661220614SPoul-Henning Kamp 	next:
327946bb7a2SPoul-Henning Kamp 		namelen = 1;
328946bb7a2SPoul-Henning Kamp 		*len = level;
329946bb7a2SPoul-Henning Kamp 	}
330946bb7a2SPoul-Henning Kamp 	return 1;
331946bb7a2SPoul-Henning Kamp }
332946bb7a2SPoul-Henning Kamp 
333946bb7a2SPoul-Henning Kamp static int
334946bb7a2SPoul-Henning Kamp sysctl_sysctl_next SYSCTL_HANDLER_ARGS
335946bb7a2SPoul-Henning Kamp {
336946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
337946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
338946bb7a2SPoul-Henning Kamp 	int i, j, error;
339946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *oid;
340946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
341946bb7a2SPoul-Henning Kamp 	int newoid[CTL_MAXNAME];
342946bb7a2SPoul-Henning Kamp 
343946bb7a2SPoul-Henning Kamp 	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
344946bb7a2SPoul-Henning Kamp 	if (i)
345946bb7a2SPoul-Henning Kamp 		return ENOENT;
346946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
347946bb7a2SPoul-Henning Kamp 	return (error);
348946bb7a2SPoul-Henning Kamp }
349946bb7a2SPoul-Henning Kamp 
350946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
351946bb7a2SPoul-Henning Kamp 
352946bb7a2SPoul-Henning Kamp static int
353946bb7a2SPoul-Henning Kamp name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp)
354946bb7a2SPoul-Henning Kamp {
355946bb7a2SPoul-Henning Kamp 	int i, j;
356946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
357946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
358946bb7a2SPoul-Henning Kamp 	char *p;
359946bb7a2SPoul-Henning Kamp 
360946bb7a2SPoul-Henning Kamp 	if (!*name)
361946bb7a2SPoul-Henning Kamp 		return ENOENT;
362946bb7a2SPoul-Henning Kamp 
363946bb7a2SPoul-Henning Kamp 	p = name + strlen(name) - 1 ;
364946bb7a2SPoul-Henning Kamp 	if (*p == '.')
365946bb7a2SPoul-Henning Kamp 		*p = '\0';
366946bb7a2SPoul-Henning Kamp 
367946bb7a2SPoul-Henning Kamp 	*len = 0;
368946bb7a2SPoul-Henning Kamp 
369946bb7a2SPoul-Henning Kamp 	for (p = name; *p && *p != '.'; p++)
370946bb7a2SPoul-Henning Kamp 		;
371946bb7a2SPoul-Henning Kamp 	i = *p;
372946bb7a2SPoul-Henning Kamp 	if (i == '.')
373946bb7a2SPoul-Henning Kamp 		*p = '\0';
374946bb7a2SPoul-Henning Kamp 
375946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
376946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
377946bb7a2SPoul-Henning Kamp 
378946bb7a2SPoul-Henning Kamp 	while (j-- && *len < CTL_MAXNAME) {
379946bb7a2SPoul-Henning Kamp 		if (!*oidpp)
380946bb7a2SPoul-Henning Kamp 			continue;
381946bb7a2SPoul-Henning Kamp 		if (strcmp(name, (*oidpp)->oid_name)) {
382946bb7a2SPoul-Henning Kamp 			oidpp++;
383946bb7a2SPoul-Henning Kamp 			continue;
384946bb7a2SPoul-Henning Kamp 		}
385946bb7a2SPoul-Henning Kamp 		*oid++ = (*oidpp)->oid_number;
386946bb7a2SPoul-Henning Kamp 		(*len)++;
387946bb7a2SPoul-Henning Kamp 
388946bb7a2SPoul-Henning Kamp 		if (!i) {
389946bb7a2SPoul-Henning Kamp 			if (oidp)
390946bb7a2SPoul-Henning Kamp 				*oidp = *oidpp;
391946bb7a2SPoul-Henning Kamp 			return (0);
392946bb7a2SPoul-Henning Kamp 		}
393946bb7a2SPoul-Henning Kamp 
394946bb7a2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
395946bb7a2SPoul-Henning Kamp 			break;
396946bb7a2SPoul-Henning Kamp 
397946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
398946bb7a2SPoul-Henning Kamp 			break;
399946bb7a2SPoul-Henning Kamp 
400946bb7a2SPoul-Henning Kamp 		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
401946bb7a2SPoul-Henning Kamp 		j = lsp->ls_length;
402946bb7a2SPoul-Henning Kamp 		oidpp = (struct sysctl_oid **)lsp->ls_items;
403946bb7a2SPoul-Henning Kamp 		name = p+1;
404946bb7a2SPoul-Henning Kamp 		for (p = name; *p && *p != '.'; p++)
405946bb7a2SPoul-Henning Kamp 				;
406946bb7a2SPoul-Henning Kamp 		i = *p;
407946bb7a2SPoul-Henning Kamp 		if (i == '.')
408946bb7a2SPoul-Henning Kamp 			*p = '\0';
409946bb7a2SPoul-Henning Kamp 	}
410946bb7a2SPoul-Henning Kamp 	return ENOENT;
411946bb7a2SPoul-Henning Kamp }
412946bb7a2SPoul-Henning Kamp 
413946bb7a2SPoul-Henning Kamp static int
414946bb7a2SPoul-Henning Kamp sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
415946bb7a2SPoul-Henning Kamp {
416946bb7a2SPoul-Henning Kamp 	char *p;
417946bb7a2SPoul-Henning Kamp 	int error, oid[CTL_MAXNAME], len;
418946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *op = 0;
419946bb7a2SPoul-Henning Kamp 
420946bb7a2SPoul-Henning Kamp 	if (!req->newlen)
421946bb7a2SPoul-Henning Kamp 		return ENOENT;
422946bb7a2SPoul-Henning Kamp 
423946bb7a2SPoul-Henning Kamp 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
424946bb7a2SPoul-Henning Kamp 
425946bb7a2SPoul-Henning Kamp 	error = SYSCTL_IN(req, p, req->newlen);
426946bb7a2SPoul-Henning Kamp 	if (error) {
427946bb7a2SPoul-Henning Kamp 		free(p, M_SYSCTL);
428946bb7a2SPoul-Henning Kamp 		return (error);
429946bb7a2SPoul-Henning Kamp 	}
430946bb7a2SPoul-Henning Kamp 
431946bb7a2SPoul-Henning Kamp 	p [req->newlen] = '\0';
432946bb7a2SPoul-Henning Kamp 
433946bb7a2SPoul-Henning Kamp 	error = name2oid(p, oid, &len, &op);
434946bb7a2SPoul-Henning Kamp 
435946bb7a2SPoul-Henning Kamp 	free(p, M_SYSCTL);
436946bb7a2SPoul-Henning Kamp 
437946bb7a2SPoul-Henning Kamp 	if (error)
438946bb7a2SPoul-Henning Kamp 		return (error);
439946bb7a2SPoul-Henning Kamp 
440946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
441946bb7a2SPoul-Henning Kamp 	return (error);
442946bb7a2SPoul-Henning Kamp }
443946bb7a2SPoul-Henning Kamp 
4443ac9f819SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
445946bb7a2SPoul-Henning Kamp 	sysctl_sysctl_name2oid, "I", "");
446946bb7a2SPoul-Henning Kamp 
447946bb7a2SPoul-Henning Kamp static int
448946bb7a2SPoul-Henning Kamp sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
449946bb7a2SPoul-Henning Kamp {
45065d0bc13SPoul-Henning Kamp 	int *name = (int *) arg1, error;
451946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
452946bb7a2SPoul-Henning Kamp 	int indx, j;
453946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
454946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
455946bb7a2SPoul-Henning Kamp 
456946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
457946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
458946bb7a2SPoul-Henning Kamp 
459946bb7a2SPoul-Henning Kamp 	indx = 0;
460946bb7a2SPoul-Henning Kamp 	while (j-- && indx < CTL_MAXNAME) {
461946bb7a2SPoul-Henning Kamp 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
462946bb7a2SPoul-Henning Kamp 			indx++;
463946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
464946bb7a2SPoul-Henning Kamp 				if ((*oidpp)->oid_handler)
465946bb7a2SPoul-Henning Kamp 					goto found;
466946bb7a2SPoul-Henning Kamp 				if (indx == namelen)
46765d0bc13SPoul-Henning Kamp 					goto found;
468946bb7a2SPoul-Henning Kamp 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
469946bb7a2SPoul-Henning Kamp 				j = lsp->ls_length;
470946bb7a2SPoul-Henning Kamp 				oidpp = (struct sysctl_oid **)lsp->ls_items;
471946bb7a2SPoul-Henning Kamp 			} else {
472946bb7a2SPoul-Henning Kamp 				if (indx != namelen)
473946bb7a2SPoul-Henning Kamp 					return EISDIR;
474946bb7a2SPoul-Henning Kamp 				goto found;
475946bb7a2SPoul-Henning Kamp 			}
476946bb7a2SPoul-Henning Kamp 		} else {
477946bb7a2SPoul-Henning Kamp 			oidpp++;
478946bb7a2SPoul-Henning Kamp 		}
479946bb7a2SPoul-Henning Kamp 	}
480946bb7a2SPoul-Henning Kamp 	return ENOENT;
481946bb7a2SPoul-Henning Kamp found:
482946bb7a2SPoul-Henning Kamp 	if (!(*oidpp)->oid_fmt)
483946bb7a2SPoul-Henning Kamp 		return ENOENT;
48465d0bc13SPoul-Henning Kamp 	error = SYSCTL_OUT(req,
48565d0bc13SPoul-Henning Kamp 		&(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind));
48665d0bc13SPoul-Henning Kamp 	if (!error)
48765d0bc13SPoul-Henning Kamp 		error = SYSCTL_OUT(req, (*oidpp)->oid_fmt,
48865d0bc13SPoul-Henning Kamp 			strlen((*oidpp)->oid_fmt)+1);
48965d0bc13SPoul-Henning Kamp 	return (error);
490946bb7a2SPoul-Henning Kamp }
491946bb7a2SPoul-Henning Kamp 
492946bb7a2SPoul-Henning Kamp 
493946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
494946bb7a2SPoul-Henning Kamp 
495946bb7a2SPoul-Henning Kamp /*
496946bb7a2SPoul-Henning Kamp  * Default "handler" functions.
497946bb7a2SPoul-Henning Kamp  */
4982e210993SPoul-Henning Kamp 
499ae0eb976SPoul-Henning Kamp /*
500ae0eb976SPoul-Henning Kamp  * Handle an integer, signed or unsigned.
501ae0eb976SPoul-Henning Kamp  * Two cases:
502ae0eb976SPoul-Henning Kamp  *     a variable:  point arg1 at it.
503ae0eb976SPoul-Henning Kamp  *     a constant:  pass it in arg2.
504ae0eb976SPoul-Henning Kamp  */
505ae0eb976SPoul-Henning Kamp 
5063a34a5c3SPoul-Henning Kamp int
5073a34a5c3SPoul-Henning Kamp sysctl_handle_int SYSCTL_HANDLER_ARGS
508b396cd83SPoul-Henning Kamp {
509ae0eb976SPoul-Henning Kamp 	int error = 0;
510b396cd83SPoul-Henning Kamp 
511ae0eb976SPoul-Henning Kamp 	if (arg1)
512ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, arg1, sizeof(int));
5131fbf1f71SBruce Evans 	else
514ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
515b396cd83SPoul-Henning Kamp 
516ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
517ae0eb976SPoul-Henning Kamp 		return (error);
518b396cd83SPoul-Henning Kamp 
519ae0eb976SPoul-Henning Kamp 	if (!arg1)
520ae0eb976SPoul-Henning Kamp 		error = EPERM;
521ae0eb976SPoul-Henning Kamp 	else
522ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, sizeof(int));
523ae0eb976SPoul-Henning Kamp 	return (error);
524b396cd83SPoul-Henning Kamp }
525b396cd83SPoul-Henning Kamp 
526ae0eb976SPoul-Henning Kamp /*
527069e9bc1SDoug Rabson  * Handle an integer, signed or unsigned.
528069e9bc1SDoug Rabson  * Two cases:
529069e9bc1SDoug Rabson  *     a variable:  point arg1 at it.
530069e9bc1SDoug Rabson  *     a constant:  pass it in arg2.
531069e9bc1SDoug Rabson  */
532069e9bc1SDoug Rabson 
533069e9bc1SDoug Rabson int
534069e9bc1SDoug Rabson sysctl_handle_long SYSCTL_HANDLER_ARGS
535069e9bc1SDoug Rabson {
536069e9bc1SDoug Rabson 	int error = 0;
537069e9bc1SDoug Rabson 
538069e9bc1SDoug Rabson 	if (arg1)
539069e9bc1SDoug Rabson 		error = SYSCTL_OUT(req, arg1, sizeof(long));
540069e9bc1SDoug Rabson 	else
541069e9bc1SDoug Rabson 		error = SYSCTL_OUT(req, &arg2, sizeof(long));
542069e9bc1SDoug Rabson 
543069e9bc1SDoug Rabson 	if (error || !req->newptr)
544069e9bc1SDoug Rabson 		return (error);
545069e9bc1SDoug Rabson 
546069e9bc1SDoug Rabson 	if (!arg1)
547069e9bc1SDoug Rabson 		error = EPERM;
548069e9bc1SDoug Rabson 	else
549069e9bc1SDoug Rabson 		error = SYSCTL_IN(req, arg1, sizeof(long));
550069e9bc1SDoug Rabson 	return (error);
551069e9bc1SDoug Rabson }
552069e9bc1SDoug Rabson 
553069e9bc1SDoug Rabson /*
554069e9bc1SDoug Rabson  * Handle an integer, signed or unsigned.
555069e9bc1SDoug Rabson  * Two cases:
556069e9bc1SDoug Rabson  *     a variable:  point arg1 at it.
557069e9bc1SDoug Rabson  *     a constant:  pass it in arg2.
558069e9bc1SDoug Rabson  */
559069e9bc1SDoug Rabson 
560069e9bc1SDoug Rabson int
561069e9bc1SDoug Rabson sysctl_handle_intptr SYSCTL_HANDLER_ARGS
562069e9bc1SDoug Rabson {
563069e9bc1SDoug Rabson 	int error = 0;
564069e9bc1SDoug Rabson 
565069e9bc1SDoug Rabson 	if (arg1)
566069e9bc1SDoug Rabson 		error = SYSCTL_OUT(req, arg1, sizeof(intptr_t));
567069e9bc1SDoug Rabson 	else
568069e9bc1SDoug Rabson 		error = SYSCTL_OUT(req, &arg2, sizeof(intptr_t));
569069e9bc1SDoug Rabson 
570069e9bc1SDoug Rabson 	if (error || !req->newptr)
571069e9bc1SDoug Rabson 		return (error);
572069e9bc1SDoug Rabson 
573069e9bc1SDoug Rabson 	if (!arg1)
574069e9bc1SDoug Rabson 		error = EPERM;
575069e9bc1SDoug Rabson 	else
576069e9bc1SDoug Rabson 		error = SYSCTL_IN(req, arg1, sizeof(intptr_t));
577069e9bc1SDoug Rabson 	return (error);
578069e9bc1SDoug Rabson }
579069e9bc1SDoug Rabson 
580069e9bc1SDoug Rabson /*
581ae0eb976SPoul-Henning Kamp  * Handle our generic '\0' terminated 'C' string.
582ae0eb976SPoul-Henning Kamp  * Two cases:
583ae0eb976SPoul-Henning Kamp  * 	a variable string:  point arg1 at it, arg2 is max length.
584ae0eb976SPoul-Henning Kamp  * 	a constant string:  point arg1 at it, arg2 is zero.
585ae0eb976SPoul-Henning Kamp  */
586ae0eb976SPoul-Henning Kamp 
5873a34a5c3SPoul-Henning Kamp int
5883a34a5c3SPoul-Henning Kamp sysctl_handle_string SYSCTL_HANDLER_ARGS
589b396cd83SPoul-Henning Kamp {
590ae0eb976SPoul-Henning Kamp 	int error=0;
591b396cd83SPoul-Henning Kamp 
592ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
593b396cd83SPoul-Henning Kamp 
594deae269aSPoul-Henning Kamp 	if (error || !req->newptr || !arg2)
595ae0eb976SPoul-Henning Kamp 		return (error);
596ae0eb976SPoul-Henning Kamp 
597ae0eb976SPoul-Henning Kamp 	if ((req->newlen - req->newidx) > arg2) {
598ae0eb976SPoul-Henning Kamp 		error = E2BIG;
599ae0eb976SPoul-Henning Kamp 	} else {
600ae0eb976SPoul-Henning Kamp 		arg2 = (req->newlen - req->newidx);
601ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, arg2);
602ae0eb976SPoul-Henning Kamp 		((char *)arg1)[arg2] = '\0';
603b396cd83SPoul-Henning Kamp 	}
604b396cd83SPoul-Henning Kamp 
6052e210993SPoul-Henning Kamp 	return (error);
606b396cd83SPoul-Henning Kamp }
607b396cd83SPoul-Henning Kamp 
608ae0eb976SPoul-Henning Kamp /*
609ae0eb976SPoul-Henning Kamp  * Handle any kind of opaque data.
610ae0eb976SPoul-Henning Kamp  * arg1 points to it, arg2 is the size.
611ae0eb976SPoul-Henning Kamp  */
612ae0eb976SPoul-Henning Kamp 
6133a34a5c3SPoul-Henning Kamp int
6143a34a5c3SPoul-Henning Kamp sysctl_handle_opaque SYSCTL_HANDLER_ARGS
615b396cd83SPoul-Henning Kamp {
616ae0eb976SPoul-Henning Kamp 	int error;
617b396cd83SPoul-Henning Kamp 
618ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, arg2);
619b396cd83SPoul-Henning Kamp 
620ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
621ae0eb976SPoul-Henning Kamp 		return (error);
622ae0eb976SPoul-Henning Kamp 
623ae0eb976SPoul-Henning Kamp 	error = SYSCTL_IN(req, arg1, arg2);
624ae0eb976SPoul-Henning Kamp 
625ae0eb976SPoul-Henning Kamp 	return (error);
626b396cd83SPoul-Henning Kamp }
627ae0eb976SPoul-Henning Kamp 
628deae269aSPoul-Henning Kamp /*
629deae269aSPoul-Henning Kamp  * Transfer functions to/from kernel space.
630deae269aSPoul-Henning Kamp  * XXX: rather untested at this point
631deae269aSPoul-Henning Kamp  */
632deae269aSPoul-Henning Kamp static int
633069e9bc1SDoug Rabson sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
634ae0eb976SPoul-Henning Kamp {
635069e9bc1SDoug Rabson 	size_t i = 0;
636deae269aSPoul-Henning Kamp 
637deae269aSPoul-Henning Kamp 	if (req->oldptr) {
638069e9bc1SDoug Rabson 		i = l;
639069e9bc1SDoug Rabson 		if (i > req->oldlen - req->oldidx)
640069e9bc1SDoug Rabson 			i = req->oldlen - req->oldidx;
641deae269aSPoul-Henning Kamp 		if (i > 0)
64209a8dfa2SBruce Evans 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
643ae0eb976SPoul-Henning Kamp 	}
644deae269aSPoul-Henning Kamp 	req->oldidx += l;
6451c346c70SNate Williams 	if (req->oldptr && i != l)
646ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
6472e210993SPoul-Henning Kamp 	return (0);
648ae0eb976SPoul-Henning Kamp }
649ae0eb976SPoul-Henning Kamp 
650deae269aSPoul-Henning Kamp static int
651069e9bc1SDoug Rabson sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
652ae0eb976SPoul-Henning Kamp {
653deae269aSPoul-Henning Kamp 	if (!req->newptr)
654deae269aSPoul-Henning Kamp 		return 0;
655deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
656ae0eb976SPoul-Henning Kamp 		return (EINVAL);
65709a8dfa2SBruce Evans 	bcopy((char *)req->newptr + req->newidx, p, l);
658ae0eb976SPoul-Henning Kamp 	req->newidx += l;
659ae0eb976SPoul-Henning Kamp 	return (0);
660ae0eb976SPoul-Henning Kamp }
661ae0eb976SPoul-Henning Kamp 
6621c346c70SNate Williams int
663069e9bc1SDoug Rabson kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
6641c346c70SNate Williams {
6651c346c70SNate Williams 	int error = 0;
6661c346c70SNate Williams 	struct sysctl_req req;
6671c346c70SNate Williams 
6681c346c70SNate Williams 	bzero(&req, sizeof req);
6691c346c70SNate Williams 
6701c346c70SNate Williams 	req.p = p;
6711c346c70SNate Williams 
6721c346c70SNate Williams 	if (oldlenp) {
6731c346c70SNate Williams 		req.oldlen = *oldlenp;
6741c346c70SNate Williams 	}
6751c346c70SNate Williams 
6761c346c70SNate Williams 	if (old) {
6771c346c70SNate Williams 		req.oldptr= old;
6781c346c70SNate Williams 	}
6791c346c70SNate Williams 
6801c346c70SNate Williams 	if (newlen) {
6811c346c70SNate Williams 		req.newlen = newlen;
6821c346c70SNate Williams 		req.newptr = new;
6831c346c70SNate Williams 	}
6841c346c70SNate Williams 
6851c346c70SNate Williams 	req.oldfunc = sysctl_old_kernel;
6861c346c70SNate Williams 	req.newfunc = sysctl_new_kernel;
6871c346c70SNate Williams 	req.lock = 1;
6881c346c70SNate Williams 
6891c346c70SNate Williams 	/* XXX this should probably be done in a general way */
6901c346c70SNate Williams 	while (memlock.sl_lock) {
6911c346c70SNate Williams 		memlock.sl_want = 1;
6921c346c70SNate Williams 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
6931c346c70SNate Williams 		memlock.sl_locked++;
6941c346c70SNate Williams 	}
6951c346c70SNate Williams 	memlock.sl_lock = 1;
6961c346c70SNate Williams 
6971c346c70SNate Williams 	error = sysctl_root(0, name, namelen, &req);
6981c346c70SNate Williams 
6991c346c70SNate Williams 	if (req.lock == 2)
7001c346c70SNate Williams 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
7011c346c70SNate Williams 
7021c346c70SNate Williams 	memlock.sl_lock = 0;
7031c346c70SNate Williams 
7041c346c70SNate Williams 	if (memlock.sl_want) {
7051c346c70SNate Williams 		memlock.sl_want = 0;
7061c346c70SNate Williams 		wakeup((caddr_t)&memlock);
7071c346c70SNate Williams 	}
7081c346c70SNate Williams 
7091c346c70SNate Williams 	if (error && error != ENOMEM)
7101c346c70SNate Williams 		return (error);
7111c346c70SNate Williams 
7121c346c70SNate Williams 	if (retval) {
7131c346c70SNate Williams 		if (req.oldptr && req.oldidx > req.oldlen)
7141c346c70SNate Williams 			*retval = req.oldlen;
7151c346c70SNate Williams 		else
7161c346c70SNate Williams 			*retval = req.oldidx;
7171c346c70SNate Williams 	}
7181c346c70SNate Williams 	return (error);
7191c346c70SNate Williams }
7201c346c70SNate Williams 
721deae269aSPoul-Henning Kamp /*
722deae269aSPoul-Henning Kamp  * Transfer function to/from user space.
723deae269aSPoul-Henning Kamp  */
724deae269aSPoul-Henning Kamp static int
725069e9bc1SDoug Rabson sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
726ae0eb976SPoul-Henning Kamp {
727069e9bc1SDoug Rabson 	int error = 0;
728069e9bc1SDoug Rabson 	size_t i = 0;
729ae0eb976SPoul-Henning Kamp 
7304b2af45fSPoul-Henning Kamp 	if (req->lock == 1 && req->oldptr) {
7314b2af45fSPoul-Henning Kamp 		vslock(req->oldptr, req->oldlen);
7324b2af45fSPoul-Henning Kamp 		req->lock = 2;
7334b2af45fSPoul-Henning Kamp 	}
734deae269aSPoul-Henning Kamp 	if (req->oldptr) {
735069e9bc1SDoug Rabson 		i = l;
736069e9bc1SDoug Rabson 		if (i > req->oldlen - req->oldidx)
737069e9bc1SDoug Rabson 			i = req->oldlen - req->oldidx;
738deae269aSPoul-Henning Kamp 		if (i > 0)
73909a8dfa2SBruce Evans 			error = copyout(p, (char *)req->oldptr + req->oldidx,
74009a8dfa2SBruce Evans 					i);
741deae269aSPoul-Henning Kamp 	}
742deae269aSPoul-Henning Kamp 	req->oldidx += l;
743ae0eb976SPoul-Henning Kamp 	if (error)
744ae0eb976SPoul-Henning Kamp 		return (error);
745deae269aSPoul-Henning Kamp 	if (req->oldptr && i < l)
746ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
747deae269aSPoul-Henning Kamp 	return (0);
748ae0eb976SPoul-Henning Kamp }
749ae0eb976SPoul-Henning Kamp 
750deae269aSPoul-Henning Kamp static int
751069e9bc1SDoug Rabson sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
752ae0eb976SPoul-Henning Kamp {
75316cd04a3SPoul-Henning Kamp 	int error;
754deae269aSPoul-Henning Kamp 
755deae269aSPoul-Henning Kamp 	if (!req->newptr)
756deae269aSPoul-Henning Kamp 		return 0;
757deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
758ae0eb976SPoul-Henning Kamp 		return (EINVAL);
75909a8dfa2SBruce Evans 	error = copyin((char *)req->newptr + req->newidx, p, l);
760ae0eb976SPoul-Henning Kamp 	req->newidx += l;
761ae0eb976SPoul-Henning Kamp 	return (error);
762b396cd83SPoul-Henning Kamp }
763b396cd83SPoul-Henning Kamp 
764df8bae1dSRodney W. Grimes /*
7652e210993SPoul-Henning Kamp  * Traverse our tree, and find the right node, execute whatever it points
7662e210993SPoul-Henning Kamp  * at, and return the resulting error code.
7672e210993SPoul-Henning Kamp  */
7682e210993SPoul-Henning Kamp 
7692e210993SPoul-Henning Kamp int
7702e210993SPoul-Henning Kamp sysctl_root SYSCTL_HANDLER_ARGS
7712e210993SPoul-Henning Kamp {
7722e210993SPoul-Henning Kamp 	int *name = (int *) arg1;
773946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
7742e210993SPoul-Henning Kamp 	int indx, i, j;
7752e210993SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
7762e210993SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
7772e210993SPoul-Henning Kamp 
7782e210993SPoul-Henning Kamp 	j = lsp->ls_length;
7792e210993SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
7802e210993SPoul-Henning Kamp 
7812e210993SPoul-Henning Kamp 	indx = 0;
7822e210993SPoul-Henning Kamp 	while (j-- && indx < CTL_MAXNAME) {
783787d58f2SPoul-Henning Kamp 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
7842e210993SPoul-Henning Kamp 			indx++;
7854b2af45fSPoul-Henning Kamp 			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
7864b2af45fSPoul-Henning Kamp 				req->lock = 0;
7872e210993SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
7882e210993SPoul-Henning Kamp 				if ((*oidpp)->oid_handler)
7892e210993SPoul-Henning Kamp 					goto found;
7902e210993SPoul-Henning Kamp 				if (indx == namelen)
7912e210993SPoul-Henning Kamp 					return ENOENT;
7922e210993SPoul-Henning Kamp 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
7932e210993SPoul-Henning Kamp 				j = lsp->ls_length;
7942e210993SPoul-Henning Kamp 				oidpp = (struct sysctl_oid **)lsp->ls_items;
7952e210993SPoul-Henning Kamp 			} else {
7962e210993SPoul-Henning Kamp 				if (indx != namelen)
7972e210993SPoul-Henning Kamp 					return EISDIR;
7982e210993SPoul-Henning Kamp 				goto found;
7992e210993SPoul-Henning Kamp 			}
8002e210993SPoul-Henning Kamp 		} else {
8012e210993SPoul-Henning Kamp 			oidpp++;
8022e210993SPoul-Henning Kamp 		}
8032e210993SPoul-Henning Kamp 	}
804deae269aSPoul-Henning Kamp 	return ENOENT;
8052e210993SPoul-Henning Kamp found:
8062e210993SPoul-Henning Kamp 	/* If writing isn't allowed */
807ae0eb976SPoul-Henning Kamp 	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
8082e210993SPoul-Henning Kamp 		return (EPERM);
8092e210993SPoul-Henning Kamp 
8103ac9f819SPoul-Henning Kamp 	/* Most likely only root can write */
8113ac9f819SPoul-Henning Kamp 	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
8123ac9f819SPoul-Henning Kamp 	    req->newptr && req->p &&
8133ac9f819SPoul-Henning Kamp 	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
8143ac9f819SPoul-Henning Kamp 		return (i);
8153ac9f819SPoul-Henning Kamp 
8162e210993SPoul-Henning Kamp 	if (!(*oidpp)->oid_handler)
8172e210993SPoul-Henning Kamp 		return EINVAL;
8182e210993SPoul-Henning Kamp 
8192e210993SPoul-Henning Kamp 	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
8202e210993SPoul-Henning Kamp 		i = ((*oidpp)->oid_handler) (*oidpp,
8212e210993SPoul-Henning Kamp 					name + indx, namelen - indx,
822ae0eb976SPoul-Henning Kamp 					req);
8232e210993SPoul-Henning Kamp 	} else {
8242e210993SPoul-Henning Kamp 		i = ((*oidpp)->oid_handler) (*oidpp,
8252e210993SPoul-Henning Kamp 					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
826ae0eb976SPoul-Henning Kamp 					req);
8272e210993SPoul-Henning Kamp 	}
8282e210993SPoul-Henning Kamp 	return (i);
8292e210993SPoul-Henning Kamp }
8302e210993SPoul-Henning Kamp 
831d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
832b8da2396SPoul-Henning Kamp struct sysctl_args {
833b8da2396SPoul-Henning Kamp 	int	*name;
834b8da2396SPoul-Henning Kamp 	u_int	namelen;
835b8da2396SPoul-Henning Kamp 	void	*old;
836b8da2396SPoul-Henning Kamp 	size_t	*oldlenp;
837b8da2396SPoul-Henning Kamp 	void	*new;
838b8da2396SPoul-Henning Kamp 	size_t	newlen;
839b8da2396SPoul-Henning Kamp };
840d2d3e875SBruce Evans #endif
841b8da2396SPoul-Henning Kamp 
842df8bae1dSRodney W. Grimes int
843cb226aaaSPoul-Henning Kamp __sysctl(struct proc *p, struct sysctl_args *uap)
844df8bae1dSRodney W. Grimes {
845069e9bc1SDoug Rabson 	int error, i, name[CTL_MAXNAME];
846069e9bc1SDoug Rabson 	size_t j;
847b396cd83SPoul-Henning Kamp 
848df8bae1dSRodney W. Grimes 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
849df8bae1dSRodney W. Grimes 		return (EINVAL);
850b396cd83SPoul-Henning Kamp 
851797f2d22SPoul-Henning Kamp  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
852797f2d22SPoul-Henning Kamp  	if (error)
853df8bae1dSRodney W. Grimes 		return (error);
854df8bae1dSRodney W. Grimes 
855deae269aSPoul-Henning Kamp 	error = userland_sysctl(p, name, uap->namelen,
856b8da2396SPoul-Henning Kamp 		uap->old, uap->oldlenp, 0,
857deae269aSPoul-Henning Kamp 		uap->new, uap->newlen, &j);
858deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
859deae269aSPoul-Henning Kamp 		return (error);
860deae269aSPoul-Henning Kamp 	if (uap->oldlenp) {
861deae269aSPoul-Henning Kamp 		i = copyout(&j, uap->oldlenp, sizeof(j));
862deae269aSPoul-Henning Kamp 		if (i)
863deae269aSPoul-Henning Kamp 			return (i);
864deae269aSPoul-Henning Kamp 	}
865deae269aSPoul-Henning Kamp 	return (error);
866b8da2396SPoul-Henning Kamp }
867b8da2396SPoul-Henning Kamp 
868b8da2396SPoul-Henning Kamp /*
869b8da2396SPoul-Henning Kamp  * This is used from various compatibility syscalls too.  That's why name
870b8da2396SPoul-Henning Kamp  * must be in kernel space.
871b8da2396SPoul-Henning Kamp  */
872b8da2396SPoul-Henning Kamp int
873069e9bc1SDoug Rabson userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval)
874b8da2396SPoul-Henning Kamp {
8754b2af45fSPoul-Henning Kamp 	int error = 0;
8767a69d923SPoul-Henning Kamp 	struct sysctl_req req, req2;
877ae0eb976SPoul-Henning Kamp 
878ae0eb976SPoul-Henning Kamp 	bzero(&req, sizeof req);
879b8da2396SPoul-Henning Kamp 
88016cd04a3SPoul-Henning Kamp 	req.p = p;
88116cd04a3SPoul-Henning Kamp 
882b8da2396SPoul-Henning Kamp 	if (oldlenp) {
883b8da2396SPoul-Henning Kamp 		if (inkernel) {
884ae0eb976SPoul-Henning Kamp 			req.oldlen = *oldlenp;
885b8da2396SPoul-Henning Kamp 		} else {
886deae269aSPoul-Henning Kamp 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
887b8da2396SPoul-Henning Kamp 			if (error)
888b8da2396SPoul-Henning Kamp 				return (error);
889b8da2396SPoul-Henning Kamp 		}
890b8da2396SPoul-Henning Kamp 	}
891b8da2396SPoul-Henning Kamp 
892ae0eb976SPoul-Henning Kamp 	if (old) {
893ae0eb976SPoul-Henning Kamp 		if (!useracc(old, req.oldlen, B_WRITE))
894ae0eb976SPoul-Henning Kamp 			return (EFAULT);
895ae0eb976SPoul-Henning Kamp 		req.oldptr= old;
896ae0eb976SPoul-Henning Kamp 	}
8972e210993SPoul-Henning Kamp 
898b8da2396SPoul-Henning Kamp 	if (newlen) {
899ae0eb976SPoul-Henning Kamp 		if (!useracc(new, req.newlen, B_READ))
900ae0eb976SPoul-Henning Kamp 			return (EFAULT);
901ae0eb976SPoul-Henning Kamp 		req.newlen = newlen;
902ae0eb976SPoul-Henning Kamp 		req.newptr = new;
903b396cd83SPoul-Henning Kamp 	}
904b396cd83SPoul-Henning Kamp 
905ae0eb976SPoul-Henning Kamp 	req.oldfunc = sysctl_old_user;
906ae0eb976SPoul-Henning Kamp 	req.newfunc = sysctl_new_user;
9074b2af45fSPoul-Henning Kamp 	req.lock = 1;
9084b2af45fSPoul-Henning Kamp 
9094b2af45fSPoul-Henning Kamp 	/* XXX this should probably be done in a general way */
9104b2af45fSPoul-Henning Kamp 	while (memlock.sl_lock) {
9114b2af45fSPoul-Henning Kamp 		memlock.sl_want = 1;
9124b2af45fSPoul-Henning Kamp 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
9134b2af45fSPoul-Henning Kamp 		memlock.sl_locked++;
9144b2af45fSPoul-Henning Kamp 	}
9154b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 1;
916ae0eb976SPoul-Henning Kamp 
9177a69d923SPoul-Henning Kamp 	do {
9187a69d923SPoul-Henning Kamp 	    req2 = req;
9197a69d923SPoul-Henning Kamp 	    error = sysctl_root(0, name, namelen, &req2);
9207a69d923SPoul-Henning Kamp 	} while (error == EAGAIN);
921b396cd83SPoul-Henning Kamp 
9227a69d923SPoul-Henning Kamp 	req = req2;
9234b2af45fSPoul-Henning Kamp 	if (req.lock == 2)
9244b2af45fSPoul-Henning Kamp 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
9254b2af45fSPoul-Henning Kamp 
9264b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 0;
9274b2af45fSPoul-Henning Kamp 
9284b2af45fSPoul-Henning Kamp 	if (memlock.sl_want) {
9294b2af45fSPoul-Henning Kamp 		memlock.sl_want = 0;
9304b2af45fSPoul-Henning Kamp 		wakeup((caddr_t)&memlock);
9314b2af45fSPoul-Henning Kamp 	}
9324b2af45fSPoul-Henning Kamp 
933deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
934deae269aSPoul-Henning Kamp 		return (error);
935deae269aSPoul-Henning Kamp 
936deae269aSPoul-Henning Kamp 	if (retval) {
937deae269aSPoul-Henning Kamp 		if (req.oldptr && req.oldidx > req.oldlen)
938ae0eb976SPoul-Henning Kamp 			*retval = req.oldlen;
939deae269aSPoul-Henning Kamp 		else
940deae269aSPoul-Henning Kamp 			*retval = req.oldidx;
941b8da2396SPoul-Henning Kamp 	}
9422e210993SPoul-Henning Kamp 	return (error);
943df8bae1dSRodney W. Grimes }
944df8bae1dSRodney W. Grimes 
945df8bae1dSRodney W. Grimes #ifdef COMPAT_43
946df8bae1dSRodney W. Grimes #include <sys/socket.h>
94745ec3b38SPoul-Henning Kamp #include <vm/vm_param.h>
94845ec3b38SPoul-Henning Kamp 
949df8bae1dSRodney W. Grimes #define	KINFO_PROC		(0<<8)
950df8bae1dSRodney W. Grimes #define	KINFO_RT		(1<<8)
951df8bae1dSRodney W. Grimes #define	KINFO_VNODE		(2<<8)
952df8bae1dSRodney W. Grimes #define	KINFO_FILE		(3<<8)
953df8bae1dSRodney W. Grimes #define	KINFO_METER		(4<<8)
954df8bae1dSRodney W. Grimes #define	KINFO_LOADAVG		(5<<8)
955df8bae1dSRodney W. Grimes #define	KINFO_CLOCKRATE		(6<<8)
956df8bae1dSRodney W. Grimes 
9576ece4a51SPeter Wemm /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
9586ece4a51SPeter Wemm #define	KINFO_BSDI_SYSINFO	(101<<8)
9596ece4a51SPeter Wemm 
9606ece4a51SPeter Wemm /*
9616ece4a51SPeter Wemm  * XXX this is bloat, but I hope it's better here than on the potentially
9626ece4a51SPeter Wemm  * limited kernel stack...  -Peter
9636ece4a51SPeter Wemm  */
9646ece4a51SPeter Wemm 
96587b6de2bSPoul-Henning Kamp static struct {
9666ece4a51SPeter Wemm 	int	bsdi_machine;		/* "i386" on BSD/386 */
9676ece4a51SPeter Wemm /*      ^^^ this is an offset to the string, relative to the struct start */
9686ece4a51SPeter Wemm 	char	*pad0;
9696ece4a51SPeter Wemm 	long	pad1;
9706ece4a51SPeter Wemm 	long	pad2;
9716ece4a51SPeter Wemm 	long	pad3;
9726ece4a51SPeter Wemm 	u_long	pad4;
9736ece4a51SPeter Wemm 	u_long	pad5;
9746ece4a51SPeter Wemm 	u_long	pad6;
9756ece4a51SPeter Wemm 
9766ece4a51SPeter Wemm 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
9776ece4a51SPeter Wemm 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
9786ece4a51SPeter Wemm 	long	pad7;
9796ece4a51SPeter Wemm 	long	pad8;
9806ece4a51SPeter Wemm 	char	*pad9;
9816ece4a51SPeter Wemm 
9826ece4a51SPeter Wemm 	long	pad10;
9836ece4a51SPeter Wemm 	long	pad11;
9846ece4a51SPeter Wemm 	int	pad12;
9856ece4a51SPeter Wemm 	long	pad13;
9866ece4a51SPeter Wemm 	quad_t	pad14;
9876ece4a51SPeter Wemm 	long	pad15;
9886ece4a51SPeter Wemm 
9896ece4a51SPeter Wemm 	struct	timeval pad16;
9906ece4a51SPeter Wemm 	/* we dont set this, because BSDI's uname used gethostname() instead */
9916ece4a51SPeter Wemm 	int	bsdi_hostname;		/* hostname on BSD/386 */
9926ece4a51SPeter Wemm 
9936ece4a51SPeter Wemm 	/* the actual string data is appended here */
9946ece4a51SPeter Wemm 
9956ece4a51SPeter Wemm } bsdi_si;
9966ece4a51SPeter Wemm /*
9976ece4a51SPeter Wemm  * this data is appended to the end of the bsdi_si structure during copyout.
9986ece4a51SPeter Wemm  * The "char *" offsets are relative to the base of the bsdi_si struct.
9996ece4a51SPeter Wemm  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
10006ece4a51SPeter Wemm  * should not exceed the length of the buffer here... (or else!! :-)
10016ece4a51SPeter Wemm  */
100287b6de2bSPoul-Henning Kamp static char bsdi_strings[80];	/* It had better be less than this! */
10036ece4a51SPeter Wemm 
1004d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1005df8bae1dSRodney W. Grimes struct getkerninfo_args {
1006df8bae1dSRodney W. Grimes 	int	op;
1007df8bae1dSRodney W. Grimes 	char	*where;
1008134e06feSBruce Evans 	size_t	*size;
1009df8bae1dSRodney W. Grimes 	int	arg;
1010df8bae1dSRodney W. Grimes };
1011d2d3e875SBruce Evans #endif
1012df8bae1dSRodney W. Grimes 
101326f9a767SRodney W. Grimes int
1014cb226aaaSPoul-Henning Kamp ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
1015df8bae1dSRodney W. Grimes {
1016b8da2396SPoul-Henning Kamp 	int error, name[6];
1017069e9bc1SDoug Rabson 	size_t size;
1018df8bae1dSRodney W. Grimes 
1019df8bae1dSRodney W. Grimes 	switch (uap->op & 0xff00) {
1020df8bae1dSRodney W. Grimes 
1021df8bae1dSRodney W. Grimes 	case KINFO_RT:
1022b8da2396SPoul-Henning Kamp 		name[0] = CTL_NET;
1023b8da2396SPoul-Henning Kamp 		name[1] = PF_ROUTE;
1024b8da2396SPoul-Henning Kamp 		name[2] = 0;
1025b8da2396SPoul-Henning Kamp 		name[3] = (uap->op & 0xff0000) >> 16;
1026b8da2396SPoul-Henning Kamp 		name[4] = uap->op & 0xff;
1027b8da2396SPoul-Henning Kamp 		name[5] = uap->arg;
1028b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
10294b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1030df8bae1dSRodney W. Grimes 		break;
1031df8bae1dSRodney W. Grimes 
1032df8bae1dSRodney W. Grimes 	case KINFO_VNODE:
1033b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1034b8da2396SPoul-Henning Kamp 		name[1] = KERN_VNODE;
1035b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10364b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1037df8bae1dSRodney W. Grimes 		break;
1038df8bae1dSRodney W. Grimes 
1039df8bae1dSRodney W. Grimes 	case KINFO_PROC:
1040b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1041b8da2396SPoul-Henning Kamp 		name[1] = KERN_PROC;
1042b8da2396SPoul-Henning Kamp 		name[2] = uap->op & 0xff;
1043b8da2396SPoul-Henning Kamp 		name[3] = uap->arg;
1044b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
10454b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1046df8bae1dSRodney W. Grimes 		break;
1047df8bae1dSRodney W. Grimes 
1048df8bae1dSRodney W. Grimes 	case KINFO_FILE:
1049b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1050b8da2396SPoul-Henning Kamp 		name[1] = KERN_FILE;
1051b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10524b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1053df8bae1dSRodney W. Grimes 		break;
1054df8bae1dSRodney W. Grimes 
1055df8bae1dSRodney W. Grimes 	case KINFO_METER:
1056b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
1057b8da2396SPoul-Henning Kamp 		name[1] = VM_METER;
1058b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10594b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1060df8bae1dSRodney W. Grimes 		break;
1061df8bae1dSRodney W. Grimes 
1062df8bae1dSRodney W. Grimes 	case KINFO_LOADAVG:
1063b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
1064b8da2396SPoul-Henning Kamp 		name[1] = VM_LOADAVG;
1065b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10664b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1067df8bae1dSRodney W. Grimes 		break;
1068df8bae1dSRodney W. Grimes 
1069df8bae1dSRodney W. Grimes 	case KINFO_CLOCKRATE:
1070b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1071b8da2396SPoul-Henning Kamp 		name[1] = KERN_CLOCKRATE;
1072b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10734b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1074df8bae1dSRodney W. Grimes 		break;
1075df8bae1dSRodney W. Grimes 
10766ece4a51SPeter Wemm 	case KINFO_BSDI_SYSINFO: {
10776ece4a51SPeter Wemm 		/*
10786ece4a51SPeter Wemm 		 * this is pretty crude, but it's just enough for uname()
10796ece4a51SPeter Wemm 		 * from BSDI's 1.x libc to work.
10806ece4a51SPeter Wemm 		 *
10816ece4a51SPeter Wemm 		 * In particular, it doesn't return the same results when
10826ece4a51SPeter Wemm 		 * the supplied buffer is too small.  BSDI's version apparently
10836ece4a51SPeter Wemm 		 * will return the amount copied, and set the *size to how
10846ece4a51SPeter Wemm 		 * much was needed.  The emulation framework here isn't capable
10856ece4a51SPeter Wemm 		 * of that, so we just set both to the amount copied.
10866ece4a51SPeter Wemm 		 * BSDI's 2.x product apparently fails with ENOMEM in this
10876ece4a51SPeter Wemm 		 * scenario.
10886ece4a51SPeter Wemm 		 */
10896ece4a51SPeter Wemm 
10906ece4a51SPeter Wemm 		u_int needed;
10916ece4a51SPeter Wemm 		u_int left;
10926ece4a51SPeter Wemm 		char *s;
10936ece4a51SPeter Wemm 
10946ece4a51SPeter Wemm 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
10956ece4a51SPeter Wemm 		bzero(bsdi_strings, sizeof(bsdi_strings));
10966ece4a51SPeter Wemm 
10976ece4a51SPeter Wemm 		s = bsdi_strings;
10986ece4a51SPeter Wemm 
10996ece4a51SPeter Wemm 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
11006ece4a51SPeter Wemm 		strcpy(s, ostype);
11016ece4a51SPeter Wemm 		s += strlen(s) + 1;
11026ece4a51SPeter Wemm 
11036ece4a51SPeter Wemm 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
11046ece4a51SPeter Wemm 		strcpy(s, osrelease);
11056ece4a51SPeter Wemm 		s += strlen(s) + 1;
11066ece4a51SPeter Wemm 
11076ece4a51SPeter Wemm 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
11086ece4a51SPeter Wemm 		strcpy(s, machine);
11096ece4a51SPeter Wemm 		s += strlen(s) + 1;
11106ece4a51SPeter Wemm 
11116ece4a51SPeter Wemm 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
11126ece4a51SPeter Wemm 
11136ece4a51SPeter Wemm 		if (uap->where == NULL) {
11146ece4a51SPeter Wemm 			/* process is asking how much buffer to supply.. */
11156ece4a51SPeter Wemm 			size = needed;
11166ece4a51SPeter Wemm 			error = 0;
11176ece4a51SPeter Wemm 			break;
11186ece4a51SPeter Wemm 		}
11196ece4a51SPeter Wemm 
11206ece4a51SPeter Wemm 
11216ece4a51SPeter Wemm 		/* if too much buffer supplied, trim it down */
11226ece4a51SPeter Wemm 		if (size > needed)
11236ece4a51SPeter Wemm 			size = needed;
11246ece4a51SPeter Wemm 
11256ece4a51SPeter Wemm 		/* how much of the buffer is remaining */
11266ece4a51SPeter Wemm 		left = size;
11276ece4a51SPeter Wemm 
11286ece4a51SPeter Wemm 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
11296ece4a51SPeter Wemm 			break;
11306ece4a51SPeter Wemm 
11316ece4a51SPeter Wemm 		/* is there any point in continuing? */
11326ece4a51SPeter Wemm 		if (left > sizeof(bsdi_si)) {
11336ece4a51SPeter Wemm 			left -= sizeof(bsdi_si);
11346ece4a51SPeter Wemm 			error = copyout(&bsdi_strings,
11356ece4a51SPeter Wemm 					uap->where + sizeof(bsdi_si), left);
11366ece4a51SPeter Wemm 		}
11376ece4a51SPeter Wemm 		break;
11386ece4a51SPeter Wemm 	}
11396ece4a51SPeter Wemm 
1140df8bae1dSRodney W. Grimes 	default:
1141df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1142df8bae1dSRodney W. Grimes 	}
1143df8bae1dSRodney W. Grimes 	if (error)
1144df8bae1dSRodney W. Grimes 		return (error);
1145cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = size;
1146df8bae1dSRodney W. Grimes 	if (uap->size)
1147df8bae1dSRodney W. Grimes 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1148df8bae1dSRodney W. Grimes 		    sizeof(size));
1149df8bae1dSRodney W. Grimes 	return (error);
1150df8bae1dSRodney W. Grimes }
1151df8bae1dSRodney W. Grimes #endif /* COMPAT_43 */
1152