xref: /freebsd/sys/kern/kern_sysctl.c (revision 3ac9f819ae6220840810e456696e197eb69712ec)
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
403ac9f819SPoul-Henning Kamp  * $Id: kern_sysctl.c,v 1.57 1995/12/14 08:31:36 phk Exp $
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes #include <sys/param.h>
44df8bae1dSRodney W. Grimes #include <sys/systm.h>
45d2d3e875SBruce Evans #include <sys/sysproto.h>
46df8bae1dSRodney W. Grimes #include <sys/kernel.h>
47df8bae1dSRodney W. Grimes #include <sys/vnode.h>
48df8bae1dSRodney W. Grimes #include <sys/unistd.h>
495bb4f738SGarrett Wollman #include <sys/conf.h>
50df8bae1dSRodney W. Grimes #include <sys/sysctl.h>
51946bb7a2SPoul-Henning Kamp #include <sys/malloc.h>
52efeaf95aSDavid Greenman #include <sys/proc.h>
53df8bae1dSRodney W. Grimes 
544cb03b1bSBruce Evans #include <vm/vm.h>
55efeaf95aSDavid Greenman #include <vm/vm_param.h>
56efeaf95aSDavid Greenman #include <vm/vm_extern.h>
574cb03b1bSBruce Evans 
584b2af45fSPoul-Henning Kamp /*
594b2af45fSPoul-Henning Kamp  * Locking and stats
604b2af45fSPoul-Henning Kamp  */
614b2af45fSPoul-Henning Kamp static struct sysctl_lock {
624b2af45fSPoul-Henning Kamp 	int	sl_lock;
634b2af45fSPoul-Henning Kamp 	int	sl_want;
644b2af45fSPoul-Henning Kamp 	int	sl_locked;
654b2af45fSPoul-Henning Kamp } memlock;
664b2af45fSPoul-Henning Kamp 
674b2af45fSPoul-Henning Kamp static int sysctl_root SYSCTL_HANDLER_ARGS;
684b2af45fSPoul-Henning Kamp 
69787d58f2SPoul-Henning Kamp extern struct linker_set sysctl_;
70787d58f2SPoul-Henning Kamp 
71946bb7a2SPoul-Henning Kamp /*
72946bb7a2SPoul-Henning Kamp  * MIB definitions.  XXX Very few of these, if any, belong here.
73946bb7a2SPoul-Henning Kamp  */
74787d58f2SPoul-Henning Kamp SYSCTL_NODE(, 0,	  sysctl, CTLFLAG_RW, 0,
75787d58f2SPoul-Henning Kamp 	"Sysctl internal magic");
762e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW, 0,
772e210993SPoul-Henning Kamp 	"High kernel, proc, limits &c");
782e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_VM,	  vm,     CTLFLAG_RW, 0,
792e210993SPoul-Henning Kamp 	"Virtual memory");
802e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_FS,	  fs,     CTLFLAG_RW, 0,
812e210993SPoul-Henning Kamp 	"File system");
822e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
832e210993SPoul-Henning Kamp 	"Network, (see socket.h)");
842e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
852e210993SPoul-Henning Kamp 	"Debugging");
862e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
872e210993SPoul-Henning Kamp 	"hardware");
882e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
892e210993SPoul-Henning Kamp 	"machine dependent");
902e210993SPoul-Henning Kamp SYSCTL_NODE(, CTL_USER,	  user,   CTLFLAG_RW, 0,
912e210993SPoul-Henning Kamp 	"user-level");
92b396cd83SPoul-Henning Kamp 
932e210993SPoul-Henning Kamp SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, "");
94b396cd83SPoul-Henning Kamp 
952e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, "");
96b396cd83SPoul-Henning Kamp 
972e210993SPoul-Henning Kamp SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, "");
98b396cd83SPoul-Henning Kamp 
992e210993SPoul-Henning Kamp SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "");
100b396cd83SPoul-Henning Kamp 
101b396cd83SPoul-Henning Kamp extern int osreldate;
1022e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "");
103b396cd83SPoul-Henning Kamp 
1042e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RD, &maxproc, 0, "");
105b396cd83SPoul-Henning Kamp 
106b396cd83SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid,
1073a34a5c3SPoul-Henning Kamp 	CTLFLAG_RD, &maxprocperuid, 0, "");
108b396cd83SPoul-Henning Kamp 
1092e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, "");
110b396cd83SPoul-Henning Kamp 
1112e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, "");
112b396cd83SPoul-Henning Kamp 
1132e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, "");
114b396cd83SPoul-Henning Kamp 
1152e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, "");
116b396cd83SPoul-Henning Kamp 
117b396cd83SPoul-Henning Kamp #ifdef _POSIX_SAVED_IDS
1182e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, "");
119b396cd83SPoul-Henning Kamp #else
1202e210993SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, "");
121b396cd83SPoul-Henning Kamp #endif
122b396cd83SPoul-Henning Kamp 
123b396cd83SPoul-Henning Kamp char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
124b396cd83SPoul-Henning Kamp 
125b396cd83SPoul-Henning Kamp SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile,
1263a34a5c3SPoul-Henning Kamp 	CTLFLAG_RW, kernelname, sizeof kernelname, "");
127b396cd83SPoul-Henning Kamp 
1282e210993SPoul-Henning Kamp SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, 0, 1, "");
129b396cd83SPoul-Henning Kamp 
1302e210993SPoul-Henning Kamp SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, "");
131b396cd83SPoul-Henning Kamp 
1322e210993SPoul-Henning Kamp SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, "");
133b396cd83SPoul-Henning Kamp 
1342e210993SPoul-Henning Kamp char hostname[MAXHOSTNAMELEN];
1352e210993SPoul-Henning Kamp 
1369565c0e6SPoul-Henning Kamp SYSCTL_STRING(_kern, KERN_HOSTNAME, hostname, CTLFLAG_RW,
1379565c0e6SPoul-Henning Kamp 	hostname, sizeof(hostname), "");
1382e210993SPoul-Henning Kamp 
1394b2af45fSPoul-Henning Kamp int securelevel = -1;
1404b2af45fSPoul-Henning Kamp 
1414b2af45fSPoul-Henning Kamp static int
1424b2af45fSPoul-Henning Kamp sysctl_kern_securelvl SYSCTL_HANDLER_ARGS
1434b2af45fSPoul-Henning Kamp {
1444b2af45fSPoul-Henning Kamp 		int error, level;
1454b2af45fSPoul-Henning Kamp 
1464b2af45fSPoul-Henning Kamp 		level = securelevel;
1474b2af45fSPoul-Henning Kamp 		error = sysctl_handle_int(oidp, &level, 0, req);
1484b2af45fSPoul-Henning Kamp 		if (error || !req->newptr)
1494b2af45fSPoul-Henning Kamp 			return (error);
1504b2af45fSPoul-Henning Kamp 		if (level < securelevel && req->p->p_pid != 1)
1514b2af45fSPoul-Henning Kamp 			return (EPERM);
1524b2af45fSPoul-Henning Kamp 		securelevel = level;
1534b2af45fSPoul-Henning Kamp 		return (error);
1544b2af45fSPoul-Henning Kamp }
1554b2af45fSPoul-Henning Kamp 
1564b2af45fSPoul-Henning Kamp SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW,
157946bb7a2SPoul-Henning Kamp 	0, 0, sysctl_kern_securelvl, "I", "");
1584b2af45fSPoul-Henning Kamp 
159946bb7a2SPoul-Henning Kamp char domainname[MAXHOSTNAMELEN];
160946bb7a2SPoul-Henning Kamp SYSCTL_STRING(_kern, KERN_DOMAINNAME, domainname, CTLFLAG_RW,
161946bb7a2SPoul-Henning Kamp 	&domainname, sizeof(domainname), "");
1624b2af45fSPoul-Henning Kamp 
163946bb7a2SPoul-Henning Kamp long hostid;
164946bb7a2SPoul-Henning Kamp /* Some trouble here, if sizeof (int) != sizeof (long) */
165946bb7a2SPoul-Henning Kamp SYSCTL_INT(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "");
1664b2af45fSPoul-Henning Kamp 
167946bb7a2SPoul-Henning Kamp /*
16865d0bc13SPoul-Henning Kamp  * This is really cheating.  These actually live in the libc, something
16965d0bc13SPoul-Henning Kamp  * which I'm not quite sure is a good idea anyway, but in order for
17065d0bc13SPoul-Henning Kamp  * getnext and friends to actually work, we define dummies here.
17165d0bc13SPoul-Henning Kamp  */
17265d0bc13SPoul-Henning Kamp 
17365d0bc13SPoul-Henning Kamp SYSCTL_STRING(_user, USER_CS_PATH, cs_path, CTLFLAG_RW, "", 0, "");
17465d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_BC_BASE_MAX, bc_base_max, CTLFLAG_RW, 0, 0, "");
17565d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_BC_DIM_MAX, bc_dim_max, CTLFLAG_RW, 0, 0, "");
17665d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_BC_SCALE_MAX, bc_scale_max, CTLFLAG_RW, 0, 0, "");
17765d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_BC_STRING_MAX, bc_string_max, CTLFLAG_RW, 0, 0, "");
17865d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_COLL_WEIGHTS_MAX, coll_weights_max, CTLFLAG_RW, 0, 0, "");
17965d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_EXPR_NEST_MAX, expr_nest_max, CTLFLAG_RW, 0, 0, "");
18065d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_LINE_MAX, line_max, CTLFLAG_RW, 0, 0, "");
18165d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_RE_DUP_MAX, re_dup_max, CTLFLAG_RW, 0, 0, "");
18265d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_VERSION, posix2_version, CTLFLAG_RW, 0, 0, "");
18365d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_C_BIND, posix2_c_bind, CTLFLAG_RW, 0, 0, "");
18465d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_C_DEV, posix2_c_dev, CTLFLAG_RW, 0, 0, "");
18565d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_CHAR_TERM, posix2_char_term, CTLFLAG_RW, 0, 0, "");
18665d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_FORT_DEV, posix2_fort_dev, CTLFLAG_RW, 0, 0, "");
18765d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_FORT_RUN, posix2_fort_run, CTLFLAG_RW, 0, 0, "");
18865d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_LOCALEDEF, posix2_localedef, CTLFLAG_RW, 0, 0, "");
18965d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_SW_DEV, posix2_sw_dev, CTLFLAG_RW, 0, 0, "");
19065d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_POSIX2_UPE, posix2_upe, CTLFLAG_RW, 0, 0, "");
19165d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_STREAM_MAX, stream_max, CTLFLAG_RW, 0, 0, "");
19265d0bc13SPoul-Henning Kamp SYSCTL_INT(_user, USER_TZNAME_MAX, tzname_max, CTLFLAG_RW, 0, 0, "");
19365d0bc13SPoul-Henning Kamp 
19465d0bc13SPoul-Henning Kamp 
19565d0bc13SPoul-Henning Kamp /*
196946bb7a2SPoul-Henning Kamp  * End of MIB definitions.
197946bb7a2SPoul-Henning Kamp  */
1984b2af45fSPoul-Henning Kamp 
199946bb7a2SPoul-Henning Kamp /*
200946bb7a2SPoul-Henning Kamp  * Initialization of the MIB tree.
201946bb7a2SPoul-Henning Kamp  *
202946bb7a2SPoul-Henning Kamp  * Order by number in each linker_set.
203946bb7a2SPoul-Henning Kamp  */
2044b2af45fSPoul-Henning Kamp 
205787d58f2SPoul-Henning Kamp static int
2063c8e79ddSBruce Evans sysctl_order_cmp(const void *a, const void *b)
207787d58f2SPoul-Henning Kamp {
2083c8e79ddSBruce Evans 	const struct sysctl_oid **pa, **pb;
2093c8e79ddSBruce Evans 
2103c8e79ddSBruce Evans 	pa = (const struct sysctl_oid **)a;
2113c8e79ddSBruce Evans 	pb = (const struct sysctl_oid **)b;
2123c8e79ddSBruce Evans 	if (*pa == NULL)
2133c8e79ddSBruce Evans 		return (1);
2143c8e79ddSBruce Evans 	if (*pb == NULL)
2153c8e79ddSBruce Evans 		return (-1);
216787d58f2SPoul-Henning Kamp 	return ((*pa)->oid_number - (*pb)->oid_number);
217787d58f2SPoul-Henning Kamp }
218787d58f2SPoul-Henning Kamp 
219787d58f2SPoul-Henning Kamp static void
220787d58f2SPoul-Henning Kamp sysctl_order(void *arg)
221787d58f2SPoul-Henning Kamp {
222946bb7a2SPoul-Henning Kamp 	int j, k;
223787d58f2SPoul-Henning Kamp 	struct linker_set *l = (struct linker_set *) arg;
224787d58f2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
225787d58f2SPoul-Henning Kamp 
226946bb7a2SPoul-Henning Kamp 	/* First, find the highest oid we have */
227946bb7a2SPoul-Henning Kamp 	j = l->ls_length;
228946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
229946bb7a2SPoul-Henning Kamp 	for (k = 0; j--; oidpp++)
230946bb7a2SPoul-Henning Kamp 		if (*oidpp && (*oidpp)->oid_number > k)
231946bb7a2SPoul-Henning Kamp 			k = (*oidpp)->oid_number;
232946bb7a2SPoul-Henning Kamp 
233946bb7a2SPoul-Henning Kamp 	/* Next, replace all OID_AUTO oids with new numbers */
234946bb7a2SPoul-Henning Kamp 	j = l->ls_length;
235946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
236946bb7a2SPoul-Henning Kamp 	k += 100;
237946bb7a2SPoul-Henning Kamp 	for (; j--; oidpp++)
238946bb7a2SPoul-Henning Kamp 		if (*oidpp && (*oidpp)->oid_number == OID_AUTO)
239946bb7a2SPoul-Henning Kamp 			(*oidpp)->oid_number = k++;
240946bb7a2SPoul-Henning Kamp 
241946bb7a2SPoul-Henning Kamp 	/* Finally: sort by oid */
242787d58f2SPoul-Henning Kamp 	j = l->ls_length;
243787d58f2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
244787d58f2SPoul-Henning Kamp 	for (; j--; oidpp++) {
245787d58f2SPoul-Henning Kamp 		if (!*oidpp)
246787d58f2SPoul-Henning Kamp 			continue;
247787d58f2SPoul-Henning Kamp 		if ((*oidpp)->oid_arg1 == arg) {
248787d58f2SPoul-Henning Kamp 			*oidpp = 0;
249787d58f2SPoul-Henning Kamp 			continue;
250787d58f2SPoul-Henning Kamp 		}
251787d58f2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE)
252787d58f2SPoul-Henning Kamp 			if (!(*oidpp)->oid_handler)
253787d58f2SPoul-Henning Kamp 				sysctl_order((*oidpp)->oid_arg1);
254787d58f2SPoul-Henning Kamp 	}
255787d58f2SPoul-Henning Kamp 	qsort(l->ls_items, l->ls_length, sizeof l->ls_items[0],
256787d58f2SPoul-Henning Kamp 		sysctl_order_cmp);
257787d58f2SPoul-Henning Kamp }
258787d58f2SPoul-Henning Kamp 
259787d58f2SPoul-Henning Kamp SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_order, &sysctl_);
260787d58f2SPoul-Henning Kamp 
261946bb7a2SPoul-Henning Kamp /*
262946bb7a2SPoul-Henning Kamp  * "Staff-functions"
263946bb7a2SPoul-Henning Kamp  *
26465d0bc13SPoul-Henning Kamp  * These functions implement a presently undocumented interface
26565d0bc13SPoul-Henning Kamp  * used by the sysctl program to walk the tree, and get the type
26665d0bc13SPoul-Henning Kamp  * so it can print the value.
26765d0bc13SPoul-Henning Kamp  * This interface is under work and consideration, and should probably
26865d0bc13SPoul-Henning Kamp  * be killed with a big axe by the first person who can find the time.
26965d0bc13SPoul-Henning Kamp  * (be aware though, that the proper interface isn't as obvious as it
27065d0bc13SPoul-Henning Kamp  * may seem, there are various conflicting requirements.
27165d0bc13SPoul-Henning Kamp  *
272946bb7a2SPoul-Henning Kamp  * {0,0}	printf the entire MIB-tree.
273946bb7a2SPoul-Henning Kamp  * {0,1,...}	return the name of the "..." OID.
274946bb7a2SPoul-Henning Kamp  * {0,2,...}	return the next OID.
275946bb7a2SPoul-Henning Kamp  * {0,3}	return the OID of the name in "new"
27665d0bc13SPoul-Henning Kamp  * {0,4,...}	return the kind & format info for the "..." OID.
277946bb7a2SPoul-Henning Kamp  */
278946bb7a2SPoul-Henning Kamp 
279787d58f2SPoul-Henning Kamp static void
280787d58f2SPoul-Henning Kamp sysctl_sysctl_debug_dump_node(struct linker_set *l, int i)
281787d58f2SPoul-Henning Kamp {
282787d58f2SPoul-Henning Kamp 	int j, k;
283787d58f2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
284787d58f2SPoul-Henning Kamp 
285787d58f2SPoul-Henning Kamp 	j = l->ls_length;
286787d58f2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) l->ls_items;
287787d58f2SPoul-Henning Kamp 	for (; j--; oidpp++) {
288787d58f2SPoul-Henning Kamp 
289787d58f2SPoul-Henning Kamp 		if (!*oidpp)
290787d58f2SPoul-Henning Kamp 			continue;
291787d58f2SPoul-Henning Kamp 
292787d58f2SPoul-Henning Kamp 		for (k=0; k<i; k++)
293787d58f2SPoul-Henning Kamp 			printf(" ");
294787d58f2SPoul-Henning Kamp 
295787d58f2SPoul-Henning Kamp 		if ((*oidpp)->oid_number > 100) {
296b8da2396SPoul-Henning Kamp 			printf("Junk! %p  # %d  %s  k %x  a1 %p  a2 %x  h %p\n",
297787d58f2SPoul-Henning Kamp 				*oidpp,
298787d58f2SPoul-Henning Kamp 		 		(*oidpp)->oid_number, (*oidpp)->oid_name,
299787d58f2SPoul-Henning Kamp 		 		(*oidpp)->oid_kind, (*oidpp)->oid_arg1,
300787d58f2SPoul-Henning Kamp 		 		(*oidpp)->oid_arg2, (*oidpp)->oid_handler);
301787d58f2SPoul-Henning Kamp 			continue;
302787d58f2SPoul-Henning Kamp 		}
303787d58f2SPoul-Henning Kamp 		printf("%d %s ", (*oidpp)->oid_number, (*oidpp)->oid_name);
304787d58f2SPoul-Henning Kamp 
305787d58f2SPoul-Henning Kamp 		printf("%c%c",
306787d58f2SPoul-Henning Kamp 			(*oidpp)->oid_kind & CTLFLAG_RD ? 'R':' ',
307787d58f2SPoul-Henning Kamp 			(*oidpp)->oid_kind & CTLFLAG_WR ? 'W':' ');
308787d58f2SPoul-Henning Kamp 
309787d58f2SPoul-Henning Kamp 		switch ((*oidpp)->oid_kind & CTLTYPE) {
310787d58f2SPoul-Henning Kamp 			case CTLTYPE_NODE:
311787d58f2SPoul-Henning Kamp 				if ((*oidpp)->oid_handler) {
312787d58f2SPoul-Henning Kamp 					printf(" Node(proc)\n");
313787d58f2SPoul-Henning Kamp 				} else {
314787d58f2SPoul-Henning Kamp 					printf(" Node\n");
315787d58f2SPoul-Henning Kamp 					sysctl_sysctl_debug_dump_node(
316787d58f2SPoul-Henning Kamp 						(*oidpp)->oid_arg1, i+2);
317787d58f2SPoul-Henning Kamp 				}
318787d58f2SPoul-Henning Kamp 				break;
319787d58f2SPoul-Henning Kamp 			case CTLTYPE_INT:    printf(" Int\n"); break;
320787d58f2SPoul-Henning Kamp 			case CTLTYPE_STRING: printf(" String\n"); break;
321787d58f2SPoul-Henning Kamp 			case CTLTYPE_QUAD:   printf(" Quad\n"); break;
322787d58f2SPoul-Henning Kamp 			case CTLTYPE_OPAQUE: printf(" Opaque/struct\n"); break;
323787d58f2SPoul-Henning Kamp 			default:	     printf("\n");
324787d58f2SPoul-Henning Kamp 		}
325787d58f2SPoul-Henning Kamp 
326787d58f2SPoul-Henning Kamp 	}
327787d58f2SPoul-Henning Kamp }
328787d58f2SPoul-Henning Kamp 
329787d58f2SPoul-Henning Kamp static int
330787d58f2SPoul-Henning Kamp sysctl_sysctl_debug SYSCTL_HANDLER_ARGS
331787d58f2SPoul-Henning Kamp {
332787d58f2SPoul-Henning Kamp 	sysctl_sysctl_debug_dump_node(&sysctl_, 0);
333787d58f2SPoul-Henning Kamp 	return ENOENT;
334787d58f2SPoul-Henning Kamp }
335787d58f2SPoul-Henning Kamp 
336787d58f2SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 0, debug, CTLTYPE_STRING|CTLFLAG_RD,
337946bb7a2SPoul-Henning Kamp 	0, 0, sysctl_sysctl_debug, "-", "");
3382e210993SPoul-Henning Kamp 
339946bb7a2SPoul-Henning Kamp static int
340946bb7a2SPoul-Henning Kamp sysctl_sysctl_name SYSCTL_HANDLER_ARGS
341946bb7a2SPoul-Henning Kamp {
342946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
343946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
344946bb7a2SPoul-Henning Kamp 	int i, j, error = 0;
345946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
346946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
347946bb7a2SPoul-Henning Kamp 	char buf[10];
3482e210993SPoul-Henning Kamp 
349946bb7a2SPoul-Henning Kamp 	while (namelen) {
350946bb7a2SPoul-Henning Kamp 		if (!lsp) {
351946bb7a2SPoul-Henning Kamp 			sprintf(buf,"%d",*name);
352946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
353946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
354946bb7a2SPoul-Henning Kamp 			if (!error)
355946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, buf, strlen(buf));
356946bb7a2SPoul-Henning Kamp 			if (error)
357946bb7a2SPoul-Henning Kamp 				return (error);
358946bb7a2SPoul-Henning Kamp 			namelen--;
359946bb7a2SPoul-Henning Kamp 			name++;
360946bb7a2SPoul-Henning Kamp 			continue;
361946bb7a2SPoul-Henning Kamp 		}
362946bb7a2SPoul-Henning Kamp 		oidpp = (struct sysctl_oid **) lsp->ls_items;
363946bb7a2SPoul-Henning Kamp 		j = lsp->ls_length;
364946bb7a2SPoul-Henning Kamp 		lsp = 0;
365946bb7a2SPoul-Henning Kamp 		for (i = 0; i < j; i++, oidpp++) {
366946bb7a2SPoul-Henning Kamp 			if (*oidpp && ((*oidpp)->oid_number != *name))
367946bb7a2SPoul-Henning Kamp 				continue;
368946bb7a2SPoul-Henning Kamp 
369946bb7a2SPoul-Henning Kamp 			if (req->oldidx)
370946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, ".", 1);
371946bb7a2SPoul-Henning Kamp 			if (!error)
372946bb7a2SPoul-Henning Kamp 				error = SYSCTL_OUT(req, (*oidpp)->oid_name,
373946bb7a2SPoul-Henning Kamp 					strlen((*oidpp)->oid_name));
374946bb7a2SPoul-Henning Kamp 			if (error)
375946bb7a2SPoul-Henning Kamp 				return (error);
376946bb7a2SPoul-Henning Kamp 
377946bb7a2SPoul-Henning Kamp 			namelen--;
378946bb7a2SPoul-Henning Kamp 			name++;
379946bb7a2SPoul-Henning Kamp 
380946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
381946bb7a2SPoul-Henning Kamp 				break;
382946bb7a2SPoul-Henning Kamp 
383946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
384946bb7a2SPoul-Henning Kamp 				break;
385946bb7a2SPoul-Henning Kamp 
386946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
387946bb7a2SPoul-Henning Kamp 			break;
388946bb7a2SPoul-Henning Kamp 		}
389946bb7a2SPoul-Henning Kamp 	}
390946bb7a2SPoul-Henning Kamp 	return (SYSCTL_OUT(req, "", 1));
391946bb7a2SPoul-Henning Kamp }
392946bb7a2SPoul-Henning Kamp 
393946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD, sysctl_sysctl_name, "");
394946bb7a2SPoul-Henning Kamp 
395946bb7a2SPoul-Henning Kamp static int
396946bb7a2SPoul-Henning Kamp sysctl_sysctl_next_ls (struct linker_set *lsp, int *name, u_int namelen,
397946bb7a2SPoul-Henning Kamp 	int *next, int *len, int level, struct sysctl_oid **oidp)
398946bb7a2SPoul-Henning Kamp {
399946bb7a2SPoul-Henning Kamp 	int i, j;
400946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
401946bb7a2SPoul-Henning Kamp 
402946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
403946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
404946bb7a2SPoul-Henning Kamp 	*len = level;
405946bb7a2SPoul-Henning Kamp 	for (i = 0; i < j; i++, oidpp++) {
406946bb7a2SPoul-Henning Kamp 		if (!*oidpp)
407946bb7a2SPoul-Henning Kamp 			continue;
408946bb7a2SPoul-Henning Kamp 
409946bb7a2SPoul-Henning Kamp 		*next = (*oidpp)->oid_number;
410946bb7a2SPoul-Henning Kamp 		*oidp = *oidpp;
411946bb7a2SPoul-Henning Kamp 
412946bb7a2SPoul-Henning Kamp 		if (!namelen) {
413946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
414946bb7a2SPoul-Henning Kamp 				return 0;
415946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
416946bb7a2SPoul-Henning Kamp 				/* We really should call the handler here...*/
417946bb7a2SPoul-Henning Kamp 				return 0;
418946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
419946bb7a2SPoul-Henning Kamp 			return (sysctl_sysctl_next_ls (lsp, 0, 0, next+1,
420946bb7a2SPoul-Henning Kamp 				len, level+1, oidp));
421946bb7a2SPoul-Henning Kamp 		}
422946bb7a2SPoul-Henning Kamp 
423946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_number < *name)
424946bb7a2SPoul-Henning Kamp 			continue;
425946bb7a2SPoul-Henning Kamp 
426946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_number > *name) {
427946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
428946bb7a2SPoul-Henning Kamp 				return 0;
429946bb7a2SPoul-Henning Kamp 			if ((*oidpp)->oid_handler)
430946bb7a2SPoul-Henning Kamp 				return 0;
431946bb7a2SPoul-Henning Kamp 			lsp = (struct linker_set*)(*oidpp)->oid_arg1;
432946bb7a2SPoul-Henning Kamp 			if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1,
433946bb7a2SPoul-Henning Kamp 				next+1, len, level+1, oidp))
434946bb7a2SPoul-Henning Kamp 				return (0);
435946bb7a2SPoul-Henning Kamp 			namelen = 1;
436946bb7a2SPoul-Henning Kamp 			*len = level;
437946bb7a2SPoul-Henning Kamp 			continue;
438946bb7a2SPoul-Henning Kamp 		}
439946bb7a2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
440946bb7a2SPoul-Henning Kamp 			continue;
441946bb7a2SPoul-Henning Kamp 
442946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
443946bb7a2SPoul-Henning Kamp 			continue;
444946bb7a2SPoul-Henning Kamp 
445946bb7a2SPoul-Henning Kamp 		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
446946bb7a2SPoul-Henning Kamp 		if (!sysctl_sysctl_next_ls (lsp, name+1, namelen-1, next+1,
447946bb7a2SPoul-Henning Kamp 			len, level+1, oidp))
448946bb7a2SPoul-Henning Kamp 			return (0);
449946bb7a2SPoul-Henning Kamp 		namelen = 1;
450946bb7a2SPoul-Henning Kamp 		*len = level;
451946bb7a2SPoul-Henning Kamp 	}
452946bb7a2SPoul-Henning Kamp 	return 1;
453946bb7a2SPoul-Henning Kamp }
454946bb7a2SPoul-Henning Kamp 
455946bb7a2SPoul-Henning Kamp static int
456946bb7a2SPoul-Henning Kamp sysctl_sysctl_next SYSCTL_HANDLER_ARGS
457946bb7a2SPoul-Henning Kamp {
458946bb7a2SPoul-Henning Kamp 	int *name = (int *) arg1;
459946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
460946bb7a2SPoul-Henning Kamp 	int i, j, error;
461946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *oid;
462946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
463946bb7a2SPoul-Henning Kamp 	int newoid[CTL_MAXNAME];
464946bb7a2SPoul-Henning Kamp 
465946bb7a2SPoul-Henning Kamp 	i = sysctl_sysctl_next_ls (lsp, name, namelen, newoid, &j, 1, &oid);
466946bb7a2SPoul-Henning Kamp 	if (i)
467946bb7a2SPoul-Henning Kamp 		return ENOENT;
468946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, newoid, j * sizeof (int));
469946bb7a2SPoul-Henning Kamp 	return (error);
470946bb7a2SPoul-Henning Kamp }
471946bb7a2SPoul-Henning Kamp 
472946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD, sysctl_sysctl_next, "");
473946bb7a2SPoul-Henning Kamp 
474946bb7a2SPoul-Henning Kamp static int
475946bb7a2SPoul-Henning Kamp name2oid (char *name, int *oid, int *len, struct sysctl_oid **oidp)
476946bb7a2SPoul-Henning Kamp {
477946bb7a2SPoul-Henning Kamp 	int i, j;
478946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
479946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
480946bb7a2SPoul-Henning Kamp 	char *p;
481946bb7a2SPoul-Henning Kamp 
482946bb7a2SPoul-Henning Kamp 	if (!*name)
483946bb7a2SPoul-Henning Kamp 		return ENOENT;
484946bb7a2SPoul-Henning Kamp 
485946bb7a2SPoul-Henning Kamp 	p = name + strlen(name) - 1 ;
486946bb7a2SPoul-Henning Kamp 	if (*p == '.')
487946bb7a2SPoul-Henning Kamp 		*p = '\0';
488946bb7a2SPoul-Henning Kamp 
489946bb7a2SPoul-Henning Kamp 	*len = 0;
490946bb7a2SPoul-Henning Kamp 
491946bb7a2SPoul-Henning Kamp 	for (p = name; *p && *p != '.'; p++)
492946bb7a2SPoul-Henning Kamp 		;
493946bb7a2SPoul-Henning Kamp 	i = *p;
494946bb7a2SPoul-Henning Kamp 	if (i == '.')
495946bb7a2SPoul-Henning Kamp 		*p = '\0';
496946bb7a2SPoul-Henning Kamp 
497946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
498946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
499946bb7a2SPoul-Henning Kamp 
500946bb7a2SPoul-Henning Kamp 	while (j-- && *len < CTL_MAXNAME) {
501946bb7a2SPoul-Henning Kamp 		if (!*oidpp)
502946bb7a2SPoul-Henning Kamp 			continue;
503946bb7a2SPoul-Henning Kamp 		if (strcmp(name, (*oidpp)->oid_name)) {
504946bb7a2SPoul-Henning Kamp 			oidpp++;
505946bb7a2SPoul-Henning Kamp 			continue;
506946bb7a2SPoul-Henning Kamp 		}
507946bb7a2SPoul-Henning Kamp 		*oid++ = (*oidpp)->oid_number;
508946bb7a2SPoul-Henning Kamp 		(*len)++;
509946bb7a2SPoul-Henning Kamp 
510946bb7a2SPoul-Henning Kamp 		if (!i) {
511946bb7a2SPoul-Henning Kamp 			if (oidp)
512946bb7a2SPoul-Henning Kamp 				*oidp = *oidpp;
513946bb7a2SPoul-Henning Kamp 			return (0);
514946bb7a2SPoul-Henning Kamp 		}
515946bb7a2SPoul-Henning Kamp 
516946bb7a2SPoul-Henning Kamp 		if (((*oidpp)->oid_kind & CTLTYPE) != CTLTYPE_NODE)
517946bb7a2SPoul-Henning Kamp 			break;
518946bb7a2SPoul-Henning Kamp 
519946bb7a2SPoul-Henning Kamp 		if ((*oidpp)->oid_handler)
520946bb7a2SPoul-Henning Kamp 			break;
521946bb7a2SPoul-Henning Kamp 
522946bb7a2SPoul-Henning Kamp 		lsp = (struct linker_set*)(*oidpp)->oid_arg1;
523946bb7a2SPoul-Henning Kamp 		j = lsp->ls_length;
524946bb7a2SPoul-Henning Kamp 		oidpp = (struct sysctl_oid **)lsp->ls_items;
525946bb7a2SPoul-Henning Kamp 		name = p+1;
526946bb7a2SPoul-Henning Kamp 		for (p = name; *p && *p != '.'; p++)
527946bb7a2SPoul-Henning Kamp 				;
528946bb7a2SPoul-Henning Kamp 		i = *p;
529946bb7a2SPoul-Henning Kamp 		if (i == '.')
530946bb7a2SPoul-Henning Kamp 			*p = '\0';
531946bb7a2SPoul-Henning Kamp 	}
532946bb7a2SPoul-Henning Kamp 	return ENOENT;
533946bb7a2SPoul-Henning Kamp }
534946bb7a2SPoul-Henning Kamp 
535946bb7a2SPoul-Henning Kamp static int
536946bb7a2SPoul-Henning Kamp sysctl_sysctl_name2oid SYSCTL_HANDLER_ARGS
537946bb7a2SPoul-Henning Kamp {
538946bb7a2SPoul-Henning Kamp 	char *p;
539946bb7a2SPoul-Henning Kamp 	int error, oid[CTL_MAXNAME], len;
540946bb7a2SPoul-Henning Kamp 	struct sysctl_oid *op = 0;
541946bb7a2SPoul-Henning Kamp 
542946bb7a2SPoul-Henning Kamp 	if (!req->newlen)
543946bb7a2SPoul-Henning Kamp 		return ENOENT;
544946bb7a2SPoul-Henning Kamp 
545946bb7a2SPoul-Henning Kamp 	p = malloc(req->newlen+1, M_SYSCTL, M_WAITOK);
546946bb7a2SPoul-Henning Kamp 
547946bb7a2SPoul-Henning Kamp 	error = SYSCTL_IN(req, p, req->newlen);
548946bb7a2SPoul-Henning Kamp 	if (error) {
549946bb7a2SPoul-Henning Kamp 		free(p, M_SYSCTL);
550946bb7a2SPoul-Henning Kamp 		return (error);
551946bb7a2SPoul-Henning Kamp 	}
552946bb7a2SPoul-Henning Kamp 
553946bb7a2SPoul-Henning Kamp 	p [req->newlen] = '\0';
554946bb7a2SPoul-Henning Kamp 
555946bb7a2SPoul-Henning Kamp 	error = name2oid(p, oid, &len, &op);
556946bb7a2SPoul-Henning Kamp 
557946bb7a2SPoul-Henning Kamp 	free(p, M_SYSCTL);
558946bb7a2SPoul-Henning Kamp 
559946bb7a2SPoul-Henning Kamp 	if (error)
560946bb7a2SPoul-Henning Kamp 		return (error);
561946bb7a2SPoul-Henning Kamp 
562946bb7a2SPoul-Henning Kamp 	error = SYSCTL_OUT(req, oid, len * sizeof *oid);
563946bb7a2SPoul-Henning Kamp 	return (error);
564946bb7a2SPoul-Henning Kamp }
565946bb7a2SPoul-Henning Kamp 
5663ac9f819SPoul-Henning Kamp SYSCTL_PROC(_sysctl, 3, name2oid, CTLFLAG_RW|CTLFLAG_ANYBODY, 0, 0,
567946bb7a2SPoul-Henning Kamp 	sysctl_sysctl_name2oid, "I", "");
568946bb7a2SPoul-Henning Kamp 
569946bb7a2SPoul-Henning Kamp static int
570946bb7a2SPoul-Henning Kamp sysctl_sysctl_oidfmt SYSCTL_HANDLER_ARGS
571946bb7a2SPoul-Henning Kamp {
57265d0bc13SPoul-Henning Kamp 	int *name = (int *) arg1, error;
573946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
574946bb7a2SPoul-Henning Kamp 	int indx, j;
575946bb7a2SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
576946bb7a2SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
577946bb7a2SPoul-Henning Kamp 
578946bb7a2SPoul-Henning Kamp 	j = lsp->ls_length;
579946bb7a2SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
580946bb7a2SPoul-Henning Kamp 
581946bb7a2SPoul-Henning Kamp 	indx = 0;
582946bb7a2SPoul-Henning Kamp 	while (j-- && indx < CTL_MAXNAME) {
583946bb7a2SPoul-Henning Kamp 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
584946bb7a2SPoul-Henning Kamp 			indx++;
585946bb7a2SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
586946bb7a2SPoul-Henning Kamp 				if ((*oidpp)->oid_handler)
587946bb7a2SPoul-Henning Kamp 					goto found;
588946bb7a2SPoul-Henning Kamp 				if (indx == namelen)
58965d0bc13SPoul-Henning Kamp 					goto found;
590946bb7a2SPoul-Henning Kamp 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
591946bb7a2SPoul-Henning Kamp 				j = lsp->ls_length;
592946bb7a2SPoul-Henning Kamp 				oidpp = (struct sysctl_oid **)lsp->ls_items;
593946bb7a2SPoul-Henning Kamp 			} else {
594946bb7a2SPoul-Henning Kamp 				if (indx != namelen)
595946bb7a2SPoul-Henning Kamp 					return EISDIR;
596946bb7a2SPoul-Henning Kamp 				goto found;
597946bb7a2SPoul-Henning Kamp 			}
598946bb7a2SPoul-Henning Kamp 		} else {
599946bb7a2SPoul-Henning Kamp 			oidpp++;
600946bb7a2SPoul-Henning Kamp 		}
601946bb7a2SPoul-Henning Kamp 	}
602946bb7a2SPoul-Henning Kamp 	return ENOENT;
603946bb7a2SPoul-Henning Kamp found:
604946bb7a2SPoul-Henning Kamp 	if (!(*oidpp)->oid_fmt)
605946bb7a2SPoul-Henning Kamp 		return ENOENT;
60665d0bc13SPoul-Henning Kamp 	error = SYSCTL_OUT(req,
60765d0bc13SPoul-Henning Kamp 		&(*oidpp)->oid_kind, sizeof((*oidpp)->oid_kind));
60865d0bc13SPoul-Henning Kamp 	if (!error)
60965d0bc13SPoul-Henning Kamp 		error = SYSCTL_OUT(req, (*oidpp)->oid_fmt,
61065d0bc13SPoul-Henning Kamp 			strlen((*oidpp)->oid_fmt)+1);
61165d0bc13SPoul-Henning Kamp 	return (error);
612946bb7a2SPoul-Henning Kamp }
613946bb7a2SPoul-Henning Kamp 
614946bb7a2SPoul-Henning Kamp 
615946bb7a2SPoul-Henning Kamp SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD, sysctl_sysctl_oidfmt, "");
616946bb7a2SPoul-Henning Kamp 
617946bb7a2SPoul-Henning Kamp /*
618946bb7a2SPoul-Henning Kamp  * Default "handler" functions.
619946bb7a2SPoul-Henning Kamp  */
6202e210993SPoul-Henning Kamp 
621ae0eb976SPoul-Henning Kamp /*
622ae0eb976SPoul-Henning Kamp  * Handle an integer, signed or unsigned.
623ae0eb976SPoul-Henning Kamp  * Two cases:
624ae0eb976SPoul-Henning Kamp  *     a variable:  point arg1 at it.
625ae0eb976SPoul-Henning Kamp  *     a constant:  pass it in arg2.
626ae0eb976SPoul-Henning Kamp  */
627ae0eb976SPoul-Henning Kamp 
6283a34a5c3SPoul-Henning Kamp int
6293a34a5c3SPoul-Henning Kamp sysctl_handle_int SYSCTL_HANDLER_ARGS
630b396cd83SPoul-Henning Kamp {
631ae0eb976SPoul-Henning Kamp 	int error = 0;
632b396cd83SPoul-Henning Kamp 
633ae0eb976SPoul-Henning Kamp 	if (arg1)
634ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, arg1, sizeof(int));
635ae0eb976SPoul-Henning Kamp 	else if (arg2)
636ae0eb976SPoul-Henning Kamp 		error = SYSCTL_OUT(req, &arg2, sizeof(int));
637b396cd83SPoul-Henning Kamp 
638ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
639ae0eb976SPoul-Henning Kamp 		return (error);
640b396cd83SPoul-Henning Kamp 
641ae0eb976SPoul-Henning Kamp 	if (!arg1)
642ae0eb976SPoul-Henning Kamp 		error = EPERM;
643ae0eb976SPoul-Henning Kamp 	else
644ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, sizeof(int));
645ae0eb976SPoul-Henning Kamp 	return (error);
646b396cd83SPoul-Henning Kamp }
647b396cd83SPoul-Henning Kamp 
648ae0eb976SPoul-Henning Kamp /*
649ae0eb976SPoul-Henning Kamp  * Handle our generic '\0' terminated 'C' string.
650ae0eb976SPoul-Henning Kamp  * Two cases:
651ae0eb976SPoul-Henning Kamp  * 	a variable string:  point arg1 at it, arg2 is max length.
652ae0eb976SPoul-Henning Kamp  * 	a constant string:  point arg1 at it, arg2 is zero.
653ae0eb976SPoul-Henning Kamp  */
654ae0eb976SPoul-Henning Kamp 
6553a34a5c3SPoul-Henning Kamp int
6563a34a5c3SPoul-Henning Kamp sysctl_handle_string SYSCTL_HANDLER_ARGS
657b396cd83SPoul-Henning Kamp {
658ae0eb976SPoul-Henning Kamp 	int error=0;
659b396cd83SPoul-Henning Kamp 
660ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, strlen((char *)arg1)+1);
661b396cd83SPoul-Henning Kamp 
662deae269aSPoul-Henning Kamp 	if (error || !req->newptr || !arg2)
663ae0eb976SPoul-Henning Kamp 		return (error);
664ae0eb976SPoul-Henning Kamp 
665ae0eb976SPoul-Henning Kamp 	if ((req->newlen - req->newidx) > arg2) {
666ae0eb976SPoul-Henning Kamp 		error = E2BIG;
667ae0eb976SPoul-Henning Kamp 	} else {
668ae0eb976SPoul-Henning Kamp 		arg2 = (req->newlen - req->newidx);
669ae0eb976SPoul-Henning Kamp 		error = SYSCTL_IN(req, arg1, arg2);
670ae0eb976SPoul-Henning Kamp 		((char *)arg1)[arg2] = '\0';
671b396cd83SPoul-Henning Kamp 	}
672b396cd83SPoul-Henning Kamp 
6732e210993SPoul-Henning Kamp 	return (error);
674b396cd83SPoul-Henning Kamp }
675b396cd83SPoul-Henning Kamp 
676ae0eb976SPoul-Henning Kamp /*
677ae0eb976SPoul-Henning Kamp  * Handle any kind of opaque data.
678ae0eb976SPoul-Henning Kamp  * arg1 points to it, arg2 is the size.
679ae0eb976SPoul-Henning Kamp  */
680ae0eb976SPoul-Henning Kamp 
6813a34a5c3SPoul-Henning Kamp int
6823a34a5c3SPoul-Henning Kamp sysctl_handle_opaque SYSCTL_HANDLER_ARGS
683b396cd83SPoul-Henning Kamp {
684ae0eb976SPoul-Henning Kamp 	int error;
685b396cd83SPoul-Henning Kamp 
686ae0eb976SPoul-Henning Kamp 	error = SYSCTL_OUT(req, arg1, arg2);
687b396cd83SPoul-Henning Kamp 
688ae0eb976SPoul-Henning Kamp 	if (error || !req->newptr)
689ae0eb976SPoul-Henning Kamp 		return (error);
690ae0eb976SPoul-Henning Kamp 
691ae0eb976SPoul-Henning Kamp 	error = SYSCTL_IN(req, arg1, arg2);
692ae0eb976SPoul-Henning Kamp 
693ae0eb976SPoul-Henning Kamp 	return (error);
694b396cd83SPoul-Henning Kamp }
695ae0eb976SPoul-Henning Kamp 
696deae269aSPoul-Henning Kamp /*
697deae269aSPoul-Henning Kamp  * Transfer functions to/from kernel space.
698deae269aSPoul-Henning Kamp  * XXX: rather untested at this point
699deae269aSPoul-Henning Kamp  */
700deae269aSPoul-Henning Kamp static int
7013ac9f819SPoul-Henning Kamp sysctl_old_kernel(struct sysctl_req *req, const void *p, int l)
702ae0eb976SPoul-Henning Kamp {
703deae269aSPoul-Henning Kamp 	int i = 0;
704deae269aSPoul-Henning Kamp 
705deae269aSPoul-Henning Kamp 	if (req->oldptr) {
706deae269aSPoul-Henning Kamp 		i = min(req->oldlen - req->oldidx, l);
707deae269aSPoul-Henning Kamp 		if (i > 0)
708ae0eb976SPoul-Henning Kamp 			bcopy(p, req->oldptr + req->oldidx, i);
709ae0eb976SPoul-Henning Kamp 	}
710deae269aSPoul-Henning Kamp 	req->oldidx += l;
711ae0eb976SPoul-Henning Kamp 	if (i != l)
712ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
7132e210993SPoul-Henning Kamp 	return (0);
714ae0eb976SPoul-Henning Kamp 
715ae0eb976SPoul-Henning Kamp }
716ae0eb976SPoul-Henning Kamp 
717deae269aSPoul-Henning Kamp static int
7183ac9f819SPoul-Henning Kamp sysctl_new_kernel(struct sysctl_req *req, const void *p, int l)
719ae0eb976SPoul-Henning Kamp {
720deae269aSPoul-Henning Kamp 	if (!req->newptr)
721deae269aSPoul-Henning Kamp 		return 0;
722deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
723ae0eb976SPoul-Henning Kamp 		return (EINVAL);
724ae0eb976SPoul-Henning Kamp 	bcopy(req->newptr + req->newidx, p, l);
725ae0eb976SPoul-Henning Kamp 	req->newidx += l;
726ae0eb976SPoul-Henning Kamp 	return (0);
727ae0eb976SPoul-Henning Kamp }
728ae0eb976SPoul-Henning Kamp 
729deae269aSPoul-Henning Kamp /*
730deae269aSPoul-Henning Kamp  * Transfer function to/from user space.
731deae269aSPoul-Henning Kamp  */
732deae269aSPoul-Henning Kamp static int
7333ac9f819SPoul-Henning Kamp sysctl_old_user(struct sysctl_req *req, const void *p, int l)
734ae0eb976SPoul-Henning Kamp {
735deae269aSPoul-Henning Kamp 	int error = 0, i = 0;
736ae0eb976SPoul-Henning Kamp 
7374b2af45fSPoul-Henning Kamp 	if (req->lock == 1 && req->oldptr) {
7384b2af45fSPoul-Henning Kamp 		vslock(req->oldptr, req->oldlen);
7394b2af45fSPoul-Henning Kamp 		req->lock = 2;
7404b2af45fSPoul-Henning Kamp 	}
741deae269aSPoul-Henning Kamp 	if (req->oldptr) {
742deae269aSPoul-Henning Kamp 		i = min(req->oldlen - req->oldidx, l);
743deae269aSPoul-Henning Kamp 		if (i > 0)
744ae0eb976SPoul-Henning Kamp 			error  = copyout(p, req->oldptr + req->oldidx, i);
745deae269aSPoul-Henning Kamp 	}
746deae269aSPoul-Henning Kamp 	req->oldidx += l;
747ae0eb976SPoul-Henning Kamp 	if (error)
748ae0eb976SPoul-Henning Kamp 		return (error);
749deae269aSPoul-Henning Kamp 	if (req->oldptr && i < l)
750ae0eb976SPoul-Henning Kamp 		return (ENOMEM);
751deae269aSPoul-Henning Kamp 	return (0);
752ae0eb976SPoul-Henning Kamp }
753ae0eb976SPoul-Henning Kamp 
754deae269aSPoul-Henning Kamp static int
755ae0eb976SPoul-Henning Kamp sysctl_new_user(struct sysctl_req *req, void *p, int l)
756ae0eb976SPoul-Henning Kamp {
75716cd04a3SPoul-Henning Kamp 	int error;
758deae269aSPoul-Henning Kamp 
759deae269aSPoul-Henning Kamp 	if (!req->newptr)
760deae269aSPoul-Henning Kamp 		return 0;
761deae269aSPoul-Henning Kamp 	if (req->newlen - req->newidx < l)
762ae0eb976SPoul-Henning Kamp 		return (EINVAL);
763ae0eb976SPoul-Henning Kamp 	error = copyin(req->newptr + req->newidx, p, l);
764ae0eb976SPoul-Henning Kamp 	req->newidx += l;
765ae0eb976SPoul-Henning Kamp 	return (error);
766b396cd83SPoul-Henning Kamp }
767b396cd83SPoul-Henning Kamp 
768df8bae1dSRodney W. Grimes /*
7692e210993SPoul-Henning Kamp  * Traverse our tree, and find the right node, execute whatever it points
7702e210993SPoul-Henning Kamp  * at, and return the resulting error code.
7712e210993SPoul-Henning Kamp  */
7722e210993SPoul-Henning Kamp 
7732e210993SPoul-Henning Kamp int
7742e210993SPoul-Henning Kamp sysctl_root SYSCTL_HANDLER_ARGS
7752e210993SPoul-Henning Kamp {
7762e210993SPoul-Henning Kamp 	int *name = (int *) arg1;
777946bb7a2SPoul-Henning Kamp 	u_int namelen = arg2;
7782e210993SPoul-Henning Kamp 	int indx, i, j;
7792e210993SPoul-Henning Kamp 	struct sysctl_oid **oidpp;
7802e210993SPoul-Henning Kamp 	struct linker_set *lsp = &sysctl_;
7812e210993SPoul-Henning Kamp 
7822e210993SPoul-Henning Kamp 	j = lsp->ls_length;
7832e210993SPoul-Henning Kamp 	oidpp = (struct sysctl_oid **) lsp->ls_items;
7842e210993SPoul-Henning Kamp 
7852e210993SPoul-Henning Kamp 	indx = 0;
7862e210993SPoul-Henning Kamp 	while (j-- && indx < CTL_MAXNAME) {
787787d58f2SPoul-Henning Kamp 		if (*oidpp && ((*oidpp)->oid_number == name[indx])) {
7882e210993SPoul-Henning Kamp 			indx++;
7894b2af45fSPoul-Henning Kamp 			if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK)
7904b2af45fSPoul-Henning Kamp 				req->lock = 0;
7912e210993SPoul-Henning Kamp 			if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
7922e210993SPoul-Henning Kamp 				if ((*oidpp)->oid_handler)
7932e210993SPoul-Henning Kamp 					goto found;
7942e210993SPoul-Henning Kamp 				if (indx == namelen)
7952e210993SPoul-Henning Kamp 					return ENOENT;
7962e210993SPoul-Henning Kamp 				lsp = (struct linker_set*)(*oidpp)->oid_arg1;
7972e210993SPoul-Henning Kamp 				j = lsp->ls_length;
7982e210993SPoul-Henning Kamp 				oidpp = (struct sysctl_oid **)lsp->ls_items;
7992e210993SPoul-Henning Kamp 			} else {
8002e210993SPoul-Henning Kamp 				if (indx != namelen)
8012e210993SPoul-Henning Kamp 					return EISDIR;
8022e210993SPoul-Henning Kamp 				goto found;
8032e210993SPoul-Henning Kamp 			}
8042e210993SPoul-Henning Kamp 		} else {
8052e210993SPoul-Henning Kamp 			oidpp++;
8062e210993SPoul-Henning Kamp 		}
8072e210993SPoul-Henning Kamp 	}
808deae269aSPoul-Henning Kamp 	return ENOENT;
8092e210993SPoul-Henning Kamp found:
8102e210993SPoul-Henning Kamp 	/* If writing isn't allowed */
811ae0eb976SPoul-Henning Kamp 	if (req->newptr && !((*oidpp)->oid_kind & CTLFLAG_WR))
8122e210993SPoul-Henning Kamp 		return (EPERM);
8132e210993SPoul-Henning Kamp 
8143ac9f819SPoul-Henning Kamp 	/* Most likely only root can write */
8153ac9f819SPoul-Henning Kamp 	if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) &&
8163ac9f819SPoul-Henning Kamp 	    req->newptr && req->p &&
8173ac9f819SPoul-Henning Kamp 	    (i = suser(req->p->p_ucred, &req->p->p_acflag)))
8183ac9f819SPoul-Henning Kamp 		return (i);
8193ac9f819SPoul-Henning Kamp 
8202e210993SPoul-Henning Kamp 	if (!(*oidpp)->oid_handler)
8212e210993SPoul-Henning Kamp 		return EINVAL;
8222e210993SPoul-Henning Kamp 
8232e210993SPoul-Henning Kamp 	if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
8242e210993SPoul-Henning Kamp 		i = ((*oidpp)->oid_handler) (*oidpp,
8252e210993SPoul-Henning Kamp 					name + indx, namelen - indx,
826ae0eb976SPoul-Henning Kamp 					req);
8272e210993SPoul-Henning Kamp 	} else {
8282e210993SPoul-Henning Kamp 		i = ((*oidpp)->oid_handler) (*oidpp,
8292e210993SPoul-Henning Kamp 					(*oidpp)->oid_arg1, (*oidpp)->oid_arg2,
830ae0eb976SPoul-Henning Kamp 					req);
8312e210993SPoul-Henning Kamp 	}
8322e210993SPoul-Henning Kamp 	return (i);
8332e210993SPoul-Henning Kamp }
8342e210993SPoul-Henning Kamp 
835d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
836b8da2396SPoul-Henning Kamp struct sysctl_args {
837b8da2396SPoul-Henning Kamp 	int	*name;
838b8da2396SPoul-Henning Kamp 	u_int	namelen;
839b8da2396SPoul-Henning Kamp 	void	*old;
840b8da2396SPoul-Henning Kamp 	size_t	*oldlenp;
841b8da2396SPoul-Henning Kamp 	void	*new;
842b8da2396SPoul-Henning Kamp 	size_t	newlen;
843b8da2396SPoul-Henning Kamp };
844d2d3e875SBruce Evans #endif
845b8da2396SPoul-Henning Kamp 
846df8bae1dSRodney W. Grimes int
8474b2af45fSPoul-Henning Kamp __sysctl(struct proc *p, struct sysctl_args *uap, int *retval)
848df8bae1dSRodney W. Grimes {
849deae269aSPoul-Henning Kamp 	int error, i, j, name[CTL_MAXNAME];
850b396cd83SPoul-Henning Kamp 
851df8bae1dSRodney W. Grimes 	if (uap->namelen > CTL_MAXNAME || uap->namelen < 2)
852df8bae1dSRodney W. Grimes 		return (EINVAL);
853b396cd83SPoul-Henning Kamp 
854797f2d22SPoul-Henning Kamp  	error = copyin(uap->name, &name, uap->namelen * sizeof(int));
855797f2d22SPoul-Henning Kamp  	if (error)
856df8bae1dSRodney W. Grimes 		return (error);
857df8bae1dSRodney W. Grimes 
858deae269aSPoul-Henning Kamp 	error = userland_sysctl(p, name, uap->namelen,
859b8da2396SPoul-Henning Kamp 		uap->old, uap->oldlenp, 0,
860deae269aSPoul-Henning Kamp 		uap->new, uap->newlen, &j);
861deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
862deae269aSPoul-Henning Kamp 		return (error);
863deae269aSPoul-Henning Kamp 	if (uap->oldlenp) {
864deae269aSPoul-Henning Kamp 		i = copyout(&j, uap->oldlenp, sizeof(j));
865deae269aSPoul-Henning Kamp 		if (i)
866deae269aSPoul-Henning Kamp 			return (i);
867deae269aSPoul-Henning Kamp 	}
868deae269aSPoul-Henning Kamp 	return (error);
869b8da2396SPoul-Henning Kamp }
870b8da2396SPoul-Henning Kamp 
871b8da2396SPoul-Henning Kamp /*
872b8da2396SPoul-Henning Kamp  * This is used from various compatibility syscalls too.  That's why name
873b8da2396SPoul-Henning Kamp  * must be in kernel space.
874b8da2396SPoul-Henning Kamp  */
875b8da2396SPoul-Henning Kamp int
876b8da2396SPoul-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)
877b8da2396SPoul-Henning Kamp {
8784b2af45fSPoul-Henning Kamp 	int error = 0;
879ae0eb976SPoul-Henning Kamp 	struct sysctl_req req;
880ae0eb976SPoul-Henning Kamp 
881ae0eb976SPoul-Henning Kamp 	bzero(&req, sizeof req);
882b8da2396SPoul-Henning Kamp 
88316cd04a3SPoul-Henning Kamp 	req.p = p;
88416cd04a3SPoul-Henning Kamp 
885b8da2396SPoul-Henning Kamp 	if (oldlenp) {
886b8da2396SPoul-Henning Kamp 		if (inkernel) {
887ae0eb976SPoul-Henning Kamp 			req.oldlen = *oldlenp;
888b8da2396SPoul-Henning Kamp 		} else {
889deae269aSPoul-Henning Kamp 			error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp));
890b8da2396SPoul-Henning Kamp 			if (error)
891b8da2396SPoul-Henning Kamp 				return (error);
892b8da2396SPoul-Henning Kamp 		}
893b8da2396SPoul-Henning Kamp 	}
894b8da2396SPoul-Henning Kamp 
895ae0eb976SPoul-Henning Kamp 	if (old) {
896ae0eb976SPoul-Henning Kamp 		if (!useracc(old, req.oldlen, B_WRITE))
897ae0eb976SPoul-Henning Kamp 			return (EFAULT);
898ae0eb976SPoul-Henning Kamp 		req.oldptr= old;
899ae0eb976SPoul-Henning Kamp 	}
9002e210993SPoul-Henning Kamp 
901b8da2396SPoul-Henning Kamp 	if (newlen) {
902ae0eb976SPoul-Henning Kamp 		if (!useracc(new, req.newlen, B_READ))
903ae0eb976SPoul-Henning Kamp 			return (EFAULT);
904ae0eb976SPoul-Henning Kamp 		req.newlen = newlen;
905ae0eb976SPoul-Henning Kamp 		req.newptr = new;
906b396cd83SPoul-Henning Kamp 	}
907b396cd83SPoul-Henning Kamp 
908ae0eb976SPoul-Henning Kamp 	req.oldfunc = sysctl_old_user;
909ae0eb976SPoul-Henning Kamp 	req.newfunc = sysctl_new_user;
9104b2af45fSPoul-Henning Kamp 	req.lock = 1;
9114b2af45fSPoul-Henning Kamp 
9124b2af45fSPoul-Henning Kamp 	/* XXX this should probably be done in a general way */
9134b2af45fSPoul-Henning Kamp 	while (memlock.sl_lock) {
9144b2af45fSPoul-Henning Kamp 		memlock.sl_want = 1;
9154b2af45fSPoul-Henning Kamp 		(void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0);
9164b2af45fSPoul-Henning Kamp 		memlock.sl_locked++;
9174b2af45fSPoul-Henning Kamp 	}
9184b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 1;
919ae0eb976SPoul-Henning Kamp 
920ae0eb976SPoul-Henning Kamp 	error = sysctl_root(0, name, namelen, &req);
921b396cd83SPoul-Henning Kamp 
9224b2af45fSPoul-Henning Kamp 	if (req.lock == 2)
9234b2af45fSPoul-Henning Kamp 		vsunlock(req.oldptr, req.oldlen, B_WRITE);
9244b2af45fSPoul-Henning Kamp 
9254b2af45fSPoul-Henning Kamp 	memlock.sl_lock = 0;
9264b2af45fSPoul-Henning Kamp 
9274b2af45fSPoul-Henning Kamp 	if (memlock.sl_want) {
9284b2af45fSPoul-Henning Kamp 		memlock.sl_want = 0;
9294b2af45fSPoul-Henning Kamp 		wakeup((caddr_t)&memlock);
9304b2af45fSPoul-Henning Kamp 	}
9314b2af45fSPoul-Henning Kamp 
932deae269aSPoul-Henning Kamp 	if (error && error != ENOMEM)
933deae269aSPoul-Henning Kamp 		return (error);
934deae269aSPoul-Henning Kamp 
935deae269aSPoul-Henning Kamp 	if (retval) {
936deae269aSPoul-Henning Kamp 		if (req.oldptr && req.oldidx > req.oldlen)
937ae0eb976SPoul-Henning Kamp 			*retval = req.oldlen;
938deae269aSPoul-Henning Kamp 		else
939deae269aSPoul-Henning Kamp 			*retval = req.oldidx;
940b8da2396SPoul-Henning Kamp 	}
9412e210993SPoul-Henning Kamp 	return (error);
942df8bae1dSRodney W. Grimes }
943df8bae1dSRodney W. Grimes 
944df8bae1dSRodney W. Grimes #ifdef COMPAT_43
945df8bae1dSRodney W. Grimes #include <sys/socket.h>
946df8bae1dSRodney W. Grimes #define	KINFO_PROC		(0<<8)
947df8bae1dSRodney W. Grimes #define	KINFO_RT		(1<<8)
948df8bae1dSRodney W. Grimes #define	KINFO_VNODE		(2<<8)
949df8bae1dSRodney W. Grimes #define	KINFO_FILE		(3<<8)
950df8bae1dSRodney W. Grimes #define	KINFO_METER		(4<<8)
951df8bae1dSRodney W. Grimes #define	KINFO_LOADAVG		(5<<8)
952df8bae1dSRodney W. Grimes #define	KINFO_CLOCKRATE		(6<<8)
953df8bae1dSRodney W. Grimes 
9546ece4a51SPeter Wemm /* Non-standard BSDI extension - only present on their 4.3 net-2 releases */
9556ece4a51SPeter Wemm #define	KINFO_BSDI_SYSINFO	(101<<8)
9566ece4a51SPeter Wemm 
9576ece4a51SPeter Wemm /*
9586ece4a51SPeter Wemm  * XXX this is bloat, but I hope it's better here than on the potentially
9596ece4a51SPeter Wemm  * limited kernel stack...  -Peter
9606ece4a51SPeter Wemm  */
9616ece4a51SPeter Wemm 
96287b6de2bSPoul-Henning Kamp static struct {
9636ece4a51SPeter Wemm 	int	bsdi_machine;		/* "i386" on BSD/386 */
9646ece4a51SPeter Wemm /*      ^^^ this is an offset to the string, relative to the struct start */
9656ece4a51SPeter Wemm 	char	*pad0;
9666ece4a51SPeter Wemm 	long	pad1;
9676ece4a51SPeter Wemm 	long	pad2;
9686ece4a51SPeter Wemm 	long	pad3;
9696ece4a51SPeter Wemm 	u_long	pad4;
9706ece4a51SPeter Wemm 	u_long	pad5;
9716ece4a51SPeter Wemm 	u_long	pad6;
9726ece4a51SPeter Wemm 
9736ece4a51SPeter Wemm 	int	bsdi_ostype;		/* "BSD/386" on BSD/386 */
9746ece4a51SPeter Wemm 	int	bsdi_osrelease;		/* "1.1" on BSD/386 */
9756ece4a51SPeter Wemm 	long	pad7;
9766ece4a51SPeter Wemm 	long	pad8;
9776ece4a51SPeter Wemm 	char	*pad9;
9786ece4a51SPeter Wemm 
9796ece4a51SPeter Wemm 	long	pad10;
9806ece4a51SPeter Wemm 	long	pad11;
9816ece4a51SPeter Wemm 	int	pad12;
9826ece4a51SPeter Wemm 	long	pad13;
9836ece4a51SPeter Wemm 	quad_t	pad14;
9846ece4a51SPeter Wemm 	long	pad15;
9856ece4a51SPeter Wemm 
9866ece4a51SPeter Wemm 	struct	timeval pad16;
9876ece4a51SPeter Wemm 	/* we dont set this, because BSDI's uname used gethostname() instead */
9886ece4a51SPeter Wemm 	int	bsdi_hostname;		/* hostname on BSD/386 */
9896ece4a51SPeter Wemm 
9906ece4a51SPeter Wemm 	/* the actual string data is appended here */
9916ece4a51SPeter Wemm 
9926ece4a51SPeter Wemm } bsdi_si;
9936ece4a51SPeter Wemm /*
9946ece4a51SPeter Wemm  * this data is appended to the end of the bsdi_si structure during copyout.
9956ece4a51SPeter Wemm  * The "char *" offsets are relative to the base of the bsdi_si struct.
9966ece4a51SPeter Wemm  * This contains "FreeBSD\02.0-BUILT-nnnnnn\0i386\0", and these strings
9976ece4a51SPeter Wemm  * should not exceed the length of the buffer here... (or else!! :-)
9986ece4a51SPeter Wemm  */
99987b6de2bSPoul-Henning Kamp static char bsdi_strings[80];	/* It had better be less than this! */
10006ece4a51SPeter Wemm 
1001d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1002df8bae1dSRodney W. Grimes struct getkerninfo_args {
1003df8bae1dSRodney W. Grimes 	int	op;
1004df8bae1dSRodney W. Grimes 	char	*where;
1005df8bae1dSRodney W. Grimes 	int	*size;
1006df8bae1dSRodney W. Grimes 	int	arg;
1007df8bae1dSRodney W. Grimes };
1008d2d3e875SBruce Evans #endif
1009df8bae1dSRodney W. Grimes 
101026f9a767SRodney W. Grimes int
10114b2af45fSPoul-Henning Kamp ogetkerninfo(struct proc *p, struct getkerninfo_args *uap, int *retval)
1012df8bae1dSRodney W. Grimes {
1013b8da2396SPoul-Henning Kamp 	int error, name[6];
1014df8bae1dSRodney W. Grimes 	u_int size;
1015df8bae1dSRodney W. Grimes 
1016df8bae1dSRodney W. Grimes 	switch (uap->op & 0xff00) {
1017df8bae1dSRodney W. Grimes 
1018df8bae1dSRodney W. Grimes 	case KINFO_RT:
1019b8da2396SPoul-Henning Kamp 		name[0] = CTL_NET;
1020b8da2396SPoul-Henning Kamp 		name[1] = PF_ROUTE;
1021b8da2396SPoul-Henning Kamp 		name[2] = 0;
1022b8da2396SPoul-Henning Kamp 		name[3] = (uap->op & 0xff0000) >> 16;
1023b8da2396SPoul-Henning Kamp 		name[4] = uap->op & 0xff;
1024b8da2396SPoul-Henning Kamp 		name[5] = uap->arg;
1025b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 6, uap->where, uap->size,
10264b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1027df8bae1dSRodney W. Grimes 		break;
1028df8bae1dSRodney W. Grimes 
1029df8bae1dSRodney W. Grimes 	case KINFO_VNODE:
1030b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1031b8da2396SPoul-Henning Kamp 		name[1] = KERN_VNODE;
1032b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10334b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1034df8bae1dSRodney W. Grimes 		break;
1035df8bae1dSRodney W. Grimes 
1036df8bae1dSRodney W. Grimes 	case KINFO_PROC:
1037b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1038b8da2396SPoul-Henning Kamp 		name[1] = KERN_PROC;
1039b8da2396SPoul-Henning Kamp 		name[2] = uap->op & 0xff;
1040b8da2396SPoul-Henning Kamp 		name[3] = uap->arg;
1041b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 4, uap->where, uap->size,
10424b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1043df8bae1dSRodney W. Grimes 		break;
1044df8bae1dSRodney W. Grimes 
1045df8bae1dSRodney W. Grimes 	case KINFO_FILE:
1046b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1047b8da2396SPoul-Henning Kamp 		name[1] = KERN_FILE;
1048b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10494b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1050df8bae1dSRodney W. Grimes 		break;
1051df8bae1dSRodney W. Grimes 
1052df8bae1dSRodney W. Grimes 	case KINFO_METER:
1053b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
1054b8da2396SPoul-Henning Kamp 		name[1] = VM_METER;
1055b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10564b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1057df8bae1dSRodney W. Grimes 		break;
1058df8bae1dSRodney W. Grimes 
1059df8bae1dSRodney W. Grimes 	case KINFO_LOADAVG:
1060b8da2396SPoul-Henning Kamp 		name[0] = CTL_VM;
1061b8da2396SPoul-Henning Kamp 		name[1] = VM_LOADAVG;
1062b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10634b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1064df8bae1dSRodney W. Grimes 		break;
1065df8bae1dSRodney W. Grimes 
1066df8bae1dSRodney W. Grimes 	case KINFO_CLOCKRATE:
1067b8da2396SPoul-Henning Kamp 		name[0] = CTL_KERN;
1068b8da2396SPoul-Henning Kamp 		name[1] = KERN_CLOCKRATE;
1069b8da2396SPoul-Henning Kamp 		error = userland_sysctl(p, name, 2, uap->where, uap->size,
10704b2af45fSPoul-Henning Kamp 			0, 0, 0, &size);
1071df8bae1dSRodney W. Grimes 		break;
1072df8bae1dSRodney W. Grimes 
10736ece4a51SPeter Wemm 	case KINFO_BSDI_SYSINFO: {
10746ece4a51SPeter Wemm 		/*
10756ece4a51SPeter Wemm 		 * this is pretty crude, but it's just enough for uname()
10766ece4a51SPeter Wemm 		 * from BSDI's 1.x libc to work.
10776ece4a51SPeter Wemm 		 *
10786ece4a51SPeter Wemm 		 * In particular, it doesn't return the same results when
10796ece4a51SPeter Wemm 		 * the supplied buffer is too small.  BSDI's version apparently
10806ece4a51SPeter Wemm 		 * will return the amount copied, and set the *size to how
10816ece4a51SPeter Wemm 		 * much was needed.  The emulation framework here isn't capable
10826ece4a51SPeter Wemm 		 * of that, so we just set both to the amount copied.
10836ece4a51SPeter Wemm 		 * BSDI's 2.x product apparently fails with ENOMEM in this
10846ece4a51SPeter Wemm 		 * scenario.
10856ece4a51SPeter Wemm 		 */
10866ece4a51SPeter Wemm 
10876ece4a51SPeter Wemm 		u_int needed;
10886ece4a51SPeter Wemm 		u_int left;
10896ece4a51SPeter Wemm 		char *s;
10906ece4a51SPeter Wemm 
10916ece4a51SPeter Wemm 		bzero((char *)&bsdi_si, sizeof(bsdi_si));
10926ece4a51SPeter Wemm 		bzero(bsdi_strings, sizeof(bsdi_strings));
10936ece4a51SPeter Wemm 
10946ece4a51SPeter Wemm 		s = bsdi_strings;
10956ece4a51SPeter Wemm 
10966ece4a51SPeter Wemm 		bsdi_si.bsdi_ostype = (s - bsdi_strings) + sizeof(bsdi_si);
10976ece4a51SPeter Wemm 		strcpy(s, ostype);
10986ece4a51SPeter Wemm 		s += strlen(s) + 1;
10996ece4a51SPeter Wemm 
11006ece4a51SPeter Wemm 		bsdi_si.bsdi_osrelease = (s - bsdi_strings) + sizeof(bsdi_si);
11016ece4a51SPeter Wemm 		strcpy(s, osrelease);
11026ece4a51SPeter Wemm 		s += strlen(s) + 1;
11036ece4a51SPeter Wemm 
11046ece4a51SPeter Wemm 		bsdi_si.bsdi_machine = (s - bsdi_strings) + sizeof(bsdi_si);
11056ece4a51SPeter Wemm 		strcpy(s, machine);
11066ece4a51SPeter Wemm 		s += strlen(s) + 1;
11076ece4a51SPeter Wemm 
11086ece4a51SPeter Wemm 		needed = sizeof(bsdi_si) + (s - bsdi_strings);
11096ece4a51SPeter Wemm 
11106ece4a51SPeter Wemm 		if (uap->where == NULL) {
11116ece4a51SPeter Wemm 			/* process is asking how much buffer to supply.. */
11126ece4a51SPeter Wemm 			size = needed;
11136ece4a51SPeter Wemm 			error = 0;
11146ece4a51SPeter Wemm 			break;
11156ece4a51SPeter Wemm 		}
11166ece4a51SPeter Wemm 
11176ece4a51SPeter Wemm 
11186ece4a51SPeter Wemm 		/* if too much buffer supplied, trim it down */
11196ece4a51SPeter Wemm 		if (size > needed)
11206ece4a51SPeter Wemm 			size = needed;
11216ece4a51SPeter Wemm 
11226ece4a51SPeter Wemm 		/* how much of the buffer is remaining */
11236ece4a51SPeter Wemm 		left = size;
11246ece4a51SPeter Wemm 
11256ece4a51SPeter Wemm 		if ((error = copyout((char *)&bsdi_si, uap->where, left)) != 0)
11266ece4a51SPeter Wemm 			break;
11276ece4a51SPeter Wemm 
11286ece4a51SPeter Wemm 		/* is there any point in continuing? */
11296ece4a51SPeter Wemm 		if (left > sizeof(bsdi_si)) {
11306ece4a51SPeter Wemm 			left -= sizeof(bsdi_si);
11316ece4a51SPeter Wemm 			error = copyout(&bsdi_strings,
11326ece4a51SPeter Wemm 					uap->where + sizeof(bsdi_si), left);
11336ece4a51SPeter Wemm 		}
11346ece4a51SPeter Wemm 		break;
11356ece4a51SPeter Wemm 	}
11366ece4a51SPeter Wemm 
1137df8bae1dSRodney W. Grimes 	default:
1138df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1139df8bae1dSRodney W. Grimes 	}
1140df8bae1dSRodney W. Grimes 	if (error)
1141df8bae1dSRodney W. Grimes 		return (error);
1142df8bae1dSRodney W. Grimes 	*retval = size;
1143df8bae1dSRodney W. Grimes 	if (uap->size)
1144df8bae1dSRodney W. Grimes 		error = copyout((caddr_t)&size, (caddr_t)uap->size,
1145df8bae1dSRodney W. Grimes 		    sizeof(size));
1146df8bae1dSRodney W. Grimes 	return (error);
1147df8bae1dSRodney W. Grimes }
1148df8bae1dSRodney W. Grimes #endif /* COMPAT_43 */
1149