xref: /freebsd/sys/kern/kern_sysctl.c (revision 7f4173cc09290763b26b990d3efb01065b7aabf9)
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
407f4173ccSPoul-Henning Kamp  * $Id: kern_sysctl.c,v 1.84 1999/02/16 10:49:48 dfr 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 
69ce02431fSDoug Rabson struct sysctl_oid_list sysctl__children; /* root list */
70787d58f2SPoul-Henning Kamp 
71946bb7a2SPoul-Henning Kamp /*
72946bb7a2SPoul-Henning Kamp  * Initialization of the MIB tree.
73946bb7a2SPoul-Henning Kamp  *
74ce02431fSDoug Rabson  * Order by number in each list.
75946bb7a2SPoul-Henning Kamp  */
764b2af45fSPoul-Henning Kamp 
77ce02431fSDoug Rabson void sysctl_register_oid(struct sysctl_oid *oidp)
78787d58f2SPoul-Henning Kamp {
79ce02431fSDoug Rabson 	struct sysctl_oid_list *parent = oidp->oid_parent;
80ce02431fSDoug Rabson 	struct sysctl_oid *p;
81ce02431fSDoug Rabson 	struct sysctl_oid *q;
82ce02431fSDoug Rabson 	int n;
833c8e79ddSBruce Evans 
84ce02431fSDoug Rabson 	/*
85ce02431fSDoug Rabson 	 * If this oid has a number OID_AUTO, give it a number which
86ce02431fSDoug Rabson 	 * is greater than any current oid.  Make sure it is at least
87ce02431fSDoug Rabson 	 * 100 to leave space for pre-assigned oid numbers.
88ce02431fSDoug Rabson 	 */
89ce02431fSDoug Rabson 	if (oidp->oid_number == OID_AUTO) {
90ce02431fSDoug Rabson 		/* First, find the highest oid in the parent list >99 */
91ce02431fSDoug Rabson 		n = 99;
92ce02431fSDoug Rabson 		SLIST_FOREACH(p, parent, oid_link) {
93ce02431fSDoug Rabson 			if (p->oid_number > n)
94ce02431fSDoug Rabson 				n = p->oid_number;
95ce02431fSDoug Rabson 		}
96ce02431fSDoug Rabson 		oidp->oid_number = n + 1;
97787d58f2SPoul-Henning Kamp 	}
98787d58f2SPoul-Henning Kamp 
99ce02431fSDoug Rabson 	/*
100ce02431fSDoug Rabson 	 * Insert the oid into the parent's list in order.
101ce02431fSDoug Rabson 	 */
102ce02431fSDoug Rabson 	q = NULL;
103ce02431fSDoug Rabson 	SLIST_FOREACH(p, parent, oid_link) {
104ce02431fSDoug Rabson 		if (oidp->oid_number < p->oid_number)
105ce02431fSDoug Rabson 			break;
106ce02431fSDoug Rabson 		q = p;
107ce02431fSDoug Rabson 	}
108ce02431fSDoug Rabson 	if (q)
109ce02431fSDoug Rabson 		SLIST_INSERT_AFTER(q, oidp, oid_link);
110ce02431fSDoug Rabson 	else
111ce02431fSDoug Rabson 		SLIST_INSERT_HEAD(parent, oidp, oid_link);
112ce02431fSDoug Rabson }
113ce02431fSDoug Rabson 
114ce02431fSDoug Rabson void sysctl_unregister_oid(struct sysctl_oid *oidp)
115787d58f2SPoul-Henning Kamp {
116ce02431fSDoug Rabson 	SLIST_REMOVE(oidp->oid_parent, oidp, sysctl_oid, oid_link);
11761220614SPoul-Henning Kamp }
118946bb7a2SPoul-Henning Kamp 
119ce02431fSDoug Rabson /*
120ce02431fSDoug Rabson  * Bulk-register all the oids in a linker_set.
121ce02431fSDoug Rabson  */
122ce02431fSDoug Rabson void sysctl_register_set(struct linker_set *lsp)
123e99ea9ecSBruce Evans {
124ce02431fSDoug Rabson 	int count = lsp->ls_length;
125ce02431fSDoug Rabson 	int i;
126ce02431fSDoug Rabson 	for (i = 0; i < count; i++)
127ce02431fSDoug Rabson 		sysctl_register_oid((struct sysctl_oid *) lsp->ls_items[i]);
128e99ea9ecSBruce Evans }
129e99ea9ecSBruce Evans 
130ce02431fSDoug Rabson void sysctl_unregister_set(struct linker_set *lsp)
131ce02431fSDoug Rabson {
132ce02431fSDoug Rabson 	int count = lsp->ls_length;
133ce02431fSDoug Rabson 	int i;
134ce02431fSDoug Rabson 	for (i = 0; i < count; i++)
135ce02431fSDoug Rabson 		sysctl_unregister_oid((struct sysctl_oid *) lsp->ls_items[i]);
136ce02431fSDoug Rabson }
137ce02431fSDoug Rabson 
138ce02431fSDoug Rabson /*
139ce02431fSDoug Rabson  * Register the kernel's oids on startup.
140ce02431fSDoug Rabson  */
141ce02431fSDoug Rabson extern struct linker_set sysctl_set;
142ce02431fSDoug Rabson 
143ce02431fSDoug Rabson static void sysctl_register_all(void *arg)
144ce02431fSDoug Rabson {
145ce02431fSDoug Rabson 	sysctl_register_set(&sysctl_set);
146ce02431fSDoug Rabson }
147ce02431fSDoug Rabson 
148ce02431fSDoug Rabson SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
149ce02431fSDoug Rabson 
150946bb7a2SPoul-Henning Kamp /*
151946bb7a2SPoul-Henning Kamp  * "Staff-functions"
152946bb7a2SPoul-Henning Kamp  *
15365d0bc13SPoul-Henning Kamp  * These functions implement a presently undocumented interface
15465d0bc13SPoul-Henning Kamp  * used by the sysctl program to walk the tree, and get the type
15565d0bc13SPoul-Henning Kamp  * so it can print the value.
15665d0bc13SPoul-Henning Kamp  * This interface is under work and consideration, and should probably
15765d0bc13SPoul-Henning Kamp  * be killed with a big axe by the first person who can find the time.
15865d0bc13SPoul-Henning Kamp  * (be aware though, that the proper interface isn't as obvious as it
15965d0bc13SPoul-Henning Kamp  * may seem, there are various conflicting requirements.
16065d0bc13SPoul-Henning Kamp  *
161946bb7a2SPoul-Henning Kamp  * {0,0}	printf the entire MIB-tree.
162946bb7a2SPoul-Henning Kamp  * {0,1,...}	return the name of the "..." OID.
16386415b71SPoul-Henning Kamp  * {0,2,...}	return the next OID.
164946bb7a2SPoul-Henning Kamp  * {0,3}	return the OID of the name in "new"
16565d0bc13SPoul-Henning Kamp  * {0,4,...}	return the kind & format info for the "..." OID.
166946bb7a2SPoul-Henning Kamp  */
167946bb7a2SPoul-Henning Kamp 
168787d58f2SPoul-Henning Kamp static void
169ce02431fSDoug Rabson sysctl_sysctl_debug_dump_node(struct sysctl_oid_list *l, int i)
170787d58f2SPoul-Henning Kamp {
171ce02431fSDoug Rabson 	int k;
172ce02431fSDoug Rabson 	struct sysctl_oid *oidp;
173787d58f2SPoul-Henning Kamp 
174ce02431fSDoug Rabson 	SLIST_FOREACH(oidp, l, oid_link) {
175787d58f2SPoul-Henning Kamp 
176787d58f2SPoul-Henning Kamp 		for (k=0; k<i; k++)
177787d58f2SPoul-Henning Kamp 			printf(" ");
178787d58f2SPoul-Henning Kamp 
179ce02431fSDoug Rabson 		printf("%d %s ", oidp->oid_number, oidp->oid_name);
180787d58f2SPoul-Henning Kamp 
181787d58f2SPoul-Henning Kamp 		printf("%c%c",
182ce02431fSDoug Rabson 			oidp->oid_kind & CTLFLAG_RD ? 'R':' ',
183ce02431fSDoug Rabson 			oidp->oid_kind & CTLFLAG_WR ? 'W':' ');
184787d58f2SPoul-Henning Kamp 
185ce02431fSDoug Rabson 		if (oidp->oid_handler)
18661220614SPoul-Henning Kamp 			printf(" *Handler");
18761220614SPoul-Henning Kamp 
188ce02431fSDoug Rabson 		switch (oidp->oid_kind & CTLTYPE) {
189787d58f2SPoul-Henning Kamp 			case CTLTYPE_NODE:
190787d58f2SPoul-Henning Kamp 				printf(" Node\n");
191ce02431fSDoug Rabson 				if (!oidp->oid_handler) {
192787d58f2SPoul-Henning Kamp 					sysctl_sysctl_debug_dump_node(
193ce02431fSDoug Rabson 						oidp->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 {
209ce02431fSDoug Rabson 	sysctl_sysctl_debug_dump_node(&sysctl__children, 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;
221ce02431fSDoug Rabson 	int error = 0;
222ce02431fSDoug Rabson 	struct sysctl_oid *oid;
2237f4173ccSPoul-Henning Kamp 	struct sysctl_oid_list *lsp = &sysctl__children, *lsp2;
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 		}
2397f4173ccSPoul-Henning Kamp 		lsp2 = 0;
240ce02431fSDoug Rabson 		SLIST_FOREACH(oid, lsp, oid_link) {
241ce02431fSDoug Rabson 			if (oid->oid_number != *name)
242946bb7a2SPoul-Henning Kamp 				continue;
243946bb7a2SPoul-Henning Kamp 
244946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
245946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
246946bb7a2SPoul-Henning Kamp 			if (!error)
247ce02431fSDoug Rabson 				error = SYSCTL_OUT(req, oid->oid_name,
248ce02431fSDoug Rabson 					strlen(oid->oid_name));
249946bb7a2SPoul-Henning Kamp 			if (error)
250946bb7a2SPoul-Henning Kamp 				return (error);
251946bb7a2SPoul-Henning Kamp 
252946bb7a2SPoul-Henning Kamp 			namelen--;
253946bb7a2SPoul-Henning Kamp 			name++;
254946bb7a2SPoul-Henning Kamp 
255ce02431fSDoug Rabson 			if ((oid->oid_kind & CTLTYPE) != CTLTYPE_NODE)
256946bb7a2SPoul-Henning Kamp 				break;
257946bb7a2SPoul-Henning Kamp 
258ce02431fSDoug Rabson 			if (oid->oid_handler)
259946bb7a2SPoul-Henning Kamp 				break;
260946bb7a2SPoul-Henning Kamp 
2617f4173ccSPoul-Henning Kamp 			lsp2 = (struct sysctl_oid_list *)oid->oid_arg1;
262946bb7a2SPoul-Henning Kamp 			break;
263946bb7a2SPoul-Henning Kamp 		}
2647f4173ccSPoul-Henning Kamp 		lsp = lsp2;
265946bb7a2SPoul-Henning Kamp 	}
266946bb7a2SPoul-Henning Kamp 	return (SYSCTL_OUT(req, "", 1));
267946bb7a2SPoul-Henning Kamp }
268946bb7a2SPoul-Henning Kamp 
269946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
270946bb7a2SPoul-Henning Kamp 
271946bb7a2SPoul-Henning Kamp static int
272ce02431fSDoug Rabson sysctl_sysctl_next_ls (struct sysctl_oid_list *lsp, int *name, u_int namelen,
273ce02431fSDoug Rabson 	int *next, int *len, int level, struct sysctl_oid **oidpp)
274946bb7a2SPoul-Henning Kamp {
275ce02431fSDoug Rabson 	struct sysctl_oid *oidp;
276946bb7a2SPoul-Henning Kamp 
277946bb7a2SPoul-Henning Kamp 	*len = level;
278ce02431fSDoug Rabson 	SLIST_FOREACH(oidp, lsp, oid_link) {
279ce02431fSDoug Rabson 		*next = oidp->oid_number;
280ce02431fSDoug Rabson 		*oidpp = oidp;
281946bb7a2SPoul-Henning Kamp 
282946bb7a2SPoul-Henning Kamp 		if (!namelen) {
283ce02431fSDoug Rabson 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
284946bb7a2SPoul-Henning Kamp 				return 0;
285ce02431fSDoug Rabson 			if (oidp->oid_handler)
286946bb7a2SPoul-Henning Kamp 				/* We really should call the handler here...*/
287946bb7a2SPoul-Henning Kamp 				return 0;
288ce02431fSDoug Rabson 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
28961220614SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
290ce02431fSDoug Rabson 				len, level+1, oidpp))
29161220614SPoul-Henning Kamp 				return 0;
29261220614SPoul-Henning Kamp 			goto next;
293946bb7a2SPoul-Henning Kamp 		}
294946bb7a2SPoul-Henning Kamp 
295ce02431fSDoug Rabson 		if (oidp->oid_number < *name)
296946bb7a2SPoul-Henning Kamp 			continue;
297946bb7a2SPoul-Henning Kamp 
298ce02431fSDoug Rabson 		if (oidp->oid_number > *name) {
299ce02431fSDoug Rabson 			if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
300946bb7a2SPoul-Henning Kamp 				return 0;
301ce02431fSDoug Rabson 			if (oidp->oid_handler)
302946bb7a2SPoul-Henning Kamp 				return 0;
303ce02431fSDoug Rabson 			lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
304946bb7a2SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
305ce02431fSDoug Rabson 				next+1, len, level+1, oidpp))
306946bb7a2SPoul-Henning Kamp 				return (0);
30761220614SPoul-Henning Kamp 			goto next;
308946bb7a2SPoul-Henning Kamp 		}
309ce02431fSDoug Rabson 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
310946bb7a2SPoul-Henning Kamp 			continue;
311946bb7a2SPoul-Henning Kamp 
312ce02431fSDoug Rabson 		if (oidp->oid_handler)
313946bb7a2SPoul-Henning Kamp 			continue;
314946bb7a2SPoul-Henning Kamp 
315ce02431fSDoug Rabson 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
316946bb7a2SPoul-Henning Kamp 		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
317ce02431fSDoug Rabson 			len, level+1, oidpp))
318946bb7a2SPoul-Henning Kamp 			return (0);
31961220614SPoul-Henning Kamp 	next:
320946bb7a2SPoul-Henning Kamp 		namelen = 1;
321946bb7a2SPoul-Henning Kamp 		*len = level;
322946bb7a2SPoul-Henning Kamp 	}
323946bb7a2SPoul-Henning Kamp 	return 1;
324946bb7a2SPoul-Henning Kamp }
325946bb7a2SPoul-Henning Kamp 
326946bb7a2SPoul-Henning Kamp static int
327946bb7a2SPoul-Henning Kamp sysctl_sysctl_next SYSCTL_HANDLER_ARGS
328946bb7a2SPoul-Henning Kamp {
329946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
330946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
331946bb7a2SPoul-Henning Kamp 	int i, j, error;
332946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *oid;
333ce02431fSDoug Rabson 	struct sysctl_oid_list *lsp = &sysctl__children;
334946bb7a2SPoul-Henning Kamp 	int newoid[CTL_MAXNAME];
335946bb7a2SPoul-Henning Kamp 
336946bb7a2SPoul-Henning Kamp 	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
337946bb7a2SPoul-Henning Kamp 	if (i)
338946bb7a2SPoul-Henning Kamp 		return ENOENT;
339946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
340946bb7a2SPoul-Henning Kamp 	return (error);
341946bb7a2SPoul-Henning Kamp }
342946bb7a2SPoul-Henning Kamp 
343946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
344946bb7a2SPoul-Henning Kamp 
345946bb7a2SPoul-Henning Kamp static int
346ce02431fSDoug Rabson name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidpp)
347946bb7a2SPoul-Henning Kamp {
348ce02431fSDoug Rabson 	int i;
349ce02431fSDoug Rabson 	struct sysctl_oid *oidp;
350ce02431fSDoug Rabson 	struct sysctl_oid_list *lsp = &sysctl__children;
351946bb7a2SPoul-Henning Kamp 	char *p;
352946bb7a2SPoul-Henning Kamp 
353946bb7a2SPoul-Henning Kamp 	if (!*name)
354946bb7a2SPoul-Henning Kamp 		return ENOENT;
355946bb7a2SPoul-Henning Kamp 
356946bb7a2SPoul-Henning Kamp 	p = name + strlen(name) - 1 ;
357946bb7a2SPoul-Henning Kamp 	if (*p == '.')
358946bb7a2SPoul-Henning Kamp 		*p = '\0';
359946bb7a2SPoul-Henning Kamp 
360946bb7a2SPoul-Henning Kamp 	*len = 0;
361946bb7a2SPoul-Henning Kamp 
362946bb7a2SPoul-Henning Kamp 	for (p = name; *p && *p != '.'; p++)
363946bb7a2SPoul-Henning Kamp 		;
364946bb7a2SPoul-Henning Kamp 	i = *p;
365946bb7a2SPoul-Henning Kamp 	if (i == '.')
366946bb7a2SPoul-Henning Kamp 		*p = '\0';
367946bb7a2SPoul-Henning Kamp 
368ce02431fSDoug Rabson 	oidp = SLIST_FIRST(lsp);
369946bb7a2SPoul-Henning Kamp 
370ce02431fSDoug Rabson 	while (oidp && *len < CTL_MAXNAME) {
371ce02431fSDoug Rabson 		if (strcmp(name, oidp->oid_name)) {
372ce02431fSDoug Rabson 			oidp = SLIST_NEXT(oidp, oid_link);
373946bb7a2SPoul-Henning Kamp 			continue;
374946bb7a2SPoul-Henning Kamp 		}
375ce02431fSDoug Rabson 		*oid++ = oidp->oid_number;
376946bb7a2SPoul-Henning Kamp 		(*len)++;
377946bb7a2SPoul-Henning Kamp 
378946bb7a2SPoul-Henning Kamp 		if (!i) {
379ce02431fSDoug Rabson 			if (oidpp)
380ce02431fSDoug Rabson 				*oidpp = oidp;
381946bb7a2SPoul-Henning Kamp 			return (0);
382946bb7a2SPoul-Henning Kamp 		}
383946bb7a2SPoul-Henning Kamp 
384ce02431fSDoug Rabson 		if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE)
385946bb7a2SPoul-Henning Kamp 			break;
386946bb7a2SPoul-Henning Kamp 
387ce02431fSDoug Rabson 		if (oidp->oid_handler)
388946bb7a2SPoul-Henning Kamp 			break;
389946bb7a2SPoul-Henning Kamp 
390ce02431fSDoug Rabson 		lsp = (struct sysctl_oid_list *)oidp->oid_arg1;
391ce02431fSDoug Rabson 		oidp = SLIST_FIRST(lsp);
392946bb7a2SPoul-Henning Kamp 		name = p+1;
393946bb7a2SPoul-Henning Kamp 		for (p = name; *p && *p != '.'; p++)
394946bb7a2SPoul-Henning Kamp 				;
395946bb7a2SPoul-Henning Kamp 		i = *p;
396946bb7a2SPoul-Henning Kamp 		if (i == '.')
397946bb7a2SPoul-Henning Kamp 			*p = '\0';
398946bb7a2SPoul-Henning Kamp 	}
399946bb7a2SPoul-Henning Kamp 	return ENOENT;
400946bb7a2SPoul-Henning Kamp }
401946bb7a2SPoul-Henning Kamp 
402946bb7a2SPoul-Henning Kamp static int
403946bb7a2SPoul-Henning Kamp sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
404946bb7a2SPoul-Henning Kamp {
405946bb7a2SPoul-Henning Kamp 	char *p;
406946bb7a2SPoul-Henning Kamp 	int error, oid[CTL_MAXNAME], len;
407946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *op = 0;
408946bb7a2SPoul-Henning Kamp 
409946bb7a2SPoul-Henning Kamp 	if (!req->newlen)
410946bb7a2SPoul-Henning Kamp 		return ENOENT;
411946bb7a2SPoul-Henning Kamp 
412946bb7a2SPoul-Henning Kamp 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
413946bb7a2SPoul-Henning Kamp 
414946bb7a2SPoul-Henning Kamp 	error = SYSCTL_IN(req, p, req->newlen);
415946bb7a2SPoul-Henning Kamp 	if (error) {
416946bb7a2SPoul-Henning Kamp 		free(p, M_SYSCTL);
417946bb7a2SPoul-Henning Kamp 		return (error);
418946bb7a2SPoul-Henning Kamp 	}
419946bb7a2SPoul-Henning Kamp 
420946bb7a2SPoul-Henning Kamp 	p [req->newlen] = '\0';
421946bb7a2SPoul-Henning Kamp 
422946bb7a2SPoul-Henning Kamp 	error = name2oid(p, oid, &len, &op);
423946bb7a2SPoul-Henning Kamp 
424946bb7a2SPoul-Henning Kamp 	free(p, M_SYSCTL);
425946bb7a2SPoul-Henning Kamp 
426946bb7a2SPoul-Henning Kamp 	if (error)
427946bb7a2SPoul-Henning Kamp 		return (error);
428946bb7a2SPoul-Henning Kamp 
429946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
430946bb7a2SPoul-Henning Kamp 	return (error);
431946bb7a2SPoul-Henning Kamp }
432946bb7a2SPoul-Henning Kamp 
4333ac9f819SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
434946bb7a2SPoul-Henning Kamp 	sysctl_sysctl_name2oid, "I", "");
435946bb7a2SPoul-Henning Kamp 
436946bb7a2SPoul-Henning Kamp static int
437946bb7a2SPoul-Henning Kamp sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
438946bb7a2SPoul-Henning Kamp {
43965d0bc13SPoul-Henning Kamp 	int *name = (int *) arg1, error;
440946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
441ce02431fSDoug Rabson 	int indx;
442ce02431fSDoug Rabson 	struct sysctl_oid *oid;
443ce02431fSDoug Rabson 	struct sysctl_oid_list *lsp = &sysctl__children;
444946bb7a2SPoul-Henning Kamp 
445ce02431fSDoug Rabson 	oid = SLIST_FIRST(lsp);
446946bb7a2SPoul-Henning Kamp 
447946bb7a2SPoul-Henning Kamp 	indx = 0;
448ce02431fSDoug Rabson 	while (oid && indx < CTL_MAXNAME) {
449ce02431fSDoug Rabson 		if (oid->oid_number == name[indx]) {
450946bb7a2SPoul-Henning Kamp 			indx++;
451ce02431fSDoug Rabson 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
452ce02431fSDoug Rabson 				if (oid->oid_handler)
453946bb7a2SPoul-Henning Kamp 					goto found;
454946bb7a2SPoul-Henning Kamp 				if (indx == namelen)
45565d0bc13SPoul-Henning Kamp 					goto found;
456ce02431fSDoug Rabson 				lsp = (struct sysctl_oid_list *)oid->oid_arg1;
457ce02431fSDoug Rabson 				oid = SLIST_FIRST(lsp);
458946bb7a2SPoul-Henning Kamp 			} else {
459946bb7a2SPoul-Henning Kamp 				if (indx != namelen)
460946bb7a2SPoul-Henning Kamp 					return EISDIR;
461946bb7a2SPoul-Henning Kamp 				goto found;
462946bb7a2SPoul-Henning Kamp 			}
463946bb7a2SPoul-Henning Kamp 		} else {
464ce02431fSDoug Rabson 			oid = SLIST_NEXT(oid, oid_link);
465946bb7a2SPoul-Henning Kamp 		}
466946bb7a2SPoul-Henning Kamp 	}
467946bb7a2SPoul-Henning Kamp 	return ENOENT;
468946bb7a2SPoul-Henning Kamp found:
469ce02431fSDoug Rabson 	if (!oid->oid_fmt)
470946bb7a2SPoul-Henning Kamp 		return ENOENT;
47165d0bc13SPoul-Henning Kamp 	error = SYSCTL_OUT(req,
472ce02431fSDoug Rabson 		&oid->oid_kind, sizeof(oid->oid_kind));
47365d0bc13SPoul-Henning Kamp 	if (!error)
474ce02431fSDoug Rabson 		error = SYSCTL_OUT(req, oid->oid_fmt,
475ce02431fSDoug Rabson 			strlen(oid->oid_fmt)+1);
47665d0bc13SPoul-Henning Kamp 	return (error);
477946bb7a2SPoul-Henning Kamp }
478946bb7a2SPoul-Henning Kamp 
47986415b71SPoul-Henning Kamp 
480946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
481946bb7a2SPoul-Henning Kamp 
482946bb7a2SPoul-Henning Kamp /*
483946bb7a2SPoul-Henning Kamp  * Default "handler" functions.
484946bb7a2SPoul-Henning Kamp  */
4852e210993SPoul-Henning Kamp 
486ae0eb976SPoul-Henning Kamp /*
487486bddb0SDoug Rabson  * Handle an int, signed or unsigned.
488ae0eb976SPoul-Henning Kamp  * Two cases:
489ae0eb976SPoul-Henning Kamp  *     a variable:  point arg1 at it.
490ae0eb976SPoul-Henning Kamp  *     a constant:  pass it in arg2.
491ae0eb976SPoul-Henning Kamp  */
492ae0eb976SPoul-Henning Kamp 
4933a34a5c3SPoul-Henning Kamp int
4943a34a5c3SPoul-Henning Kamp sysctl_handle_int SYSCTL_HANDLER_ARGS
495b396cd83SPoul-Henning Kamp {
496ae0eb976SPoul-Henning Kamp 	int error = 0;
497b396cd83SPoul-Henning Kamp 
498ae0eb976SPoul-Henning Kamp 	if (arg1)
499ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, arg1, sizeof(int));
5001fbf1f71SBruce Evans 	else
501ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
502b396cd83SPoul-Henning Kamp 
503ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
504ae0eb976SPoul-Henning Kamp 		return (error);
505b396cd83SPoul-Henning Kamp 
506ae0eb976SPoul-Henning Kamp 	if (!arg1)
507ae0eb976SPoul-Henning Kamp 		error = EPERM;
508ae0eb976SPoul-Henning Kamp 	else
509ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, sizeof(int));
510ae0eb976SPoul-Henning Kamp 	return (error);
511b396cd83SPoul-Henning Kamp }
512b396cd83SPoul-Henning Kamp 
513ae0eb976SPoul-Henning Kamp /*
514486bddb0SDoug Rabson  * Handle a long, signed or unsigned.
515069e9bc1SDoug Rabson  * Two cases:
516069e9bc1SDoug Rabson  *     a variable:  point arg1 at it.
517069e9bc1SDoug Rabson  *     a constant:  pass it in arg2.
518069e9bc1SDoug Rabson  */
519069e9bc1SDoug Rabson 
520069e9bc1SDoug Rabson int
521069e9bc1SDoug Rabson sysctl_handle_long SYSCTL_HANDLER_ARGS
522069e9bc1SDoug Rabson {
523069e9bc1SDoug Rabson 	int error = 0;
524069e9bc1SDoug Rabson 
525069e9bc1SDoug Rabson 	error = SYSCTL_OUT(req, arg1, sizeof(long));
526069e9bc1SDoug Rabson 
527069e9bc1SDoug Rabson 	if (error || !req->newptr)
528069e9bc1SDoug Rabson 		return (error);
529069e9bc1SDoug Rabson 
530069e9bc1SDoug Rabson 	if (!arg1)
531069e9bc1SDoug Rabson 		error = EPERM;
532069e9bc1SDoug Rabson 	else
533069e9bc1SDoug Rabson 		error = SYSCTL_IN(req, arg1, sizeof(long));
534069e9bc1SDoug Rabson 	return (error);
535069e9bc1SDoug Rabson }
536069e9bc1SDoug Rabson 
537069e9bc1SDoug Rabson /*
538ae0eb976SPoul-Henning Kamp  * Handle our generic '\0' terminated 'C' string.
539ae0eb976SPoul-Henning Kamp  * Two cases:
540ae0eb976SPoul-Henning Kamp  * 	a variable string:  point arg1 at it, arg2 is max length.
541ae0eb976SPoul-Henning Kamp  * 	a constant string:  point arg1 at it, arg2 is zero.
542ae0eb976SPoul-Henning Kamp  */
543ae0eb976SPoul-Henning Kamp 
5443a34a5c3SPoul-Henning Kamp int
5453a34a5c3SPoul-Henning Kamp sysctl_handle_string SYSCTL_HANDLER_ARGS
546b396cd83SPoul-Henning Kamp {
547ae0eb976SPoul-Henning Kamp 	int error=0;
548b396cd83SPoul-Henning Kamp 
549ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
550b396cd83SPoul-Henning Kamp 
551deae269aSPoul-Henning Kamp 	if (error || !req->newptr || !arg2)
552ae0eb976SPoul-Henning Kamp 		return (error);
553ae0eb976SPoul-Henning Kamp 
554ae0eb976SPoul-Henning Kamp 	if ((req->newlen - req->newidx) > arg2) {
555ae0eb976SPoul-Henning Kamp 		error = E2BIG;
556ae0eb976SPoul-Henning Kamp 	} else {
557ae0eb976SPoul-Henning Kamp 		arg2 = (req->newlen - req->newidx);
558ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, arg2);
559ae0eb976SPoul-Henning Kamp 		((char *)arg1)[arg2] = '\0';
560b396cd83SPoul-Henning Kamp 	}
561b396cd83SPoul-Henning Kamp 
5622e210993SPoul-Henning Kamp 	return (error);
563b396cd83SPoul-Henning Kamp }
564b396cd83SPoul-Henning Kamp 
565ae0eb976SPoul-Henning Kamp /*
566ae0eb976SPoul-Henning Kamp  * Handle any kind of opaque data.
567ae0eb976SPoul-Henning Kamp  * arg1 points to it, arg2 is the size.
568ae0eb976SPoul-Henning Kamp  */
569ae0eb976SPoul-Henning Kamp 
5703a34a5c3SPoul-Henning Kamp int
5713a34a5c3SPoul-Henning Kamp sysctl_handle_opaque SYSCTL_HANDLER_ARGS
572b396cd83SPoul-Henning Kamp {
573ae0eb976SPoul-Henning Kamp 	int error;
574b396cd83SPoul-Henning Kamp 
575ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, arg2);
576b396cd83SPoul-Henning Kamp 
577ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
578ae0eb976SPoul-Henning Kamp 		return (error);
579ae0eb976SPoul-Henning Kamp 
580ae0eb976SPoul-Henning Kamp 	error = SYSCTL_IN(req, arg1, arg2);
581ae0eb976SPoul-Henning Kamp 
582ae0eb976SPoul-Henning Kamp 	return (error);
583b396cd83SPoul-Henning Kamp }
584ae0eb976SPoul-Henning Kamp 
585deae269aSPoul-Henning Kamp /*
586deae269aSPoul-Henning Kamp  * Transfer functions to/from kernel space.
587deae269aSPoul-Henning Kamp  * XXX: rather untested at this point
588deae269aSPoul-Henning Kamp  */
589deae269aSPoul-Henning Kamp static int
590069e9bc1SDoug Rabson sysctl_old_kernel(struct sysctl_req *req, const void *p, size_t l)
591ae0eb976SPoul-Henning Kamp {
592069e9bc1SDoug Rabson 	size_t i = 0;
593deae269aSPoul-Henning Kamp 
594deae269aSPoul-Henning Kamp 	if (req->oldptr) {
595069e9bc1SDoug Rabson 		i = l;
596069e9bc1SDoug Rabson 		if (i > req->oldlen - req->oldidx)
597069e9bc1SDoug Rabson 			i = req->oldlen - req->oldidx;
598deae269aSPoul-Henning Kamp 		if (i > 0)
59909a8dfa2SBruce Evans 			bcopy(p, (char *)req->oldptr + req->oldidx, i);
600ae0eb976SPoul-Henning Kamp 	}
601deae269aSPoul-Henning Kamp 	req->oldidx += l;
6021c346c70SNate Williams 	if (req->oldptr && i != l)
603ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
6042e210993SPoul-Henning Kamp 	return (0);
605ae0eb976SPoul-Henning Kamp }
606ae0eb976SPoul-Henning Kamp 
607deae269aSPoul-Henning Kamp static int
608069e9bc1SDoug Rabson sysctl_new_kernel(struct sysctl_req *req, void *p, size_t l)
609ae0eb976SPoul-Henning Kamp {
610deae269aSPoul-Henning Kamp 	if (!req->newptr)
611deae269aSPoul-Henning Kamp 		return 0;
612deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
613ae0eb976SPoul-Henning Kamp 		return (EINVAL);
61409a8dfa2SBruce Evans 	bcopy((char *)req->newptr + req->newidx, p, l);
615ae0eb976SPoul-Henning Kamp 	req->newidx += l;
616ae0eb976SPoul-Henning Kamp 	return (0);
617ae0eb976SPoul-Henning Kamp }
618ae0eb976SPoul-Henning Kamp 
6191c346c70SNate Williams int
620069e9bc1SDoug Rabson kernel_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen, size_t *retval)
6211c346c70SNate Williams {
6221c346c70SNate Williams 	int error = 0;
6231c346c70SNate Williams 	struct sysctl_req req;
6241c346c70SNate Williams 
6251c346c70SNate Williams 	bzero(&req, sizeof req);
6261c346c70SNate Williams 
6271c346c70SNate Williams 	req.p = p;
6281c346c70SNate Williams 
6291c346c70SNate Williams 	if (oldlenp) {
6301c346c70SNate Williams 		req.oldlen = *oldlenp;
6311c346c70SNate Williams 	}
6321c346c70SNate Williams 
6331c346c70SNate Williams 	if (old) {
6341c346c70SNate Williams 		req.oldptr= old;
6351c346c70SNate Williams 	}
6361c346c70SNate Williams 
6371c346c70SNate Williams 	if (newlen) {
6381c346c70SNate Williams 		req.newlen = newlen;
6391c346c70SNate Williams 		req.newptr = new;
6401c346c70SNate Williams 	}
6411c346c70SNate Williams 
6421c346c70SNate Williams 	req.oldfunc = sysctl_old_kernel;
6431c346c70SNate Williams 	req.newfunc = sysctl_new_kernel;
6441c346c70SNate Williams 	req.lock = 1;
6451c346c70SNate Williams 
6461c346c70SNate Williams 	/* XXX this should probably be done in a general way */
6471c346c70SNate Williams 	while (memlock.sl_lock) {
6481c346c70SNate Williams 		memlock.sl_want = 1;
6491c346c70SNate Williams 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
6501c346c70SNate Williams 		memlock.sl_locked++;
6511c346c70SNate Williams 	}
6521c346c70SNate Williams 	memlock.sl_lock = 1;
6531c346c70SNate Williams 
6541c346c70SNate Williams 	error = sysctl_root(0, name, namelen, &req);
6551c346c70SNate Williams 
6561c346c70SNate Williams 	if (req.lock == 2)
6571c346c70SNate Williams 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
6581c346c70SNate Williams 
6591c346c70SNate Williams 	memlock.sl_lock = 0;
6601c346c70SNate Williams 
6611c346c70SNate Williams 	if (memlock.sl_want) {
6621c346c70SNate Williams 		memlock.sl_want = 0;
6631c346c70SNate Williams 		wakeup((caddr_t)&memlock);
6641c346c70SNate Williams 	}
6651c346c70SNate Williams 
6661c346c70SNate Williams 	if (error && error != ENOMEM)
6671c346c70SNate Williams 		return (error);
6681c346c70SNate Williams 
6691c346c70SNate Williams 	if (retval) {
6701c346c70SNate Williams 		if (req.oldptr && req.oldidx > req.oldlen)
6711c346c70SNate Williams 			*retval = req.oldlen;
6721c346c70SNate Williams 		else
6731c346c70SNate Williams 			*retval = req.oldidx;
6741c346c70SNate Williams 	}
6751c346c70SNate Williams 	return (error);
6761c346c70SNate Williams }
6771c346c70SNate Williams 
678deae269aSPoul-Henning Kamp /*
679deae269aSPoul-Henning Kamp  * Transfer function to/from user space.
680deae269aSPoul-Henning Kamp  */
681deae269aSPoul-Henning Kamp static int
682069e9bc1SDoug Rabson sysctl_old_user(struct sysctl_req *req, const void *p, size_t l)
683ae0eb976SPoul-Henning Kamp {
684069e9bc1SDoug Rabson 	int error = 0;
685069e9bc1SDoug Rabson 	size_t i = 0;
686ae0eb976SPoul-Henning Kamp 
6874b2af45fSPoul-Henning Kamp 	if (req->lock == 1 && req->oldptr) {
6884b2af45fSPoul-Henning Kamp 		vslock(req->oldptr, req->oldlen);
6894b2af45fSPoul-Henning Kamp 		req->lock = 2;
6904b2af45fSPoul-Henning Kamp 	}
691deae269aSPoul-Henning Kamp 	if (req->oldptr) {
692069e9bc1SDoug Rabson 		i = l;
693069e9bc1SDoug Rabson 		if (i > req->oldlen - req->oldidx)
694069e9bc1SDoug Rabson 			i = req->oldlen - req->oldidx;
695deae269aSPoul-Henning Kamp 		if (i > 0)
69609a8dfa2SBruce Evans 			error = copyout(p, (char *)req->oldptr + req->oldidx,
69709a8dfa2SBruce Evans 					i);
698deae269aSPoul-Henning Kamp 	}
699deae269aSPoul-Henning Kamp 	req->oldidx += l;
700ae0eb976SPoul-Henning Kamp 	if (error)
701ae0eb976SPoul-Henning Kamp 		return (error);
702deae269aSPoul-Henning Kamp 	if (req->oldptr && i < l)
703ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
704deae269aSPoul-Henning Kamp 	return (0);
705ae0eb976SPoul-Henning Kamp }
706ae0eb976SPoul-Henning Kamp 
707deae269aSPoul-Henning Kamp static int
708069e9bc1SDoug Rabson sysctl_new_user(struct sysctl_req *req, void *p, size_t l)
709ae0eb976SPoul-Henning Kamp {
71016cd04a3SPoul-Henning Kamp 	int error;
711deae269aSPoul-Henning Kamp 
712deae269aSPoul-Henning Kamp 	if (!req->newptr)
713deae269aSPoul-Henning Kamp 		return 0;
714deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
715ae0eb976SPoul-Henning Kamp 		return (EINVAL);
71609a8dfa2SBruce Evans 	error = copyin((char *)req->newptr + req->newidx, p, l);
717ae0eb976SPoul-Henning Kamp 	req->newidx += l;
718ae0eb976SPoul-Henning Kamp 	return (error);
719b396cd83SPoul-Henning Kamp }
720b396cd83SPoul-Henning Kamp 
721df8bae1dSRodney W. Grimes /*
7222e210993SPoul-Henning Kamp  * Traverse our tree, and find the right node, execute whatever it points
7232e210993SPoul-Henning Kamp  * at, and return the resulting error code.
7242e210993SPoul-Henning Kamp  */
7252e210993SPoul-Henning Kamp 
7262e210993SPoul-Henning Kamp int
7272e210993SPoul-Henning Kamp sysctl_root SYSCTL_HANDLER_ARGS
7282e210993SPoul-Henning Kamp {
7292e210993SPoul-Henning Kamp 	int *name = (int *) arg1;
730946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
731ce02431fSDoug Rabson 	int indx, i;
732ce02431fSDoug Rabson 	struct sysctl_oid *oid;
733ce02431fSDoug Rabson 	struct sysctl_oid_list *lsp = &sysctl__children;
7342e210993SPoul-Henning Kamp 
735ce02431fSDoug Rabson 	oid = SLIST_FIRST(lsp);
7362e210993SPoul-Henning Kamp 
7372e210993SPoul-Henning Kamp 	indx = 0;
738ce02431fSDoug Rabson 	while (oid && indx < CTL_MAXNAME) {
739ce02431fSDoug Rabson 		if (oid->oid_number == name[indx]) {
7402e210993SPoul-Henning Kamp 			indx++;
741ce02431fSDoug Rabson 			if (oid->oid_kind & CTLFLAG_NOLOCK)
7424b2af45fSPoul-Henning Kamp 				req->lock = 0;
743ce02431fSDoug Rabson 			if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
744ce02431fSDoug Rabson 				if (oid->oid_handler)
7452e210993SPoul-Henning Kamp 					goto found;
7462e210993SPoul-Henning Kamp 				if (indx == namelen)
7472e210993SPoul-Henning Kamp 					return ENOENT;
748ce02431fSDoug Rabson 				lsp = (struct sysctl_oid_list *)oid->oid_arg1;
749ce02431fSDoug Rabson 				oid = SLIST_FIRST(lsp);
7502e210993SPoul-Henning Kamp 			} else {
7512e210993SPoul-Henning Kamp 				if (indx != namelen)
7522e210993SPoul-Henning Kamp 					return EISDIR;
7532e210993SPoul-Henning Kamp 				goto found;
7542e210993SPoul-Henning Kamp 			}
7552e210993SPoul-Henning Kamp 		} else {
756ce02431fSDoug Rabson 			oid = SLIST_NEXT(oid, oid_link);
7572e210993SPoul-Henning Kamp 		}
7582e210993SPoul-Henning Kamp 	}
759deae269aSPoul-Henning Kamp 	return ENOENT;
7602e210993SPoul-Henning Kamp found:
7612e210993SPoul-Henning Kamp 	/* If writing isn't allowed */
762ce02431fSDoug Rabson 	if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) ||
763ce02431fSDoug Rabson 	    ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0)))
7642e210993SPoul-Henning Kamp 		return (EPERM);
7652e210993SPoul-Henning Kamp 
7663ac9f819SPoul-Henning Kamp 	/* Most likely only root can write */
767ce02431fSDoug Rabson 	if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
7683ac9f819SPoul-Henning Kamp 	    req->newptr && req->p &&
7693ac9f819SPoul-Henning Kamp 	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
7703ac9f819SPoul-Henning Kamp 		return (i);
7713ac9f819SPoul-Henning Kamp 
772ce02431fSDoug Rabson 	if (!oid->oid_handler)
7732e210993SPoul-Henning Kamp 		return EINVAL;
7742e210993SPoul-Henning Kamp 
775ce02431fSDoug Rabson 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
776ce02431fSDoug Rabson 		i = (oid->oid_handler) (oid,
7772e210993SPoul-Henning Kamp 					name + indx, namelen - indx,
778ae0eb976SPoul-Henning Kamp 					req);
7792e210993SPoul-Henning Kamp 	} else {
780ce02431fSDoug Rabson 		i = (oid->oid_handler) (oid,
781ce02431fSDoug Rabson 					oid->oid_arg1, oid->oid_arg2,
782ae0eb976SPoul-Henning Kamp 					req);
7832e210993SPoul-Henning Kamp 	}
7842e210993SPoul-Henning Kamp 	return (i);
7852e210993SPoul-Henning Kamp }
7862e210993SPoul-Henning Kamp 
787d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
788b8da2396SPoul-Henning Kamp struct sysctl_args {
789b8da2396SPoul-Henning Kamp 	int	*name;
790b8da2396SPoul-Henning Kamp 	u_int	namelen;
791b8da2396SPoul-Henning Kamp 	void	*old;
792b8da2396SPoul-Henning Kamp 	size_t	*oldlenp;
793b8da2396SPoul-Henning Kamp 	void	*new;
794b8da2396SPoul-Henning Kamp 	size_t	newlen;
795b8da2396SPoul-Henning Kamp };
796d2d3e875SBruce Evans #endif
797b8da2396SPoul-Henning Kamp 
798df8bae1dSRodney W. Grimes int
799cb226aaaSPoul-Henning Kamp __sysctl(struct proc *p, struct sysctl_args *uap)
800df8bae1dSRodney W. Grimes {
801069e9bc1SDoug Rabson 	int error, i, name[CTL_MAXNAME];
802069e9bc1SDoug Rabson 	size_t j;
803b396cd83SPoul-Henning Kamp 
804df8bae1dSRodney W. Grimes 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
805df8bae1dSRodney W. Grimes 		return (EINVAL);
806b396cd83SPoul-Henning Kamp 
807797f2d22SPoul-Henning Kamp  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
808797f2d22SPoul-Henning Kamp  	if (error)
809df8bae1dSRodney W. Grimes 		return (error);
810df8bae1dSRodney W. Grimes 
811deae269aSPoul-Henning Kamp 	error = userland_sysctl(p, name, uap->namelen,
812b8da2396SPoul-Henning Kamp 		uap->old, uap->oldlenp, 0,
813deae269aSPoul-Henning Kamp 		uap->new, uap->newlen, &j);
814deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
815deae269aSPoul-Henning Kamp 		return (error);
816deae269aSPoul-Henning Kamp 	if (uap->oldlenp) {
817deae269aSPoul-Henning Kamp 		i = copyout(&j, uap->oldlenp, sizeof(j));
818deae269aSPoul-Henning Kamp 		if (i)
819deae269aSPoul-Henning Kamp 			return (i);
820deae269aSPoul-Henning Kamp 	}
821deae269aSPoul-Henning Kamp 	return (error);
822b8da2396SPoul-Henning Kamp }
823b8da2396SPoul-Henning Kamp 
824b8da2396SPoul-Henning Kamp /*
825b8da2396SPoul-Henning Kamp  * This is used from various compatibility syscalls too.  That's why name
826b8da2396SPoul-Henning Kamp  * must be in kernel space.
827b8da2396SPoul-Henning Kamp  */
828b8da2396SPoul-Henning Kamp int
829069e9bc1SDoug 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)
830b8da2396SPoul-Henning Kamp {
8314b2af45fSPoul-Henning Kamp 	int error = 0;
8327a69d923SPoul-Henning Kamp 	struct sysctl_req req, req2;
833ae0eb976SPoul-Henning Kamp 
834ae0eb976SPoul-Henning Kamp 	bzero(&req, sizeof req);
835b8da2396SPoul-Henning Kamp 
83616cd04a3SPoul-Henning Kamp 	req.p = p;
83716cd04a3SPoul-Henning Kamp 
838b8da2396SPoul-Henning Kamp 	if (oldlenp) {
839b8da2396SPoul-Henning Kamp 		if (inkernel) {
840ae0eb976SPoul-Henning Kamp 			req.oldlen = *oldlenp;
841b8da2396SPoul-Henning Kamp 		} else {
842deae269aSPoul-Henning Kamp 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
843b8da2396SPoul-Henning Kamp 			if (error)
844b8da2396SPoul-Henning Kamp 				return (error);
845b8da2396SPoul-Henning Kamp 		}
846b8da2396SPoul-Henning Kamp 	}
847b8da2396SPoul-Henning Kamp 
848ae0eb976SPoul-Henning Kamp 	if (old) {
849ae0eb976SPoul-Henning Kamp 		if (!useracc(old, req.oldlen, B_WRITE))
850ae0eb976SPoul-Henning Kamp 			return (EFAULT);
851ae0eb976SPoul-Henning Kamp 		req.oldptr= old;
852ae0eb976SPoul-Henning Kamp 	}
8532e210993SPoul-Henning Kamp 
854b8da2396SPoul-Henning Kamp 	if (newlen) {
855ae0eb976SPoul-Henning Kamp 		if (!useracc(new, req.newlen, B_READ))
856ae0eb976SPoul-Henning Kamp 			return (EFAULT);
857ae0eb976SPoul-Henning Kamp 		req.newlen = newlen;
858ae0eb976SPoul-Henning Kamp 		req.newptr = new;
859b396cd83SPoul-Henning Kamp 	}
860b396cd83SPoul-Henning Kamp 
861ae0eb976SPoul-Henning Kamp 	req.oldfunc = sysctl_old_user;
862ae0eb976SPoul-Henning Kamp 	req.newfunc = sysctl_new_user;
8634b2af45fSPoul-Henning Kamp 	req.lock = 1;
8644b2af45fSPoul-Henning Kamp 
8654b2af45fSPoul-Henning Kamp 	/* XXX this should probably be done in a general way */
8664b2af45fSPoul-Henning Kamp 	while (memlock.sl_lock) {
8674b2af45fSPoul-Henning Kamp 		memlock.sl_want = 1;
8684b2af45fSPoul-Henning Kamp 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
8694b2af45fSPoul-Henning Kamp 		memlock.sl_locked++;
8704b2af45fSPoul-Henning Kamp 	}
8714b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 1;
872ae0eb976SPoul-Henning Kamp 
8737a69d923SPoul-Henning Kamp 	do {
8747a69d923SPoul-Henning Kamp 	    req2 = req;
8757a69d923SPoul-Henning Kamp 	    error = sysctl_root(0, name, namelen, &req2);
8767a69d923SPoul-Henning Kamp 	} while (error == EAGAIN);
877b396cd83SPoul-Henning Kamp 
8787a69d923SPoul-Henning Kamp 	req = req2;
8794b2af45fSPoul-Henning Kamp 	if (req.lock == 2)
8804b2af45fSPoul-Henning Kamp 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
8814b2af45fSPoul-Henning Kamp 
8824b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 0;
8834b2af45fSPoul-Henning Kamp 
8844b2af45fSPoul-Henning Kamp 	if (memlock.sl_want) {
8854b2af45fSPoul-Henning Kamp 		memlock.sl_want = 0;
8864b2af45fSPoul-Henning Kamp 		wakeup((caddr_t)&memlock);
8874b2af45fSPoul-Henning Kamp 	}
8884b2af45fSPoul-Henning Kamp 
889deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
890deae269aSPoul-Henning Kamp 		return (error);
891deae269aSPoul-Henning Kamp 
892deae269aSPoul-Henning Kamp 	if (retval) {
893deae269aSPoul-Henning Kamp 		if (req.oldptr && req.oldidx > req.oldlen)
894ae0eb976SPoul-Henning Kamp 			*retval = req.oldlen;
895deae269aSPoul-Henning Kamp 		else
896deae269aSPoul-Henning Kamp 			*retval = req.oldidx;
897b8da2396SPoul-Henning Kamp 	}
8982e210993SPoul-Henning Kamp 	return (error);
899df8bae1dSRodney W. Grimes }
900df8bae1dSRodney W. Grimes 
901df8bae1dSRodney W. Grimes #ifdef COMPAT_43
902df8bae1dSRodney W. Grimes #include <sys/socket.h>
90345ec3b38SPoul-Henning Kamp #include <vm/vm_param.h>
90445ec3b38SPoul-Henning Kamp 
905df8bae1dSRodney W. Grimes #define	KINFO_PROC		(0<<8)
906df8bae1dSRodney W. Grimes #define	KINFO_RT		(1<<8)
907df8bae1dSRodney W. Grimes #define	KINFO_VNODE		(2<<8)
908df8bae1dSRodney W. Grimes #define	KINFO_FILE		(3<<8)
909df8bae1dSRodney W. Grimes #define	KINFO_METER		(4<<8)
910df8bae1dSRodney W. Grimes #define	KINFO_LOADAVG		(5<<8)
911df8bae1dSRodney W. Grimes #define	KINFO_CLOCKRATE		(6<<8)
912df8bae1dSRodney W. Grimes 
9136ece4a51SPeter Wemm /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
9146ece4a51SPeter Wemm #define	KINFO_BSDI_SYSINFO	(101<<8)
9156ece4a51SPeter Wemm 
9166ece4a51SPeter Wemm /*
9176ece4a51SPeter Wemm  * XXX this is bloat, but I hope it's better here than on the potentially
9186ece4a51SPeter Wemm  * limited kernel stack...  -Peter
9196ece4a51SPeter Wemm  */
9206ece4a51SPeter Wemm 
92187b6de2bSPoul-Henning Kamp static struct {
9226ece4a51SPeter Wemm 	int	bsdi_machine;		/* "i386" on BSD/386 */
9236ece4a51SPeter Wemm /*      ^^^ this is an offset to the string, relative to the struct start */
9246ece4a51SPeter Wemm 	char	*pad0;
9256ece4a51SPeter Wemm 	long	pad1;
9266ece4a51SPeter Wemm 	long	pad2;
9276ece4a51SPeter Wemm 	long	pad3;
9286ece4a51SPeter Wemm 	u_long	pad4;
9296ece4a51SPeter Wemm 	u_long	pad5;
9306ece4a51SPeter Wemm 	u_long	pad6;
9316ece4a51SPeter Wemm 
9326ece4a51SPeter Wemm 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
9336ece4a51SPeter Wemm 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
9346ece4a51SPeter Wemm 	long	pad7;
9356ece4a51SPeter Wemm 	long	pad8;
9366ece4a51SPeter Wemm 	char	*pad9;
9376ece4a51SPeter Wemm 
9386ece4a51SPeter Wemm 	long	pad10;
9396ece4a51SPeter Wemm 	long	pad11;
9406ece4a51SPeter Wemm 	int	pad12;
9416ece4a51SPeter Wemm 	long	pad13;
9426ece4a51SPeter Wemm 	quad_t	pad14;
9436ece4a51SPeter Wemm 	long	pad15;
9446ece4a51SPeter Wemm 
9456ece4a51SPeter Wemm 	struct	timeval pad16;
9466ece4a51SPeter Wemm 	/* we dont set this, because BSDI's uname used gethostname() instead */
9476ece4a51SPeter Wemm 	int	bsdi_hostname;		/* hostname on BSD/386 */
9486ece4a51SPeter Wemm 
9496ece4a51SPeter Wemm 	/* the actual string data is appended here */
9506ece4a51SPeter Wemm 
9516ece4a51SPeter Wemm } bsdi_si;
9526ece4a51SPeter Wemm /*
9536ece4a51SPeter Wemm  * this data is appended to the end of the bsdi_si structure during copyout.
9546ece4a51SPeter Wemm  * The "char *" offsets are relative to the base of the bsdi_si struct.
9556ece4a51SPeter Wemm  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
9566ece4a51SPeter Wemm  * should not exceed the length of the buffer here... (or else!! :-)
9576ece4a51SPeter Wemm  */
95887b6de2bSPoul-Henning Kamp static char bsdi_strings[80];	/* It had better be less than this! */
9596ece4a51SPeter Wemm 
960d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
961df8bae1dSRodney W. Grimes struct getkerninfo_args {
962df8bae1dSRodney W. Grimes 	int	op;
963df8bae1dSRodney W. Grimes 	char	*where;
964134e06feSBruce Evans 	size_t	*size;
965df8bae1dSRodney W. Grimes 	int	arg;
966df8bae1dSRodney W. Grimes };
967d2d3e875SBruce Evans #endif
968df8bae1dSRodney W. Grimes 
96926f9a767SRodney W. Grimes int
970cb226aaaSPoul-Henning Kamp ogetkerninfo(struct proc *p, struct getkerninfo_args *uap)
971df8bae1dSRodney W. Grimes {
972b8da2396SPoul-Henning Kamp 	int error, name[6];
973069e9bc1SDoug Rabson 	size_t size;
974df8bae1dSRodney W. Grimes 
975df8bae1dSRodney W. Grimes 	switch (uap->op & 0xff00) {
976df8bae1dSRodney W. Grimes 
977df8bae1dSRodney W. Grimes 	case KINFO_RT:
978b8da2396SPoul-Henning Kamp 		name[0] = CTL_NET;
979b8da2396SPoul-Henning Kamp 		name[1] = PF_ROUTE;
980b8da2396SPoul-Henning Kamp 		name[2] = 0;
981b8da2396SPoul-Henning Kamp 		name[3] = (uap->op & 0xff0000) >> 16;
982b8da2396SPoul-Henning Kamp 		name[4] = uap->op & 0xff;
983b8da2396SPoul-Henning Kamp 		name[5] = uap->arg;
984b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
9854b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
986df8bae1dSRodney W. Grimes 		break;
987df8bae1dSRodney W. Grimes 
988df8bae1dSRodney W. Grimes 	case KINFO_VNODE:
989b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
990b8da2396SPoul-Henning Kamp 		name[1] = KERN_VNODE;
991b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
9924b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
993df8bae1dSRodney W. Grimes 		break;
994df8bae1dSRodney W. Grimes 
995df8bae1dSRodney W. Grimes 	case KINFO_PROC:
996b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
997b8da2396SPoul-Henning Kamp 		name[1] = KERN_PROC;
998b8da2396SPoul-Henning Kamp 		name[2] = uap->op & 0xff;
999b8da2396SPoul-Henning Kamp 		name[3] = uap->arg;
1000b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
10014b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1002df8bae1dSRodney W. Grimes 		break;
1003df8bae1dSRodney W. Grimes 
1004df8bae1dSRodney W. Grimes 	case KINFO_FILE:
1005b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1006b8da2396SPoul-Henning Kamp 		name[1] = KERN_FILE;
1007b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10084b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1009df8bae1dSRodney W. Grimes 		break;
1010df8bae1dSRodney W. Grimes 
1011df8bae1dSRodney W. Grimes 	case KINFO_METER:
1012b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
1013b8da2396SPoul-Henning Kamp 		name[1] = VM_METER;
1014b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10154b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1016df8bae1dSRodney W. Grimes 		break;
1017df8bae1dSRodney W. Grimes 
1018df8bae1dSRodney W. Grimes 	case KINFO_LOADAVG:
1019b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
1020b8da2396SPoul-Henning Kamp 		name[1] = VM_LOADAVG;
1021b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10224b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1023df8bae1dSRodney W. Grimes 		break;
1024df8bae1dSRodney W. Grimes 
1025df8bae1dSRodney W. Grimes 	case KINFO_CLOCKRATE:
1026b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1027b8da2396SPoul-Henning Kamp 		name[1] = KERN_CLOCKRATE;
1028b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10294b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1030df8bae1dSRodney W. Grimes 		break;
1031df8bae1dSRodney W. Grimes 
10326ece4a51SPeter Wemm 	case KINFO_BSDI_SYSINFO: {
10336ece4a51SPeter Wemm 		/*
10346ece4a51SPeter Wemm 		 * this is pretty crude, but it's just enough for uname()
10356ece4a51SPeter Wemm 		 * from BSDI's 1.x libc to work.
10366ece4a51SPeter Wemm 		 *
10376ece4a51SPeter Wemm 		 * In particular, it doesn't return the same results when
10386ece4a51SPeter Wemm 		 * the supplied buffer is too small.  BSDI's version apparently
10396ece4a51SPeter Wemm 		 * will return the amount copied, and set the *size to how
10406ece4a51SPeter Wemm 		 * much was needed.  The emulation framework here isn't capable
10416ece4a51SPeter Wemm 		 * of that, so we just set both to the amount copied.
10426ece4a51SPeter Wemm 		 * BSDI's 2.x product apparently fails with ENOMEM in this
10436ece4a51SPeter Wemm 		 * scenario.
10446ece4a51SPeter Wemm 		 */
10456ece4a51SPeter Wemm 
10466ece4a51SPeter Wemm 		u_int needed;
10476ece4a51SPeter Wemm 		u_int left;
10486ece4a51SPeter Wemm 		char *s;
10496ece4a51SPeter Wemm 
10506ece4a51SPeter Wemm 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
10516ece4a51SPeter Wemm 		bzero(bsdi_strings, sizeof(bsdi_strings));
10526ece4a51SPeter Wemm 
10536ece4a51SPeter Wemm 		s = bsdi_strings;
10546ece4a51SPeter Wemm 
10556ece4a51SPeter Wemm 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
10566ece4a51SPeter Wemm 		strcpy(s, ostype);
10576ece4a51SPeter Wemm 		s += strlen(s) + 1;
10586ece4a51SPeter Wemm 
10596ece4a51SPeter Wemm 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
10606ece4a51SPeter Wemm 		strcpy(s, osrelease);
10616ece4a51SPeter Wemm 		s += strlen(s) + 1;
10626ece4a51SPeter Wemm 
10636ece4a51SPeter Wemm 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
10646ece4a51SPeter Wemm 		strcpy(s, machine);
10656ece4a51SPeter Wemm 		s += strlen(s) + 1;
10666ece4a51SPeter Wemm 
10676ece4a51SPeter Wemm 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
10686ece4a51SPeter Wemm 
10696ece4a51SPeter Wemm 		if (uap->where == NULL) {
10706ece4a51SPeter Wemm 			/* process is asking how much buffer to supply.. */
10716ece4a51SPeter Wemm 			size = needed;
10726ece4a51SPeter Wemm 			error = 0;
10736ece4a51SPeter Wemm 			break;
10746ece4a51SPeter Wemm 		}
10756ece4a51SPeter Wemm 
10766ece4a51SPeter Wemm 
10776ece4a51SPeter Wemm 		/* if too much buffer supplied, trim it down */
10786ece4a51SPeter Wemm 		if (size > needed)
10796ece4a51SPeter Wemm 			size = needed;
10806ece4a51SPeter Wemm 
10816ece4a51SPeter Wemm 		/* how much of the buffer is remaining */
10826ece4a51SPeter Wemm 		left = size;
10836ece4a51SPeter Wemm 
10846ece4a51SPeter Wemm 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
10856ece4a51SPeter Wemm 			break;
10866ece4a51SPeter Wemm 
10876ece4a51SPeter Wemm 		/* is there any point in continuing? */
10886ece4a51SPeter Wemm 		if (left > sizeof(bsdi_si)) {
10896ece4a51SPeter Wemm 			left -= sizeof(bsdi_si);
10906ece4a51SPeter Wemm 			error = copyout(&bsdi_strings,
10916ece4a51SPeter Wemm 					uap->where + sizeof(bsdi_si), left);
10926ece4a51SPeter Wemm 		}
10936ece4a51SPeter Wemm 		break;
10946ece4a51SPeter Wemm 	}
10956ece4a51SPeter Wemm 
1096df8bae1dSRodney W. Grimes 	default:
1097df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1098df8bae1dSRodney W. Grimes 	}
1099df8bae1dSRodney W. Grimes 	if (error)
1100df8bae1dSRodney W. Grimes 		return (error);
1101cb226aaaSPoul-Henning Kamp 	p->p_retval[0] = size;
1102df8bae1dSRodney W. Grimes 	if (uap->size)
1103df8bae1dSRodney W. Grimes 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1104df8bae1dSRodney W. Grimes 		    sizeof(size));
1105df8bae1dSRodney W. Grimes 	return (error);
1106df8bae1dSRodney W. Grimes }
1107df8bae1dSRodney W. Grimes #endif /* COMPAT_43 */
1108