xref: /freebsd/sys/kern/kern_sysctl.c (revision 09a8dfa2609f6be79252c94d3b959ec2cf1a0835)
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
4009a8dfa2SBruce Evans  * $Id: kern_sysctl.c,v 1.64 1996/06/10 16:23:30 nate Exp $
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes #include <sys/param.h>
44df8bae1dSRodney W. Grimes #include <sys/kernel.h>
45df8bae1dSRodney W. Grimes #include <sys/sysctl.h>
46946bb7a2SPoul-Henning Kamp #include <sys/malloc.h>
47efeaf95aSDavid Greenman #include <sys/proc.h>
4845ec3b38SPoul-Henning Kamp #include <sys/systm.h>
4945ec3b38SPoul-Henning Kamp #include <sys/sysproto.h>
504cb03b1bSBruce Evans #include <vm/vm.h>
51efeaf95aSDavid Greenman #include <vm/vm_extern.h>
5245ec3b38SPoul-Henning Kamp #include <sys/vnode.h>
534cb03b1bSBruce Evans 
544b2af45fSPoul-Henning Kamp /*
554b2af45fSPoul-Henning Kamp  * Locking and stats
564b2af45fSPoul-Henning Kamp  */
574b2af45fSPoul-Henning Kamp static struct sysctl_lock {
584b2af45fSPoul-Henning Kamp 	int	sl_lock;
594b2af45fSPoul-Henning Kamp 	int	sl_want;
604b2af45fSPoul-Henning Kamp 	int	sl_locked;
614b2af45fSPoul-Henning Kamp } memlock;
624b2af45fSPoul-Henning Kamp 
634b2af45fSPoul-Henning Kamp static int sysctl_root SYSCTL_HANDLER_ARGS;
644b2af45fSPoul-Henning Kamp 
65787d58f2SPoul-Henning Kamp extern struct linker_set sysctl_;
66787d58f2SPoul-Henning Kamp 
67946bb7a2SPoul-Henning Kamp /*
68946bb7a2SPoul-Henning Kamp  * Initialization of the MIB tree.
69946bb7a2SPoul-Henning Kamp  *
70946bb7a2SPoul-Henning Kamp  * Order by number in each linker_set.
71946bb7a2SPoul-Henning Kamp  */
724b2af45fSPoul-Henning Kamp 
73787d58f2SPoul-Henning Kamp static int
743c8e79ddSBruce Evans sysctl_order_cmp(const void *a, const void *b)
75787d58f2SPoul-Henning Kamp {
763c8e79ddSBruce Evans 	const struct sysctl_oid **pa, **pb;
773c8e79ddSBruce Evans 
783c8e79ddSBruce Evans 	pa = (const struct sysctl_oid **)a;
793c8e79ddSBruce Evans 	pb = (const struct sysctl_oid **)b;
803c8e79ddSBruce Evans 	if (*pa == NULL)
813c8e79ddSBruce Evans 		return (1);
823c8e79ddSBruce Evans 	if (*pb == NULL)
833c8e79ddSBruce Evans 		return (-1);
84787d58f2SPoul-Henning Kamp 	return ((*pa)->oid_number - (*pb)->oid_number);
85787d58f2SPoul-Henning Kamp }
86787d58f2SPoul-Henning Kamp 
87787d58f2SPoul-Henning Kamp static void
88787d58f2SPoul-Henning Kamp sysctl_order(void *arg)
89787d58f2SPoul-Henning Kamp {
90946bb7a2SPoul-Henning Kamp 	int j, k;
91787d58f2SPoul-Henning Kamp 	struct linker_set *l = (struct linker_set *) arg;
92787d58f2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
93787d58f2SPoul-Henning Kamp 
94946bb7a2SPoul-Henning Kamp 	/* First, find the highest oid we have */
95946bb7a2SPoul-Henning Kamp 	j = l->ls_length;
96946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
9761220614SPoul-Henning Kamp 	for (k = 0; j--; oidpp++) {
9861220614SPoul-Henning Kamp 		if ((*oidpp)->oid_arg1 == arg) {
9961220614SPoul-Henning Kamp 			*oidpp = 0;
10061220614SPoul-Henning Kamp 			continue;
10161220614SPoul-Henning Kamp 		}
102946bb7a2SPoul-Henning Kamp 		if (*oidpp && (*oidpp)->oid_number > k)
103946bb7a2SPoul-Henning Kamp 			k = (*oidpp)->oid_number;
10461220614SPoul-Henning Kamp 	}
105946bb7a2SPoul-Henning Kamp 
106946bb7a2SPoul-Henning Kamp 	/* Next, replace all OID_AUTO oids with new numbers */
107946bb7a2SPoul-Henning Kamp 	j = l->ls_length;
108946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
109946bb7a2SPoul-Henning Kamp 	k += 100;
110946bb7a2SPoul-Henning Kamp 	for (; j--; oidpp++)
111946bb7a2SPoul-Henning Kamp 		if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
112946bb7a2SPoul-Henning Kamp 			(*oidpp)->oid_number = k++;
113946bb7a2SPoul-Henning Kamp 
114946bb7a2SPoul-Henning Kamp 	/* Finally: sort by oid */
115787d58f2SPoul-Henning Kamp 	j = l->ls_length;
116787d58f2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
117787d58f2SPoul-Henning Kamp 	for (; j--; oidpp++) {
118787d58f2SPoul-Henning Kamp 		if (!*oidpp)
119787d58f2SPoul-Henning Kamp 			continue;
120787d58f2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
121787d58f2SPoul-Henning Kamp 			if (!(*oidpp)->oid_handler)
122787d58f2SPoul-Henning Kamp 				sysctl_order((*oidpp)->oid_arg1);
123787d58f2SPoul-Henning Kamp 	}
124787d58f2SPoul-Henning Kamp 	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
125787d58f2SPoul-Henning Kamp 		sysctl_order_cmp);
126787d58f2SPoul-Henning Kamp }
127787d58f2SPoul-Henning Kamp 
128787d58f2SPoul-Henning Kamp SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
129787d58f2SPoul-Henning Kamp 
130946bb7a2SPoul-Henning Kamp /*
131946bb7a2SPoul-Henning Kamp  * "Staff-functions"
132946bb7a2SPoul-Henning Kamp  *
13365d0bc13SPoul-Henning Kamp  * These functions implement a presently undocumented interface
13465d0bc13SPoul-Henning Kamp  * used by the sysctl program to walk the tree, and get the type
13565d0bc13SPoul-Henning Kamp  * so it can print the value.
13665d0bc13SPoul-Henning Kamp  * This interface is under work and consideration, and should probably
13765d0bc13SPoul-Henning Kamp  * be killed with a big axe by the first person who can find the time.
13865d0bc13SPoul-Henning Kamp  * (be aware though, that the proper interface isn't as obvious as it
13965d0bc13SPoul-Henning Kamp  * may seem, there are various conflicting requirements.
14065d0bc13SPoul-Henning Kamp  *
141946bb7a2SPoul-Henning Kamp  * {0,0}	printf the entire MIB-tree.
142946bb7a2SPoul-Henning Kamp  * {0,1,...}	return the name of the "..." OID.
143946bb7a2SPoul-Henning Kamp  * {0,2,...}	return the next OID.
144946bb7a2SPoul-Henning Kamp  * {0,3}	return the OID of the name in "new"
14565d0bc13SPoul-Henning Kamp  * {0,4,...}	return the kind & format info for the "..." OID.
146946bb7a2SPoul-Henning Kamp  */
147946bb7a2SPoul-Henning Kamp 
148787d58f2SPoul-Henning Kamp static void
149787d58f2SPoul-Henning Kamp sysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
150787d58f2SPoul-Henning Kamp {
151787d58f2SPoul-Henning Kamp 	int j, k;
152787d58f2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
153787d58f2SPoul-Henning Kamp 
154787d58f2SPoul-Henning Kamp 	j = l->ls_length;
155787d58f2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
156787d58f2SPoul-Henning Kamp 	for (; j--; oidpp++) {
157787d58f2SPoul-Henning Kamp 
158787d58f2SPoul-Henning Kamp 		if (!*oidpp)
159787d58f2SPoul-Henning Kamp 			continue;
160787d58f2SPoul-Henning Kamp 
161787d58f2SPoul-Henning Kamp 		for (k=0; k<i; k++)
162787d58f2SPoul-Henning Kamp 			printf(" ");
163787d58f2SPoul-Henning Kamp 
164787d58f2SPoul-Henning Kamp 		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
165787d58f2SPoul-Henning Kamp 
166787d58f2SPoul-Henning Kamp 		printf("%c%c",
167787d58f2SPoul-Henning Kamp 			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
168787d58f2SPoul-Henning Kamp 			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
169787d58f2SPoul-Henning Kamp 
17061220614SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
17161220614SPoul-Henning Kamp 			printf(" *Handler");
17261220614SPoul-Henning Kamp 
173787d58f2SPoul-Henning Kamp 		switch ((*oidpp)->oid_kind & CTLTYPE) {
174787d58f2SPoul-Henning Kamp 			case CTLTYPE_NODE:
175787d58f2SPoul-Henning Kamp 				printf(" Node\n");
17661220614SPoul-Henning Kamp 				if (!(*oidpp)->oid_handler) {
177787d58f2SPoul-Henning Kamp 					sysctl_sysctl_debug_dump_node(
178787d58f2SPoul-Henning Kamp 						(*oidpp)->oid_arg1, i+2);
179787d58f2SPoul-Henning Kamp 				}
180787d58f2SPoul-Henning Kamp 				break;
181787d58f2SPoul-Henning Kamp 			case CTLTYPE_INT:    printf(" Int\n"); break;
182787d58f2SPoul-Henning Kamp 			case CTLTYPE_STRING: printf(" String\n"); break;
183787d58f2SPoul-Henning Kamp 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
184787d58f2SPoul-Henning Kamp 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
185787d58f2SPoul-Henning Kamp 			default:	     printf("\n");
186787d58f2SPoul-Henning Kamp 		}
187787d58f2SPoul-Henning Kamp 
188787d58f2SPoul-Henning Kamp 	}
189787d58f2SPoul-Henning Kamp }
190787d58f2SPoul-Henning Kamp 
191787d58f2SPoul-Henning Kamp static int
192787d58f2SPoul-Henning Kamp sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
193787d58f2SPoul-Henning Kamp {
194787d58f2SPoul-Henning Kamp 	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
195787d58f2SPoul-Henning Kamp 	return ENOENT;
196787d58f2SPoul-Henning Kamp }
197787d58f2SPoul-Henning Kamp 
198787d58f2SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
199946bb7a2SPoul-Henning Kamp 	0, 0, sysctl_sysctl_debug, "-", "");
2002e210993SPoul-Henning Kamp 
201946bb7a2SPoul-Henning Kamp static int
202946bb7a2SPoul-Henning Kamp sysctl_sysctl_name SYSCTL_HANDLER_ARGS
203946bb7a2SPoul-Henning Kamp {
204946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
205946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
206946bb7a2SPoul-Henning Kamp 	int i, j, error = 0;
207946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
208946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
209946bb7a2SPoul-Henning Kamp 	char buf[10];
2102e210993SPoul-Henning Kamp 
211946bb7a2SPoul-Henning Kamp 	while (namelen) {
212946bb7a2SPoul-Henning Kamp 		if (!lsp) {
213946bb7a2SPoul-Henning Kamp 			sprintf(buf,"%d",*name);
214946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
215946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
216946bb7a2SPoul-Henning Kamp 			if (!error)
217946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, buf, strlen(buf));
218946bb7a2SPoul-Henning Kamp 			if (error)
219946bb7a2SPoul-Henning Kamp 				return (error);
220946bb7a2SPoul-Henning Kamp 			namelen--;
221946bb7a2SPoul-Henning Kamp 			name++;
222946bb7a2SPoul-Henning Kamp 			continue;
223946bb7a2SPoul-Henning Kamp 		}
224946bb7a2SPoul-Henning Kamp 		oidpp = (struct sysctl_oid **) lsp->ls_items;
225946bb7a2SPoul-Henning Kamp 		j = lsp->ls_length;
226946bb7a2SPoul-Henning Kamp 		lsp = 0;
227946bb7a2SPoul-Henning Kamp 		for (i = 0; i < j; i++, oidpp++) {
228946bb7a2SPoul-Henning Kamp 			if (*oidpp && ((*oidpp)->oid_number != *name))
229946bb7a2SPoul-Henning Kamp 				continue;
230946bb7a2SPoul-Henning Kamp 
231946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
232946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
233946bb7a2SPoul-Henning Kamp 			if (!error)
234946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, (*oidpp)->oid_name,
235946bb7a2SPoul-Henning Kamp 					strlen((*oidpp)->oid_name));
236946bb7a2SPoul-Henning Kamp 			if (error)
237946bb7a2SPoul-Henning Kamp 				return (error);
238946bb7a2SPoul-Henning Kamp 
239946bb7a2SPoul-Henning Kamp 			namelen--;
240946bb7a2SPoul-Henning Kamp 			name++;
241946bb7a2SPoul-Henning Kamp 
242946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
243946bb7a2SPoul-Henning Kamp 				break;
244946bb7a2SPoul-Henning Kamp 
245946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
246946bb7a2SPoul-Henning Kamp 				break;
247946bb7a2SPoul-Henning Kamp 
248946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
249946bb7a2SPoul-Henning Kamp 			break;
250946bb7a2SPoul-Henning Kamp 		}
251946bb7a2SPoul-Henning Kamp 	}
252946bb7a2SPoul-Henning Kamp 	return (SYSCTL_OUT(req, "", 1));
253946bb7a2SPoul-Henning Kamp }
254946bb7a2SPoul-Henning Kamp 
255946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
256946bb7a2SPoul-Henning Kamp 
257946bb7a2SPoul-Henning Kamp static int
258946bb7a2SPoul-Henning Kamp sysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen,
259946bb7a2SPoul-Henning Kamp 	int *next, int *len, int level, struct sysctl_oid **oidp)
260946bb7a2SPoul-Henning Kamp {
261946bb7a2SPoul-Henning Kamp 	int i, j;
262946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
263946bb7a2SPoul-Henning Kamp 
264946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
265946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
266946bb7a2SPoul-Henning Kamp 	*len = level;
267946bb7a2SPoul-Henning Kamp 	for (i = 0; i < j; i++, oidpp++) {
268946bb7a2SPoul-Henning Kamp 		if (!*oidpp)
269946bb7a2SPoul-Henning Kamp 			continue;
270946bb7a2SPoul-Henning Kamp 
271946bb7a2SPoul-Henning Kamp 		*next = (*oidpp)->oid_number;
272946bb7a2SPoul-Henning Kamp 		*oidp = *oidpp;
273946bb7a2SPoul-Henning Kamp 
274946bb7a2SPoul-Henning Kamp 		if (!namelen) {
275946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
276946bb7a2SPoul-Henning Kamp 				return 0;
277946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
278946bb7a2SPoul-Henning Kamp 				/* We really should call the handler here...*/
279946bb7a2SPoul-Henning Kamp 				return 0;
280946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
28161220614SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
28261220614SPoul-Henning Kamp 				len, level+1, oidp))
28361220614SPoul-Henning Kamp 				return 0;
28461220614SPoul-Henning Kamp 			goto next;
285946bb7a2SPoul-Henning Kamp 		}
286946bb7a2SPoul-Henning Kamp 
287946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_number < *name)
288946bb7a2SPoul-Henning Kamp 			continue;
289946bb7a2SPoul-Henning Kamp 
290946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_number > *name) {
291946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
292946bb7a2SPoul-Henning Kamp 				return 0;
293946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
294946bb7a2SPoul-Henning Kamp 				return 0;
295946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
296946bb7a2SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
297946bb7a2SPoul-Henning Kamp 				next+1, len, level+1, oidp))
298946bb7a2SPoul-Henning Kamp 				return (0);
29961220614SPoul-Henning Kamp 			goto next;
300946bb7a2SPoul-Henning Kamp 		}
301946bb7a2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
302946bb7a2SPoul-Henning Kamp 			continue;
303946bb7a2SPoul-Henning Kamp 
304946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
305946bb7a2SPoul-Henning Kamp 			continue;
306946bb7a2SPoul-Henning Kamp 
307946bb7a2SPoul-Henning Kamp 		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
308946bb7a2SPoul-Henning Kamp 		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
309946bb7a2SPoul-Henning Kamp 			len, level+1, oidp))
310946bb7a2SPoul-Henning Kamp 			return (0);
31161220614SPoul-Henning Kamp 	next:
312946bb7a2SPoul-Henning Kamp 		namelen = 1;
313946bb7a2SPoul-Henning Kamp 		*len = level;
314946bb7a2SPoul-Henning Kamp 	}
315946bb7a2SPoul-Henning Kamp 	return 1;
316946bb7a2SPoul-Henning Kamp }
317946bb7a2SPoul-Henning Kamp 
318946bb7a2SPoul-Henning Kamp static int
319946bb7a2SPoul-Henning Kamp sysctl_sysctl_next SYSCTL_HANDLER_ARGS
320946bb7a2SPoul-Henning Kamp {
321946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
322946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
323946bb7a2SPoul-Henning Kamp 	int i, j, error;
324946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *oid;
325946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
326946bb7a2SPoul-Henning Kamp 	int newoid[CTL_MAXNAME];
327946bb7a2SPoul-Henning Kamp 
328946bb7a2SPoul-Henning Kamp 	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
329946bb7a2SPoul-Henning Kamp 	if (i)
330946bb7a2SPoul-Henning Kamp 		return ENOENT;
331946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
332946bb7a2SPoul-Henning Kamp 	return (error);
333946bb7a2SPoul-Henning Kamp }
334946bb7a2SPoul-Henning Kamp 
335946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
336946bb7a2SPoul-Henning Kamp 
337946bb7a2SPoul-Henning Kamp static int
338946bb7a2SPoul-Henning Kamp name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp)
339946bb7a2SPoul-Henning Kamp {
340946bb7a2SPoul-Henning Kamp 	int i, j;
341946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
342946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
343946bb7a2SPoul-Henning Kamp 	char *p;
344946bb7a2SPoul-Henning Kamp 
345946bb7a2SPoul-Henning Kamp 	if (!*name)
346946bb7a2SPoul-Henning Kamp 		return ENOENT;
347946bb7a2SPoul-Henning Kamp 
348946bb7a2SPoul-Henning Kamp 	p = name + strlen(name) - 1 ;
349946bb7a2SPoul-Henning Kamp 	if (*p == '.')
350946bb7a2SPoul-Henning Kamp 		*p = '\0';
351946bb7a2SPoul-Henning Kamp 
352946bb7a2SPoul-Henning Kamp 	*len = 0;
353946bb7a2SPoul-Henning Kamp 
354946bb7a2SPoul-Henning Kamp 	for (p = name; *p && *p != '.'; p++)
355946bb7a2SPoul-Henning Kamp 		;
356946bb7a2SPoul-Henning Kamp 	i = *p;
357946bb7a2SPoul-Henning Kamp 	if (i == '.')
358946bb7a2SPoul-Henning Kamp 		*p = '\0';
359946bb7a2SPoul-Henning Kamp 
360946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
361946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
362946bb7a2SPoul-Henning Kamp 
363946bb7a2SPoul-Henning Kamp 	while (j-- && *len < CTL_MAXNAME) {
364946bb7a2SPoul-Henning Kamp 		if (!*oidpp)
365946bb7a2SPoul-Henning Kamp 			continue;
366946bb7a2SPoul-Henning Kamp 		if (strcmp(name, (*oidpp)->oid_name)) {
367946bb7a2SPoul-Henning Kamp 			oidpp++;
368946bb7a2SPoul-Henning Kamp 			continue;
369946bb7a2SPoul-Henning Kamp 		}
370946bb7a2SPoul-Henning Kamp 		*oid++ = (*oidpp)->oid_number;
371946bb7a2SPoul-Henning Kamp 		(*len)++;
372946bb7a2SPoul-Henning Kamp 
373946bb7a2SPoul-Henning Kamp 		if (!i) {
374946bb7a2SPoul-Henning Kamp 			if (oidp)
375946bb7a2SPoul-Henning Kamp 				*oidp = *oidpp;
376946bb7a2SPoul-Henning Kamp 			return (0);
377946bb7a2SPoul-Henning Kamp 		}
378946bb7a2SPoul-Henning Kamp 
379946bb7a2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
380946bb7a2SPoul-Henning Kamp 			break;
381946bb7a2SPoul-Henning Kamp 
382946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
383946bb7a2SPoul-Henning Kamp 			break;
384946bb7a2SPoul-Henning Kamp 
385946bb7a2SPoul-Henning Kamp 		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
386946bb7a2SPoul-Henning Kamp 		j = lsp->ls_length;
387946bb7a2SPoul-Henning Kamp 		oidpp = (struct sysctl_oid **)lsp->ls_items;
388946bb7a2SPoul-Henning Kamp 		name = p+1;
389946bb7a2SPoul-Henning Kamp 		for (p = name; *p && *p != '.'; p++)
390946bb7a2SPoul-Henning Kamp 				;
391946bb7a2SPoul-Henning Kamp 		i = *p;
392946bb7a2SPoul-Henning Kamp 		if (i == '.')
393946bb7a2SPoul-Henning Kamp 			*p = '\0';
394946bb7a2SPoul-Henning Kamp 	}
395946bb7a2SPoul-Henning Kamp 	return ENOENT;
396946bb7a2SPoul-Henning Kamp }
397946bb7a2SPoul-Henning Kamp 
398946bb7a2SPoul-Henning Kamp static int
399946bb7a2SPoul-Henning Kamp sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
400946bb7a2SPoul-Henning Kamp {
401946bb7a2SPoul-Henning Kamp 	char *p;
402946bb7a2SPoul-Henning Kamp 	int error, oid[CTL_MAXNAME], len;
403946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *op = 0;
404946bb7a2SPoul-Henning Kamp 
405946bb7a2SPoul-Henning Kamp 	if (!req->newlen)
406946bb7a2SPoul-Henning Kamp 		return ENOENT;
407946bb7a2SPoul-Henning Kamp 
408946bb7a2SPoul-Henning Kamp 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
409946bb7a2SPoul-Henning Kamp 
410946bb7a2SPoul-Henning Kamp 	error = SYSCTL_IN(req, p, req->newlen);
411946bb7a2SPoul-Henning Kamp 	if (error) {
412946bb7a2SPoul-Henning Kamp 		free(p, M_SYSCTL);
413946bb7a2SPoul-Henning Kamp 		return (error);
414946bb7a2SPoul-Henning Kamp 	}
415946bb7a2SPoul-Henning Kamp 
416946bb7a2SPoul-Henning Kamp 	p [req->newlen] = '\0';
417946bb7a2SPoul-Henning Kamp 
418946bb7a2SPoul-Henning Kamp 	error = name2oid(p, oid, &len, &op);
419946bb7a2SPoul-Henning Kamp 
420946bb7a2SPoul-Henning Kamp 	free(p, M_SYSCTL);
421946bb7a2SPoul-Henning Kamp 
422946bb7a2SPoul-Henning Kamp 	if (error)
423946bb7a2SPoul-Henning Kamp 		return (error);
424946bb7a2SPoul-Henning Kamp 
425946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
426946bb7a2SPoul-Henning Kamp 	return (error);
427946bb7a2SPoul-Henning Kamp }
428946bb7a2SPoul-Henning Kamp 
4293ac9f819SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
430946bb7a2SPoul-Henning Kamp 	sysctl_sysctl_name2oid, "I", "");
431946bb7a2SPoul-Henning Kamp 
432946bb7a2SPoul-Henning Kamp static int
433946bb7a2SPoul-Henning Kamp sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
434946bb7a2SPoul-Henning Kamp {
43565d0bc13SPoul-Henning Kamp 	int *name = (int *) arg1, error;
436946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
437946bb7a2SPoul-Henning Kamp 	int indx, j;
438946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
439946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
440946bb7a2SPoul-Henning Kamp 
441946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
442946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
443946bb7a2SPoul-Henning Kamp 
444946bb7a2SPoul-Henning Kamp 	indx = 0;
445946bb7a2SPoul-Henning Kamp 	while (j-- && indx < CTL_MAXNAME) {
446946bb7a2SPoul-Henning Kamp 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
447946bb7a2SPoul-Henning Kamp 			indx++;
448946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
449946bb7a2SPoul-Henning Kamp 				if ((*oidpp)->oid_handler)
450946bb7a2SPoul-Henning Kamp 					goto found;
451946bb7a2SPoul-Henning Kamp 				if (indx == namelen)
45265d0bc13SPoul-Henning Kamp 					goto found;
453946bb7a2SPoul-Henning Kamp 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
454946bb7a2SPoul-Henning Kamp 				j = lsp->ls_length;
455946bb7a2SPoul-Henning Kamp 				oidpp = (struct sysctl_oid **)lsp->ls_items;
456946bb7a2SPoul-Henning Kamp 			} else {
457946bb7a2SPoul-Henning Kamp 				if (indx != namelen)
458946bb7a2SPoul-Henning Kamp 					return EISDIR;
459946bb7a2SPoul-Henning Kamp 				goto found;
460946bb7a2SPoul-Henning Kamp 			}
461946bb7a2SPoul-Henning Kamp 		} else {
462946bb7a2SPoul-Henning Kamp 			oidpp++;
463946bb7a2SPoul-Henning Kamp 		}
464946bb7a2SPoul-Henning Kamp 	}
465946bb7a2SPoul-Henning Kamp 	return ENOENT;
466946bb7a2SPoul-Henning Kamp found:
467946bb7a2SPoul-Henning Kamp 	if (!(*oidpp)->oid_fmt)
468946bb7a2SPoul-Henning Kamp 		return ENOENT;
46965d0bc13SPoul-Henning Kamp 	error = SYSCTL_OUT(req,
47065d0bc13SPoul-Henning Kamp 		&(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind));
47165d0bc13SPoul-Henning Kamp 	if (!error)
47265d0bc13SPoul-Henning Kamp 		error = SYSCTL_OUT(req, (*oidpp)->oid_fmt,
47365d0bc13SPoul-Henning Kamp 			strlen((*oidpp)->oid_fmt)+1);
47465d0bc13SPoul-Henning Kamp 	return (error);
475946bb7a2SPoul-Henning Kamp }
476946bb7a2SPoul-Henning Kamp 
477946bb7a2SPoul-Henning Kamp 
478946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
479946bb7a2SPoul-Henning Kamp 
480946bb7a2SPoul-Henning Kamp /*
481946bb7a2SPoul-Henning Kamp  * Default "handler" functions.
482946bb7a2SPoul-Henning Kamp  */
4832e210993SPoul-Henning Kamp 
484ae0eb976SPoul-Henning Kamp /*
485ae0eb976SPoul-Henning Kamp  * Handle an integer, signed or unsigned.
486ae0eb976SPoul-Henning Kamp  * Two cases:
487ae0eb976SPoul-Henning Kamp  *     a variable:  point arg1 at it.
488ae0eb976SPoul-Henning Kamp  *     a constant:  pass it in arg2.
489ae0eb976SPoul-Henning Kamp  */
490ae0eb976SPoul-Henning Kamp 
4913a34a5c3SPoul-Henning Kamp int
4923a34a5c3SPoul-Henning Kamp sysctl_handle_int SYSCTL_HANDLER_ARGS
493b396cd83SPoul-Henning Kamp {
494ae0eb976SPoul-Henning Kamp 	int error = 0;
495b396cd83SPoul-Henning Kamp 
496ae0eb976SPoul-Henning Kamp 	if (arg1)
497ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, arg1, sizeof(int));
498ae0eb976SPoul-Henning Kamp 	else if (arg2)
499ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
500b396cd83SPoul-Henning Kamp 
501ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
502ae0eb976SPoul-Henning Kamp 		return (error);
503b396cd83SPoul-Henning Kamp 
504ae0eb976SPoul-Henning Kamp 	if (!arg1)
505ae0eb976SPoul-Henning Kamp 		error = EPERM;
506ae0eb976SPoul-Henning Kamp 	else
507ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, sizeof(int));
508ae0eb976SPoul-Henning Kamp 	return (error);
509b396cd83SPoul-Henning Kamp }
510b396cd83SPoul-Henning Kamp 
511ae0eb976SPoul-Henning Kamp /*
512ae0eb976SPoul-Henning Kamp  * Handle our generic '\0' terminated 'C' string.
513ae0eb976SPoul-Henning Kamp  * Two cases:
514ae0eb976SPoul-Henning Kamp  * 	a variable string:  point arg1 at it, arg2 is max length.
515ae0eb976SPoul-Henning Kamp  * 	a constant string:  point arg1 at it, arg2 is zero.
516ae0eb976SPoul-Henning Kamp  */
517ae0eb976SPoul-Henning Kamp 
5183a34a5c3SPoul-Henning Kamp int
5193a34a5c3SPoul-Henning Kamp sysctl_handle_string SYSCTL_HANDLER_ARGS
520b396cd83SPoul-Henning Kamp {
521ae0eb976SPoul-Henning Kamp 	int error=0;
522b396cd83SPoul-Henning Kamp 
523ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
524b396cd83SPoul-Henning Kamp 
525deae269aSPoul-Henning Kamp 	if (error || !req->newptr || !arg2)
526ae0eb976SPoul-Henning Kamp 		return (error);
527ae0eb976SPoul-Henning Kamp 
528ae0eb976SPoul-Henning Kamp 	if ((req->newlen - req->newidx) > arg2) {
529ae0eb976SPoul-Henning Kamp 		error = E2BIG;
530ae0eb976SPoul-Henning Kamp 	} else {
531ae0eb976SPoul-Henning Kamp 		arg2 = (req->newlen - req->newidx);
532ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, arg2);
533ae0eb976SPoul-Henning Kamp 		((char *)arg1)[arg2] = '\0';
534b396cd83SPoul-Henning Kamp 	}
535b396cd83SPoul-Henning Kamp 
5362e210993SPoul-Henning Kamp 	return (error);
537b396cd83SPoul-Henning Kamp }
538b396cd83SPoul-Henning Kamp 
539ae0eb976SPoul-Henning Kamp /*
540ae0eb976SPoul-Henning Kamp  * Handle any kind of opaque data.
541ae0eb976SPoul-Henning Kamp  * arg1 points to it, arg2 is the size.
542ae0eb976SPoul-Henning Kamp  */
543ae0eb976SPoul-Henning Kamp 
5443a34a5c3SPoul-Henning Kamp int
5453a34a5c3SPoul-Henning Kamp sysctl_handle_opaque SYSCTL_HANDLER_ARGS
546b396cd83SPoul-Henning Kamp {
547ae0eb976SPoul-Henning Kamp 	int error;
548b396cd83SPoul-Henning Kamp 
549ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, arg2);
550b396cd83SPoul-Henning Kamp 
551ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
552ae0eb976SPoul-Henning Kamp 		return (error);
553ae0eb976SPoul-Henning Kamp 
554ae0eb976SPoul-Henning Kamp 	error = SYSCTL_IN(req, arg1, arg2);
555ae0eb976SPoul-Henning Kamp 
556ae0eb976SPoul-Henning Kamp 	return (error);
557b396cd83SPoul-Henning Kamp }
558ae0eb976SPoul-Henning Kamp 
559deae269aSPoul-Henning Kamp /*
560deae269aSPoul-Henning Kamp  * Transfer functions to/from kernel space.
561deae269aSPoul-Henning Kamp  * XXX: rather untested at this point
562deae269aSPoul-Henning Kamp  */
563deae269aSPoul-Henning Kamp static int
5643ac9f819SPoul-Henning Kamp sysctl_old_kernel(struct sysctl_req *req, const void *p, int l)
565ae0eb976SPoul-Henning Kamp {
566deae269aSPoul-Henning Kamp 	int i = 0;
567deae269aSPoul-Henning Kamp 
568deae269aSPoul-Henning Kamp 	if (req->oldptr) {
569deae269aSPoul-Henning Kamp 		i = min(req->oldlen - req->oldidx, l);
570deae269aSPoul-Henning Kamp 		if (i > 0)
57109a8dfa2SBruce Evans 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
572ae0eb976SPoul-Henning Kamp 	}
573deae269aSPoul-Henning Kamp 	req->oldidx += l;
5741c346c70SNate Williams 	if (req->oldptr && i != l)
575ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
5762e210993SPoul-Henning Kamp 	return (0);
577ae0eb976SPoul-Henning Kamp }
578ae0eb976SPoul-Henning Kamp 
579deae269aSPoul-Henning Kamp static int
5801c346c70SNate Williams sysctl_new_kernel(struct sysctl_req *req, void *p, int l)
581ae0eb976SPoul-Henning Kamp {
582deae269aSPoul-Henning Kamp 	if (!req->newptr)
583deae269aSPoul-Henning Kamp 		return 0;
584deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
585ae0eb976SPoul-Henning Kamp 		return (EINVAL);
58609a8dfa2SBruce Evans 	bcopy((char *)req->newptr + req->newidx, p, l);
587ae0eb976SPoul-Henning Kamp 	req->newidx += l;
588ae0eb976SPoul-Henning Kamp 	return (0);
589ae0eb976SPoul-Henning Kamp }
590ae0eb976SPoul-Henning Kamp 
5911c346c70SNate Williams int
5921c346c70SNate Williams kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, int *retval)
5931c346c70SNate Williams {
5941c346c70SNate Williams 	int error = 0;
5951c346c70SNate Williams 	struct sysctl_req req;
5961c346c70SNate Williams 
5971c346c70SNate Williams 	bzero(&req, sizeof req);
5981c346c70SNate Williams 
5991c346c70SNate Williams 	req.p = p;
6001c346c70SNate Williams 
6011c346c70SNate Williams 	if (oldlenp) {
6021c346c70SNate Williams 		req.oldlen = *oldlenp;
6031c346c70SNate Williams 	}
6041c346c70SNate Williams 
6051c346c70SNate Williams 	if (old) {
6061c346c70SNate Williams 		req.oldptr= old;
6071c346c70SNate Williams 	}
6081c346c70SNate Williams 
6091c346c70SNate Williams 	if (newlen) {
6101c346c70SNate Williams 		req.newlen = newlen;
6111c346c70SNate Williams 		req.newptr = new;
6121c346c70SNate Williams 	}
6131c346c70SNate Williams 
6141c346c70SNate Williams 	req.oldfunc = sysctl_old_kernel;
6151c346c70SNate Williams 	req.newfunc = sysctl_new_kernel;
6161c346c70SNate Williams 	req.lock = 1;
6171c346c70SNate Williams 
6181c346c70SNate Williams 	/* XXX this should probably be done in a general way */
6191c346c70SNate Williams 	while (memlock.sl_lock) {
6201c346c70SNate Williams 		memlock.sl_want = 1;
6211c346c70SNate Williams 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
6221c346c70SNate Williams 		memlock.sl_locked++;
6231c346c70SNate Williams 	}
6241c346c70SNate Williams 	memlock.sl_lock = 1;
6251c346c70SNate Williams 
6261c346c70SNate Williams 	error = sysctl_root(0, name, namelen, &req);
6271c346c70SNate Williams 
6281c346c70SNate Williams 	if (req.lock == 2)
6291c346c70SNate Williams 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
6301c346c70SNate Williams 
6311c346c70SNate Williams 	memlock.sl_lock = 0;
6321c346c70SNate Williams 
6331c346c70SNate Williams 	if (memlock.sl_want) {
6341c346c70SNate Williams 		memlock.sl_want = 0;
6351c346c70SNate Williams 		wakeup((caddr_t)&memlock);
6361c346c70SNate Williams 	}
6371c346c70SNate Williams 
6381c346c70SNate Williams 	if (error && error != ENOMEM)
6391c346c70SNate Williams 		return (error);
6401c346c70SNate Williams 
6411c346c70SNate Williams 	if (retval) {
6421c346c70SNate Williams 		if (req.oldptr && req.oldidx > req.oldlen)
6431c346c70SNate Williams 			*retval = req.oldlen;
6441c346c70SNate Williams 		else
6451c346c70SNate Williams 			*retval = req.oldidx;
6461c346c70SNate Williams 	}
6471c346c70SNate Williams 	return (error);
6481c346c70SNate Williams }
6491c346c70SNate Williams 
650deae269aSPoul-Henning Kamp /*
651deae269aSPoul-Henning Kamp  * Transfer function to/from user space.
652deae269aSPoul-Henning Kamp  */
653deae269aSPoul-Henning Kamp static int
6543ac9f819SPoul-Henning Kamp sysctl_old_user(struct sysctl_req *req, const void *p, int l)
655ae0eb976SPoul-Henning Kamp {
656deae269aSPoul-Henning Kamp 	int error = 0, i = 0;
657ae0eb976SPoul-Henning Kamp 
6584b2af45fSPoul-Henning Kamp 	if (req->lock == 1 && req->oldptr) {
6594b2af45fSPoul-Henning Kamp 		vslock(req->oldptr, req->oldlen);
6604b2af45fSPoul-Henning Kamp 		req->lock = 2;
6614b2af45fSPoul-Henning Kamp 	}
662deae269aSPoul-Henning Kamp 	if (req->oldptr) {
663deae269aSPoul-Henning Kamp 		i = min(req->oldlen - req->oldidx, l);
664deae269aSPoul-Henning Kamp 		if (i > 0)
66509a8dfa2SBruce Evans 			error = copyout(p, (char *)req->oldptr + req->oldidx,
66609a8dfa2SBruce Evans 					i);
667deae269aSPoul-Henning Kamp 	}
668deae269aSPoul-Henning Kamp 	req->oldidx += l;
669ae0eb976SPoul-Henning Kamp 	if (error)
670ae0eb976SPoul-Henning Kamp 		return (error);
671deae269aSPoul-Henning Kamp 	if (req->oldptr && i < l)
672ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
673deae269aSPoul-Henning Kamp 	return (0);
674ae0eb976SPoul-Henning Kamp }
675ae0eb976SPoul-Henning Kamp 
676deae269aSPoul-Henning Kamp static int
677ae0eb976SPoul-Henning Kamp sysctl_new_user(struct sysctl_req *req, void *p, int l)
678ae0eb976SPoul-Henning Kamp {
67916cd04a3SPoul-Henning Kamp 	int error;
680deae269aSPoul-Henning Kamp 
681deae269aSPoul-Henning Kamp 	if (!req->newptr)
682deae269aSPoul-Henning Kamp 		return 0;
683deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
684ae0eb976SPoul-Henning Kamp 		return (EINVAL);
68509a8dfa2SBruce Evans 	error = copyin((char *)req->newptr + req->newidx, p, l);
686ae0eb976SPoul-Henning Kamp 	req->newidx += l;
687ae0eb976SPoul-Henning Kamp 	return (error);
688b396cd83SPoul-Henning Kamp }
689b396cd83SPoul-Henning Kamp 
690df8bae1dSRodney W. Grimes /*
6912e210993SPoul-Henning Kamp  * Traverse our tree, and find the right node, execute whatever it points
6922e210993SPoul-Henning Kamp  * at, and return the resulting error code.
6932e210993SPoul-Henning Kamp  */
6942e210993SPoul-Henning Kamp 
6952e210993SPoul-Henning Kamp int
6962e210993SPoul-Henning Kamp sysctl_root SYSCTL_HANDLER_ARGS
6972e210993SPoul-Henning Kamp {
6982e210993SPoul-Henning Kamp 	int *name = (int *) arg1;
699946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
7002e210993SPoul-Henning Kamp 	int indx, i, j;
7012e210993SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
7022e210993SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
7032e210993SPoul-Henning Kamp 
7042e210993SPoul-Henning Kamp 	j = lsp->ls_length;
7052e210993SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
7062e210993SPoul-Henning Kamp 
7072e210993SPoul-Henning Kamp 	indx = 0;
7082e210993SPoul-Henning Kamp 	while (j-- && indx < CTL_MAXNAME) {
709787d58f2SPoul-Henning Kamp 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
7102e210993SPoul-Henning Kamp 			indx++;
7114b2af45fSPoul-Henning Kamp 			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
7124b2af45fSPoul-Henning Kamp 				req->lock = 0;
7132e210993SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
7142e210993SPoul-Henning Kamp 				if ((*oidpp)->oid_handler)
7152e210993SPoul-Henning Kamp 					goto found;
7162e210993SPoul-Henning Kamp 				if (indx == namelen)
7172e210993SPoul-Henning Kamp 					return ENOENT;
7182e210993SPoul-Henning Kamp 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
7192e210993SPoul-Henning Kamp 				j = lsp->ls_length;
7202e210993SPoul-Henning Kamp 				oidpp = (struct sysctl_oid **)lsp->ls_items;
7212e210993SPoul-Henning Kamp 			} else {
7222e210993SPoul-Henning Kamp 				if (indx != namelen)
7232e210993SPoul-Henning Kamp 					return EISDIR;
7242e210993SPoul-Henning Kamp 				goto found;
7252e210993SPoul-Henning Kamp 			}
7262e210993SPoul-Henning Kamp 		} else {
7272e210993SPoul-Henning Kamp 			oidpp++;
7282e210993SPoul-Henning Kamp 		}
7292e210993SPoul-Henning Kamp 	}
730deae269aSPoul-Henning Kamp 	return ENOENT;
7312e210993SPoul-Henning Kamp found:
7322e210993SPoul-Henning Kamp 	/* If writing isn't allowed */
733ae0eb976SPoul-Henning Kamp 	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
7342e210993SPoul-Henning Kamp 		return (EPERM);
7352e210993SPoul-Henning Kamp 
7363ac9f819SPoul-Henning Kamp 	/* Most likely only root can write */
7373ac9f819SPoul-Henning Kamp 	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
7383ac9f819SPoul-Henning Kamp 	    req->newptr && req->p &&
7393ac9f819SPoul-Henning Kamp 	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
7403ac9f819SPoul-Henning Kamp 		return (i);
7413ac9f819SPoul-Henning Kamp 
7422e210993SPoul-Henning Kamp 	if (!(*oidpp)->oid_handler)
7432e210993SPoul-Henning Kamp 		return EINVAL;
7442e210993SPoul-Henning Kamp 
7452e210993SPoul-Henning Kamp 	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
7462e210993SPoul-Henning Kamp 		i = ((*oidpp)->oid_handler) (*oidpp,
7472e210993SPoul-Henning Kamp 					name + indx, namelen - indx,
748ae0eb976SPoul-Henning Kamp 					req);
7492e210993SPoul-Henning Kamp 	} else {
7502e210993SPoul-Henning Kamp 		i = ((*oidpp)->oid_handler) (*oidpp,
7512e210993SPoul-Henning Kamp 					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
752ae0eb976SPoul-Henning Kamp 					req);
7532e210993SPoul-Henning Kamp 	}
7542e210993SPoul-Henning Kamp 	return (i);
7552e210993SPoul-Henning Kamp }
7562e210993SPoul-Henning Kamp 
757d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
758b8da2396SPoul-Henning Kamp struct sysctl_args {
759b8da2396SPoul-Henning Kamp 	int	*name;
760b8da2396SPoul-Henning Kamp 	u_int	namelen;
761b8da2396SPoul-Henning Kamp 	void	*old;
762b8da2396SPoul-Henning Kamp 	size_t	*oldlenp;
763b8da2396SPoul-Henning Kamp 	void	*new;
764b8da2396SPoul-Henning Kamp 	size_t	newlen;
765b8da2396SPoul-Henning Kamp };
766d2d3e875SBruce Evans #endif
767b8da2396SPoul-Henning Kamp 
768df8bae1dSRodney W. Grimes int
7694b2af45fSPoul-Henning Kamp __sysctl(struct proc *p, struct sysctl_args *uap, int *retval)
770df8bae1dSRodney W. Grimes {
771deae269aSPoul-Henning Kamp 	int error, i, j, name[CTL_MAXNAME];
772b396cd83SPoul-Henning Kamp 
773df8bae1dSRodney W. Grimes 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
774df8bae1dSRodney W. Grimes 		return (EINVAL);
775b396cd83SPoul-Henning Kamp 
776797f2d22SPoul-Henning Kamp  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
777797f2d22SPoul-Henning Kamp  	if (error)
778df8bae1dSRodney W. Grimes 		return (error);
779df8bae1dSRodney W. Grimes 
780deae269aSPoul-Henning Kamp 	error = userland_sysctl(p, name, uap->namelen,
781b8da2396SPoul-Henning Kamp 		uap->old, uap->oldlenp, 0,
782deae269aSPoul-Henning Kamp 		uap->new, uap->newlen, &j);
783deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
784deae269aSPoul-Henning Kamp 		return (error);
785deae269aSPoul-Henning Kamp 	if (uap->oldlenp) {
786deae269aSPoul-Henning Kamp 		i = copyout(&j, uap->oldlenp, sizeof(j));
787deae269aSPoul-Henning Kamp 		if (i)
788deae269aSPoul-Henning Kamp 			return (i);
789deae269aSPoul-Henning Kamp 	}
790deae269aSPoul-Henning Kamp 	return (error);
791b8da2396SPoul-Henning Kamp }
792b8da2396SPoul-Henning Kamp 
793b8da2396SPoul-Henning Kamp /*
794b8da2396SPoul-Henning Kamp  * This is used from various compatibility syscalls too.  That's why name
795b8da2396SPoul-Henning Kamp  * must be in kernel space.
796b8da2396SPoul-Henning Kamp  */
797b8da2396SPoul-Henning Kamp int
798b8da2396SPoul-Henning Kamp userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, int *retval)
799b8da2396SPoul-Henning Kamp {
8004b2af45fSPoul-Henning Kamp 	int error = 0;
8017a69d923SPoul-Henning Kamp 	struct sysctl_req req, req2;
802ae0eb976SPoul-Henning Kamp 
803ae0eb976SPoul-Henning Kamp 	bzero(&req, sizeof req);
804b8da2396SPoul-Henning Kamp 
80516cd04a3SPoul-Henning Kamp 	req.p = p;
80616cd04a3SPoul-Henning Kamp 
807b8da2396SPoul-Henning Kamp 	if (oldlenp) {
808b8da2396SPoul-Henning Kamp 		if (inkernel) {
809ae0eb976SPoul-Henning Kamp 			req.oldlen = *oldlenp;
810b8da2396SPoul-Henning Kamp 		} else {
811deae269aSPoul-Henning Kamp 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
812b8da2396SPoul-Henning Kamp 			if (error)
813b8da2396SPoul-Henning Kamp 				return (error);
814b8da2396SPoul-Henning Kamp 		}
815b8da2396SPoul-Henning Kamp 	}
816b8da2396SPoul-Henning Kamp 
817ae0eb976SPoul-Henning Kamp 	if (old) {
818ae0eb976SPoul-Henning Kamp 		if (!useracc(old, req.oldlen, B_WRITE))
819ae0eb976SPoul-Henning Kamp 			return (EFAULT);
820ae0eb976SPoul-Henning Kamp 		req.oldptr= old;
821ae0eb976SPoul-Henning Kamp 	}
8222e210993SPoul-Henning Kamp 
823b8da2396SPoul-Henning Kamp 	if (newlen) {
824ae0eb976SPoul-Henning Kamp 		if (!useracc(new, req.newlen, B_READ))
825ae0eb976SPoul-Henning Kamp 			return (EFAULT);
826ae0eb976SPoul-Henning Kamp 		req.newlen = newlen;
827ae0eb976SPoul-Henning Kamp 		req.newptr = new;
828b396cd83SPoul-Henning Kamp 	}
829b396cd83SPoul-Henning Kamp 
830ae0eb976SPoul-Henning Kamp 	req.oldfunc = sysctl_old_user;
831ae0eb976SPoul-Henning Kamp 	req.newfunc = sysctl_new_user;
8324b2af45fSPoul-Henning Kamp 	req.lock = 1;
8334b2af45fSPoul-Henning Kamp 
8344b2af45fSPoul-Henning Kamp 	/* XXX this should probably be done in a general way */
8354b2af45fSPoul-Henning Kamp 	while (memlock.sl_lock) {
8364b2af45fSPoul-Henning Kamp 		memlock.sl_want = 1;
8374b2af45fSPoul-Henning Kamp 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
8384b2af45fSPoul-Henning Kamp 		memlock.sl_locked++;
8394b2af45fSPoul-Henning Kamp 	}
8404b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 1;
841ae0eb976SPoul-Henning Kamp 
8427a69d923SPoul-Henning Kamp 	do {
8437a69d923SPoul-Henning Kamp 	    req2 = req;
8447a69d923SPoul-Henning Kamp 	    error = sysctl_root(0, name, namelen, &req2);
8457a69d923SPoul-Henning Kamp 	} while (error == EAGAIN);
846b396cd83SPoul-Henning Kamp 
8477a69d923SPoul-Henning Kamp 	req = req2;
8484b2af45fSPoul-Henning Kamp 	if (req.lock == 2)
8494b2af45fSPoul-Henning Kamp 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
8504b2af45fSPoul-Henning Kamp 
8514b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 0;
8524b2af45fSPoul-Henning Kamp 
8534b2af45fSPoul-Henning Kamp 	if (memlock.sl_want) {
8544b2af45fSPoul-Henning Kamp 		memlock.sl_want = 0;
8554b2af45fSPoul-Henning Kamp 		wakeup((caddr_t)&memlock);
8564b2af45fSPoul-Henning Kamp 	}
8574b2af45fSPoul-Henning Kamp 
858deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
859deae269aSPoul-Henning Kamp 		return (error);
860deae269aSPoul-Henning Kamp 
861deae269aSPoul-Henning Kamp 	if (retval) {
862deae269aSPoul-Henning Kamp 		if (req.oldptr && req.oldidx > req.oldlen)
863ae0eb976SPoul-Henning Kamp 			*retval = req.oldlen;
864deae269aSPoul-Henning Kamp 		else
865deae269aSPoul-Henning Kamp 			*retval = req.oldidx;
866b8da2396SPoul-Henning Kamp 	}
8672e210993SPoul-Henning Kamp 	return (error);
868df8bae1dSRodney W. Grimes }
869df8bae1dSRodney W. Grimes 
870df8bae1dSRodney W. Grimes #ifdef COMPAT_43
871df8bae1dSRodney W. Grimes #include <sys/socket.h>
87245ec3b38SPoul-Henning Kamp #include <vm/vm_param.h>
87345ec3b38SPoul-Henning Kamp 
874df8bae1dSRodney W. Grimes #define	KINFO_PROC		(0<<8)
875df8bae1dSRodney W. Grimes #define	KINFO_RT		(1<<8)
876df8bae1dSRodney W. Grimes #define	KINFO_VNODE		(2<<8)
877df8bae1dSRodney W. Grimes #define	KINFO_FILE		(3<<8)
878df8bae1dSRodney W. Grimes #define	KINFO_METER		(4<<8)
879df8bae1dSRodney W. Grimes #define	KINFO_LOADAVG		(5<<8)
880df8bae1dSRodney W. Grimes #define	KINFO_CLOCKRATE		(6<<8)
881df8bae1dSRodney W. Grimes 
8826ece4a51SPeter Wemm /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
8836ece4a51SPeter Wemm #define	KINFO_BSDI_SYSINFO	(101<<8)
8846ece4a51SPeter Wemm 
8856ece4a51SPeter Wemm /*
8866ece4a51SPeter Wemm  * XXX this is bloat, but I hope it's better here than on the potentially
8876ece4a51SPeter Wemm  * limited kernel stack...  -Peter
8886ece4a51SPeter Wemm  */
8896ece4a51SPeter Wemm 
89087b6de2bSPoul-Henning Kamp static struct {
8916ece4a51SPeter Wemm 	int	bsdi_machine;		/* "i386" on BSD/386 */
8926ece4a51SPeter Wemm /*      ^^^ this is an offset to the string, relative to the struct start */
8936ece4a51SPeter Wemm 	char	*pad0;
8946ece4a51SPeter Wemm 	long	pad1;
8956ece4a51SPeter Wemm 	long	pad2;
8966ece4a51SPeter Wemm 	long	pad3;
8976ece4a51SPeter Wemm 	u_long	pad4;
8986ece4a51SPeter Wemm 	u_long	pad5;
8996ece4a51SPeter Wemm 	u_long	pad6;
9006ece4a51SPeter Wemm 
9016ece4a51SPeter Wemm 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
9026ece4a51SPeter Wemm 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
9036ece4a51SPeter Wemm 	long	pad7;
9046ece4a51SPeter Wemm 	long	pad8;
9056ece4a51SPeter Wemm 	char	*pad9;
9066ece4a51SPeter Wemm 
9076ece4a51SPeter Wemm 	long	pad10;
9086ece4a51SPeter Wemm 	long	pad11;
9096ece4a51SPeter Wemm 	int	pad12;
9106ece4a51SPeter Wemm 	long	pad13;
9116ece4a51SPeter Wemm 	quad_t	pad14;
9126ece4a51SPeter Wemm 	long	pad15;
9136ece4a51SPeter Wemm 
9146ece4a51SPeter Wemm 	struct	timeval pad16;
9156ece4a51SPeter Wemm 	/* we dont set this, because BSDI's uname used gethostname() instead */
9166ece4a51SPeter Wemm 	int	bsdi_hostname;		/* hostname on BSD/386 */
9176ece4a51SPeter Wemm 
9186ece4a51SPeter Wemm 	/* the actual string data is appended here */
9196ece4a51SPeter Wemm 
9206ece4a51SPeter Wemm } bsdi_si;
9216ece4a51SPeter Wemm /*
9226ece4a51SPeter Wemm  * this data is appended to the end of the bsdi_si structure during copyout.
9236ece4a51SPeter Wemm  * The "char *" offsets are relative to the base of the bsdi_si struct.
9246ece4a51SPeter Wemm  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
9256ece4a51SPeter Wemm  * should not exceed the length of the buffer here... (or else!! :-)
9266ece4a51SPeter Wemm  */
92787b6de2bSPoul-Henning Kamp static char bsdi_strings[80];	/* It had better be less than this! */
9286ece4a51SPeter Wemm 
929d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
930df8bae1dSRodney W. Grimes struct getkerninfo_args {
931df8bae1dSRodney W. Grimes 	int	op;
932df8bae1dSRodney W. Grimes 	char	*where;
933df8bae1dSRodney W. Grimes 	int	*size;
934df8bae1dSRodney W. Grimes 	int	arg;
935df8bae1dSRodney W. Grimes };
936d2d3e875SBruce Evans #endif
937df8bae1dSRodney W. Grimes 
93826f9a767SRodney W. Grimes int
9394b2af45fSPoul-Henning Kamp ogetkerninfo(struct proc *p, struct getkerninfo_args *uap, int *retval)
940df8bae1dSRodney W. Grimes {
941b8da2396SPoul-Henning Kamp 	int error, name[6];
942df8bae1dSRodney W. Grimes 	u_int size;
943df8bae1dSRodney W. Grimes 
944df8bae1dSRodney W. Grimes 	switch (uap->op & 0xff00) {
945df8bae1dSRodney W. Grimes 
946df8bae1dSRodney W. Grimes 	case KINFO_RT:
947b8da2396SPoul-Henning Kamp 		name[0] = CTL_NET;
948b8da2396SPoul-Henning Kamp 		name[1] = PF_ROUTE;
949b8da2396SPoul-Henning Kamp 		name[2] = 0;
950b8da2396SPoul-Henning Kamp 		name[3] = (uap->op & 0xff0000) >> 16;
951b8da2396SPoul-Henning Kamp 		name[4] = uap->op & 0xff;
952b8da2396SPoul-Henning Kamp 		name[5] = uap->arg;
953b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
9544b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
955df8bae1dSRodney W. Grimes 		break;
956df8bae1dSRodney W. Grimes 
957df8bae1dSRodney W. Grimes 	case KINFO_VNODE:
958b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
959b8da2396SPoul-Henning Kamp 		name[1] = KERN_VNODE;
960b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
9614b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
962df8bae1dSRodney W. Grimes 		break;
963df8bae1dSRodney W. Grimes 
964df8bae1dSRodney W. Grimes 	case KINFO_PROC:
965b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
966b8da2396SPoul-Henning Kamp 		name[1] = KERN_PROC;
967b8da2396SPoul-Henning Kamp 		name[2] = uap->op & 0xff;
968b8da2396SPoul-Henning Kamp 		name[3] = uap->arg;
969b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
9704b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
971df8bae1dSRodney W. Grimes 		break;
972df8bae1dSRodney W. Grimes 
973df8bae1dSRodney W. Grimes 	case KINFO_FILE:
974b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
975b8da2396SPoul-Henning Kamp 		name[1] = KERN_FILE;
976b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
9774b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
978df8bae1dSRodney W. Grimes 		break;
979df8bae1dSRodney W. Grimes 
980df8bae1dSRodney W. Grimes 	case KINFO_METER:
981b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
982b8da2396SPoul-Henning Kamp 		name[1] = VM_METER;
983b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
9844b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
985df8bae1dSRodney W. Grimes 		break;
986df8bae1dSRodney W. Grimes 
987df8bae1dSRodney W. Grimes 	case KINFO_LOADAVG:
988b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
989b8da2396SPoul-Henning Kamp 		name[1] = VM_LOADAVG;
990b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
9914b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
992df8bae1dSRodney W. Grimes 		break;
993df8bae1dSRodney W. Grimes 
994df8bae1dSRodney W. Grimes 	case KINFO_CLOCKRATE:
995b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
996b8da2396SPoul-Henning Kamp 		name[1] = KERN_CLOCKRATE;
997b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
9984b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
999df8bae1dSRodney W. Grimes 		break;
1000df8bae1dSRodney W. Grimes 
10016ece4a51SPeter Wemm 	case KINFO_BSDI_SYSINFO: {
10026ece4a51SPeter Wemm 		/*
10036ece4a51SPeter Wemm 		 * this is pretty crude, but it's just enough for uname()
10046ece4a51SPeter Wemm 		 * from BSDI's 1.x libc to work.
10056ece4a51SPeter Wemm 		 *
10066ece4a51SPeter Wemm 		 * In particular, it doesn't return the same results when
10076ece4a51SPeter Wemm 		 * the supplied buffer is too small.  BSDI's version apparently
10086ece4a51SPeter Wemm 		 * will return the amount copied, and set the *size to how
10096ece4a51SPeter Wemm 		 * much was needed.  The emulation framework here isn't capable
10106ece4a51SPeter Wemm 		 * of that, so we just set both to the amount copied.
10116ece4a51SPeter Wemm 		 * BSDI's 2.x product apparently fails with ENOMEM in this
10126ece4a51SPeter Wemm 		 * scenario.
10136ece4a51SPeter Wemm 		 */
10146ece4a51SPeter Wemm 
10156ece4a51SPeter Wemm 		u_int needed;
10166ece4a51SPeter Wemm 		u_int left;
10176ece4a51SPeter Wemm 		char *s;
10186ece4a51SPeter Wemm 
10196ece4a51SPeter Wemm 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
10206ece4a51SPeter Wemm 		bzero(bsdi_strings, sizeof(bsdi_strings));
10216ece4a51SPeter Wemm 
10226ece4a51SPeter Wemm 		s = bsdi_strings;
10236ece4a51SPeter Wemm 
10246ece4a51SPeter Wemm 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
10256ece4a51SPeter Wemm 		strcpy(s, ostype);
10266ece4a51SPeter Wemm 		s += strlen(s) + 1;
10276ece4a51SPeter Wemm 
10286ece4a51SPeter Wemm 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
10296ece4a51SPeter Wemm 		strcpy(s, osrelease);
10306ece4a51SPeter Wemm 		s += strlen(s) + 1;
10316ece4a51SPeter Wemm 
10326ece4a51SPeter Wemm 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
10336ece4a51SPeter Wemm 		strcpy(s, machine);
10346ece4a51SPeter Wemm 		s += strlen(s) + 1;
10356ece4a51SPeter Wemm 
10366ece4a51SPeter Wemm 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
10376ece4a51SPeter Wemm 
10386ece4a51SPeter Wemm 		if (uap->where == NULL) {
10396ece4a51SPeter Wemm 			/* process is asking how much buffer to supply.. */
10406ece4a51SPeter Wemm 			size = needed;
10416ece4a51SPeter Wemm 			error = 0;
10426ece4a51SPeter Wemm 			break;
10436ece4a51SPeter Wemm 		}
10446ece4a51SPeter Wemm 
10456ece4a51SPeter Wemm 
10466ece4a51SPeter Wemm 		/* if too much buffer supplied, trim it down */
10476ece4a51SPeter Wemm 		if (size > needed)
10486ece4a51SPeter Wemm 			size = needed;
10496ece4a51SPeter Wemm 
10506ece4a51SPeter Wemm 		/* how much of the buffer is remaining */
10516ece4a51SPeter Wemm 		left = size;
10526ece4a51SPeter Wemm 
10536ece4a51SPeter Wemm 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
10546ece4a51SPeter Wemm 			break;
10556ece4a51SPeter Wemm 
10566ece4a51SPeter Wemm 		/* is there any point in continuing? */
10576ece4a51SPeter Wemm 		if (left > sizeof(bsdi_si)) {
10586ece4a51SPeter Wemm 			left -= sizeof(bsdi_si);
10596ece4a51SPeter Wemm 			error = copyout(&bsdi_strings,
10606ece4a51SPeter Wemm 					uap->where + sizeof(bsdi_si), left);
10616ece4a51SPeter Wemm 		}
10626ece4a51SPeter Wemm 		break;
10636ece4a51SPeter Wemm 	}
10646ece4a51SPeter Wemm 
1065df8bae1dSRodney W. Grimes 	default:
1066df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1067df8bae1dSRodney W. Grimes 	}
1068df8bae1dSRodney W. Grimes 	if (error)
1069df8bae1dSRodney W. Grimes 		return (error);
1070df8bae1dSRodney W. Grimes 	*retval = size;
1071df8bae1dSRodney W. Grimes 	if (uap->size)
1072df8bae1dSRodney W. Grimes 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1073df8bae1dSRodney W. Grimes 		    sizeof(size));
1074df8bae1dSRodney W. Grimes 	return (error);
1075df8bae1dSRodney W. Grimes }
1076df8bae1dSRodney W. Grimes #endif /* COMPAT_43 */
1077