sysctl.c revision 1.103
1/*	$OpenBSD: sysctl.c,v 1.103 2004/01/11 21:54:27 deraadt Exp $	*/
2/*	$NetBSD: sysctl.c,v 1.9 1995/09/30 07:12:50 thorpej Exp $	*/
3
4/*
5 * Copyright (c) 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1993\n\
36	The Regents of the University of California.  All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40#if 0
41static const char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
42#else
43static char *rcsid = "$OpenBSD: sysctl.c,v 1.103 2004/01/11 21:54:27 deraadt Exp $";
44#endif
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/gmon.h>
49#include <sys/mount.h>
50#include <sys/stat.h>
51#include <sys/sem.h>
52#include <sys/shm.h>
53#include <sys/sysctl.h>
54#include <sys/socket.h>
55#include <sys/malloc.h>
56#include <sys/dkstat.h>
57#include <sys/uio.h>
58#include <sys/tty.h>
59#include <sys/namei.h>
60#include <sys/sensors.h>
61#include <machine/cpu.h>
62#include <net/route.h>
63
64#include <netinet/in.h>
65#include <netinet/in_systm.h>
66#include <netinet/ip.h>
67#include <netinet/in_pcb.h>
68#include <netinet/ip_icmp.h>
69#include <netinet/ip_ipip.h>
70#include <netinet/ip_ether.h>
71#include <netinet/ip_ah.h>
72#include <netinet/ip_esp.h>
73#include <netinet/icmp_var.h>
74#include <netinet/ip_var.h>
75#include <netinet/udp.h>
76#include <netinet/udp_var.h>
77#include <netinet/tcp.h>
78#include <netinet/tcp_timer.h>
79#include <netinet/tcp_var.h>
80#include <netinet/ip_gre.h>
81#include <netinet/ip_ipcomp.h>
82#include <netinet/ip_carp.h>
83
84#ifdef INET6
85#include <netinet/ip6.h>
86#include <netinet/icmp6.h>
87#include <netinet6/ip6_var.h>
88#include <netinet6/pim6_var.h>
89#endif
90
91#include <uvm/uvm_swap_encrypt.h>
92
93#include <ufs/ufs/quota.h>
94#include <ufs/ufs/inode.h>
95#include <ufs/ffs/fs.h>
96#include <ufs/ffs/ffs_extern.h>
97
98#include <nfs/rpcv2.h>
99#include <nfs/nfsproto.h>
100#include <nfs/nfs.h>
101
102#include <netipx/ipx.h>
103#include <netipx/ipx_var.h>
104#include <netipx/spx_var.h>
105#include <ddb/db_var.h>
106#include <dev/rndvar.h>
107
108#include <err.h>
109#include <errno.h>
110#include <stdio.h>
111#include <stdlib.h>
112#include <string.h>
113#include <ctype.h>
114
115#ifdef CPU_BIOS
116#include <machine/biosvar.h>
117#endif
118
119struct ctlname topname[] = CTL_NAMES;
120struct ctlname kernname[] = CTL_KERN_NAMES;
121struct ctlname vmname[] = CTL_VM_NAMES;
122struct ctlname fsname[] = CTL_FS_NAMES;
123struct ctlname netname[] = CTL_NET_NAMES;
124struct ctlname hwname[] = CTL_HW_NAMES;
125struct ctlname username[] = CTL_USER_NAMES;
126struct ctlname debugname[CTL_DEBUG_MAXID];
127struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
128struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
129struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
130struct ctlname ttyname[] = CTL_KERN_TTY_NAMES;
131struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES;
132struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES;
133struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES;
134struct ctlname *vfsname;
135#ifdef CTL_MACHDEP_NAMES
136struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
137#endif
138struct ctlname ddbname[] = CTL_DDB_NAMES;
139char names[BUFSIZ];
140int lastused;
141
142struct list {
143	struct	ctlname *list;
144	int	size;
145};
146struct list toplist = { topname, CTL_MAXID };
147struct list secondlevel[] = {
148	{ 0, 0 },			/* CTL_UNSPEC */
149	{ kernname, KERN_MAXID },	/* CTL_KERN */
150	{ vmname, VM_MAXID },		/* CTL_VM */
151	{ fsname, FS_MAXID },		/* CTL_FS */
152	{ netname, NET_MAXID },		/* CTL_NET */
153	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
154	{ hwname, HW_MAXID },		/* CTL_HW */
155#ifdef CTL_MACHDEP_NAMES
156	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
157#else
158	{ 0, 0 },			/* CTL_MACHDEP */
159#endif
160	{ username, USER_MAXID },	/* CTL_USER_NAMES */
161	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
162	{ 0, 0 },			/* CTL_VFS */
163};
164
165int	Aflag, aflag, nflag, qflag;
166
167/*
168 * Variables requiring special processing.
169 */
170#define	CLOCK		0x00000001
171#define	BOOTTIME	0x00000002
172#define	CHRDEV		0x00000004
173#define	BLKDEV		0x00000008
174#define	RNDSTATS	0x00000010
175#define	BADDYNAMIC	0x00000020
176#define	BIOSGEO		0x00000040
177#define	BIOSDEV		0x00000080
178#define	MAJ2DEV		0x00000100
179#define	UNSIGNED	0x00000200
180#define	KMEMBUCKETS	0x00000400
181#define	LONGARRAY	0x00000800
182#define	KMEMSTATS	0x00001000
183#define	SENSORS		0x00002000
184
185/* prototypes */
186void debuginit(void);
187void listall(char *, struct list *);
188void parse(char *, int);
189void parse_baddynamic(int *, size_t, char *, void **, size_t *, int, int);
190void usage(void);
191int findname(char *, char *, char **, struct list *);
192int sysctl_inet(char *, char **, int *, int, int *);
193#ifdef INET6
194int sysctl_inet6(char *, char **, int *, int, int *);
195#endif
196int sysctl_ipx(char *, char **, int *, int, int *);
197int sysctl_fs(char *, char **, int *, int, int *);
198static int sysctl_vfs(char *, char **, int[], int, int *);
199static int sysctl_vfsgen(char *, char **, int[], int, int *);
200int sysctl_bios(char *, char **, int *, int, int *);
201int sysctl_swpenc(char *, char **, int *, int, int *);
202int sysctl_forkstat(char *, char **, int *, int, int *);
203int sysctl_tty(char *, char **, int *, int, int *);
204int sysctl_nchstats(char *, char **, int *, int, int *);
205int sysctl_malloc(char *, char **, int *, int, int *);
206int sysctl_seminfo(char *, char **, int *, int, int *);
207int sysctl_shminfo(char *, char **, int *, int, int *);
208int sysctl_watchdog(char *, char **, int *, int, int *);
209int sysctl_sensors(char *, char **, int *, int, int *);
210int sysctl_emul(char *, char *, int);
211#ifdef CPU_CHIPSET
212int sysctl_chipset(char *, char **, int *, int, int *);
213#endif
214void vfsinit(void);
215
216char *equ = "=";
217
218int
219main(int argc, char *argv[])
220{
221	int ch, lvl1;
222
223	while ((ch = getopt(argc, argv, "AanqwO")) != -1) {
224		switch (ch) {
225
226		case 'O':
227			equ = " = ";
228			break;
229
230		case 'A':
231			Aflag = 1;
232			break;
233
234		case 'a':
235			aflag = 1;
236			break;
237
238		case 'n':
239			nflag = 1;
240			break;
241
242		case 'q':
243			qflag = 1;
244			break;
245
246		case 'w':
247			/* flag no longer needed; var=value implies write */
248			break;
249
250		default:
251			usage();
252		}
253	}
254	argc -= optind;
255	argv += optind;
256
257	if (argc == 0 && (Aflag || aflag)) {
258		debuginit();
259		vfsinit();
260		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
261			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
262		return (0);
263	}
264	if (argc == 0)
265		usage();
266	for (; *argv != NULL; ++argv)
267		parse(*argv, 1);
268	return (0);
269}
270
271/*
272 * List all variables known to the system.
273 */
274void
275listall(char *prefix, struct list *lp)
276{
277	char *cp, name[BUFSIZ];
278	int lvl2, len;
279
280	if (lp->list == NULL)
281		return;
282	if ((len = strlcpy(name, prefix, sizeof(name))) >= sizeof(name))
283		warn("%s: name too long", prefix);
284	cp = name + len++;
285	*cp++ = '.';
286	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
287		if (lp->list[lvl2].ctl_name == NULL)
288			continue;
289		if (strlcpy(cp, lp->list[lvl2].ctl_name,
290		    sizeof(name) - len) >= sizeof(name) - len)
291			warn("%s: name too long", lp->list[lvl2].ctl_name);
292		parse(name, Aflag);
293	}
294}
295
296/*
297 * Parse a name into a MIB entry.
298 * Lookup and print out the MIB entry if it exists.
299 * Set a new value if requested.
300 */
301void
302parse(char *string, int flags)
303{
304	int indx, type, state, intval, len;
305	size_t size, newsize = 0;
306	int lal = 0, special = 0;
307	void *newval = 0;
308	int64_t quadval;
309	struct list *lp;
310	int mib[CTL_MAXNAME];
311	char *cp, *bufp, buf[BUFSIZ];
312
313	(void)strlcpy(buf, string, sizeof(buf));
314	bufp = buf;
315	if ((cp = strchr(string, '=')) != NULL) {
316		*strchr(buf, '=') = '\0';
317		*cp++ = '\0';
318		while (isspace(*cp))
319			cp++;
320		newval = cp;
321		newsize = strlen(cp);
322	}
323	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
324		return;
325	mib[0] = indx;
326	if (indx == CTL_VFS)
327		vfsinit();
328	if (indx == CTL_DEBUG)
329		debuginit();
330	lp = &secondlevel[indx];
331	if (lp->list == 0) {
332		warnx("%s: class is not implemented", topname[indx].ctl_name);
333		return;
334	}
335	if (bufp == NULL) {
336		listall(topname[indx].ctl_name, lp);
337		return;
338	}
339	if ((indx = findname(string, "second", &bufp, lp)) == -1)
340		return;
341	mib[1] = indx;
342	type = lp->list[indx].ctl_type;
343	len = 2;
344	switch (mib[0]) {
345
346	case CTL_KERN:
347		switch (mib[1]) {
348		case KERN_PROF:
349			mib[2] = GPROF_STATE;
350			size = sizeof(state);
351			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
352				if (flags == 0)
353					return;
354				if (!nflag)
355					(void)printf("%s: ", string);
356				(void)puts("kernel is not compiled for profiling");
357				return;
358			}
359			if (!nflag)
360				(void)printf("%s = %s\n", string,
361				    state == GMON_PROF_OFF ? "off" : "running");
362			return;
363		case KERN_FORKSTAT:
364			sysctl_forkstat(string, &bufp, mib, flags, &type);
365			return;
366		case KERN_TTY:
367			len = sysctl_tty(string, &bufp, mib, flags, &type);
368			if (len < 0)
369				return;
370			newsize = 0;
371			break;
372		case KERN_NCHSTATS:
373			sysctl_nchstats(string, &bufp, mib, flags, &type);
374			return;
375		case KERN_MALLOCSTATS:
376			len = sysctl_malloc(string, &bufp, mib, flags, &type);
377			if (len < 0)
378				return;
379			if (mib[2] == KERN_MALLOC_BUCKET)
380				special |= KMEMBUCKETS;
381			if (mib[2] == KERN_MALLOC_KMEMSTATS)
382				special |= KMEMSTATS;
383			newsize = 0;
384			break;
385		case KERN_MBSTAT:
386			if (flags == 0)
387				return;
388			warnx("use netstat to view %s", string);
389			return;
390		case KERN_MSGBUF:
391			if (flags == 0)
392				return;
393			warnx("use dmesg to view %s", string);
394			return;
395		case KERN_VNODE:
396		case KERN_FILE:
397			if (flags == 0)
398				return;
399			warnx("use pstat to view %s information", string);
400			return;
401		case KERN_PROC:
402		case KERN_PROC2:
403			if (flags == 0)
404				return;
405			warnx("use ps to view %s information", string);
406			return;
407		case KERN_CLOCKRATE:
408			special |= CLOCK;
409			break;
410		case KERN_BOOTTIME:
411			special |= BOOTTIME;
412			break;
413		case KERN_RND:
414			special |= RNDSTATS;
415			break;
416		case KERN_HOSTID:
417		case KERN_ARND:
418			special |= UNSIGNED;
419			break;
420		case KERN_CPTIME:
421			special |= LONGARRAY;
422			lal = CPUSTATES;
423			break;
424		case KERN_SEMINFO:
425			len = sysctl_seminfo(string, &bufp, mib, flags, &type);
426			if (len < 0)
427				return;
428			break;
429		case KERN_SHMINFO:
430			len = sysctl_shminfo(string, &bufp, mib, flags, &type);
431			if (len < 0)
432				return;
433			break;
434		case KERN_WATCHDOG:
435			len = sysctl_watchdog(string, &bufp, mib, flags,
436			    &type);
437			if (len < 0)
438				return;
439			break;
440		case KERN_EMUL:
441			sysctl_emul(string, newval, flags);
442			return;
443		}
444		break;
445
446	case CTL_HW:
447		switch (mib[1]) {
448		case HW_DISKSTATS:
449			/*
450			 * Only complain if someone asks explicitly for this,
451			 * otherwise "fail" silently.
452			 */
453			if (flags)
454				warnx("use vmstat to view %s information",
455				    string);
456			return;
457		case HW_SENSORS:
458			special |= SENSORS;
459			len = sysctl_sensors(string, &bufp, mib, flags, &type);
460			if (len < 0)
461				return;
462			break;
463		}
464		break;
465
466	case CTL_VM:
467		if (mib[1] == VM_LOADAVG) {
468			double loads[3];
469
470			getloadavg(loads, 3);
471			if (!nflag)
472				(void)printf("%s%s", string, equ);
473			(void)printf("%.2f %.2f %.2f\n", loads[0],
474			    loads[1], loads[2]);
475			return;
476		} else if (mib[1] == VM_PSSTRINGS) {
477			struct _ps_strings _ps;
478
479			size = sizeof(_ps);
480			if (sysctl(mib, 2, &_ps, &size, NULL, 0) == -1) {
481				if (flags == 0)
482					return;
483				if (!nflag)
484					(void)printf("%s: ", string);
485				(void)puts("can't find ps strings");
486				return;
487			}
488			if (!nflag)
489				(void)printf("%s%s", string, equ);
490			(void)printf("%p\n", _ps.val);
491			return;
492		} else if (mib[1] == VM_SWAPENCRYPT) {
493			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
494			if (len < 0)
495				return;
496
497			break;
498		} else if (mib[1] == VM_NKMEMPAGES ||
499		    mib[1] == VM_ANONMIN ||
500		    mib[1] == VM_VTEXTMIN ||
501		    mib[1] == VM_VNODEMIN) {
502			break;
503		}
504		if (flags == 0)
505			return;
506		warnx("use vmstat or systat to view %s information", string);
507		return;
508
509		break;
510
511	case CTL_NET:
512		if (mib[1] == PF_INET) {
513			len = sysctl_inet(string, &bufp, mib, flags, &type);
514			if (len < 0)
515				return;
516
517			if ((mib[2] == IPPROTO_TCP &&
518			     mib[3] == TCPCTL_BADDYNAMIC) ||
519			    (mib[2] == IPPROTO_UDP &&
520			     mib[3] == UDPCTL_BADDYNAMIC)) {
521
522				special |= BADDYNAMIC;
523
524				if (newval != NULL)
525					parse_baddynamic(mib, len, string,
526					    &newval, &newsize, flags, nflag);
527			}
528			break;
529		}
530#ifdef INET6
531		if (mib[1] == PF_INET6) {
532			len = sysctl_inet6(string, &bufp, mib, flags, &type);
533			if (len < 0)
534				return;
535
536			break;
537		}
538#endif
539		if (mib[1] == PF_IPX) {
540			len = sysctl_ipx(string, &bufp, mib, flags, &type);
541			if (len >= 0)
542				break;
543			return;
544		}
545		if (flags == 0)
546			return;
547		warnx("use netstat to view %s information", string);
548		return;
549
550	case CTL_DEBUG:
551		mib[2] = CTL_DEBUG_VALUE;
552		len = 3;
553		break;
554
555	case CTL_MACHDEP:
556#ifdef CPU_CONSDEV
557		if (mib[1] == CPU_CONSDEV)
558			special |= CHRDEV;
559#endif
560#ifdef CPU_BLK2CHR
561		if (mib[1] == CPU_BLK2CHR) {
562			if (bufp == NULL)
563				return;
564			mib[2] = makedev(atoi(bufp),0);
565			bufp = NULL;
566			len = 3;
567			special |= CHRDEV;
568			break;
569		}
570#endif
571#ifdef CPU_CHR2BLK
572		if (mib[1] == CPU_CHR2BLK) {
573			if (bufp == NULL)
574				return;
575			mib[2] = makedev(atoi(bufp),0);
576			bufp = NULL;
577			len = 3;
578			special |= BLKDEV;
579			break;
580		}
581#endif
582#ifdef CPU_BIOS
583		if (mib[1] == CPU_BIOS) {
584			len = sysctl_bios(string, &bufp, mib, flags, &type);
585			if (len < 0)
586				return;
587			if (mib[2] == BIOS_DEV)
588				special |= BIOSDEV;
589			if (mib[2] == BIOS_DISKINFO)
590				special |= BIOSGEO;
591			break;
592		}
593#endif
594#ifdef CPU_CHIPSET
595		if (mib[1] == CPU_CHIPSET) {
596			len = sysctl_chipset(string, &bufp, mib, flags, &type);
597			if (len < 0)
598				return;
599			break;
600		}
601#endif
602#ifdef CPU_LONGRUN
603		if (mib[1] == CPU_LONGRUN)
604			return;
605#endif
606
607		break;
608
609	case CTL_FS:
610		len = sysctl_fs(string, &bufp, mib, flags, &type);
611		if (len >= 0)
612			break;
613		return;
614
615	case CTL_VFS:
616		if (mib[1])
617			len = sysctl_vfs(string, &bufp, mib, flags, &type);
618		else
619			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
620		if (len >= 0) {
621			if (type == CTLTYPE_STRUCT) {
622				if (flags)
623					warnx("use nfsstat to view %s information",
624					    MOUNT_NFS);
625				return;
626			} else
627				break;
628		}
629		return;
630
631	case CTL_USER:
632	case CTL_DDB:
633		break;
634
635	default:
636		warnx("illegal top level value: %d", mib[0]);
637		return;
638
639	}
640	if (bufp) {
641		warnx("name %s in %s is unknown", bufp, string);
642		return;
643	}
644	if (newsize > 0) {
645		switch (type) {
646		case CTLTYPE_INT:
647			errno = 0;
648			if (special & UNSIGNED)
649				intval = strtoul(newval, &cp, 10);
650			else
651				intval = strtol(newval, &cp, 10);
652			if (*cp != '\0') {
653				warnx("%s: illegal value: %s", string,
654				    (char *)newval);
655				return;
656			}
657			if (errno == ERANGE) {
658				warnx("%s: value %s out of range", string,
659				    (char *)newval);
660				return;
661			}
662			newval = &intval;
663			newsize = sizeof(intval);
664			break;
665
666		case CTLTYPE_QUAD:
667			/* XXX - assumes sizeof(long long) == sizeof(quad_t) */
668			(void)sscanf(newval, "%lld", (long long *)&quadval);
669			newval = &quadval;
670			newsize = sizeof(quadval);
671			break;
672		}
673	}
674	size = BUFSIZ;
675	if (sysctl(mib, len, buf, &size, newval, newsize) == -1) {
676		if (flags == 0)
677			return;
678		switch (errno) {
679		case EOPNOTSUPP:
680			warnx("%s: value is not available", string);
681			return;
682		case ENOTDIR:
683			warnx("%s: specification is incomplete", string);
684			return;
685		case ENOMEM:
686			warnx("%s: type is unknown to this program", string);
687			return;
688		case ENXIO:
689			if (special & BIOSGEO)
690				return;
691		default:
692			warn("%s", string);
693			return;
694		}
695	}
696	if (special & KMEMBUCKETS) {
697		struct kmembuckets *kb = (struct kmembuckets *)buf;
698		if (!nflag)
699			(void)printf("%s%s", string, equ);
700		printf("(");
701		printf("calls = %llu ", (long long)kb->kb_calls);
702		printf("total_allocated = %llu ", (long long)kb->kb_total);
703		printf("total_free = %lld ", (long long)kb->kb_totalfree);
704		printf("elements = %lld ", (long long)kb->kb_elmpercl);
705		printf("high watermark = %lld ", (long long)kb->kb_highwat);
706		printf("could_free = %lld", (long long)kb->kb_couldfree);
707		printf(")\n");
708		return;
709	}
710	if (special & KMEMSTATS) {
711		struct kmemstats *km = (struct kmemstats *)buf;
712		int j, first = 1;
713
714		if (!nflag)
715			(void)printf("%s%s", string, equ);
716		(void)printf("(inuse = %ld, calls = %ld, memuse = %ldK, "
717		    "limblocks = %d, mapblocks = %d, maxused = %ldK, "
718		    "limit = %ldK, spare = %ld, sizes = (",
719		    km->ks_inuse, km->ks_calls,
720		    (km->ks_memuse + 1023) / 1024, km->ks_limblocks,
721		    km->ks_mapblocks, (km->ks_maxused + 1023) / 1024,
722		    (km->ks_limit + 1023) / 1024, km->ks_spare);
723		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
724			if ((km->ks_size & j ) == 0)
725				continue;
726			if (first)
727				(void)printf("%d", j);
728			else
729				(void)printf(",%d", j);
730			first = 0;
731		}
732		if (first)
733			(void)printf("none");
734		(void)printf("))\n");
735		return;
736	}
737	if (special & CLOCK) {
738		struct clockinfo *clkp = (struct clockinfo *)buf;
739
740		if (!nflag)
741			(void)printf("%s%s", string, equ);
742		(void)printf(
743		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
744		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
745		return;
746	}
747	if (special & BOOTTIME) {
748		struct timeval *btp = (struct timeval *)buf;
749		time_t boottime;
750
751		if (!nflag) {
752			boottime = btp->tv_sec;
753			(void)printf("%s%s%s", string, equ, ctime(&boottime));
754		} else
755			(void)printf("%ld\n", btp->tv_sec);
756		return;
757	}
758	if (special & BLKDEV) {
759		dev_t dev = *(dev_t *)buf;
760
761		if (!nflag)
762			(void)printf("%s%s%s\n", string, equ,
763			    devname(dev, S_IFBLK));
764		else
765			(void)printf("0x%x\n", dev);
766		return;
767	}
768	if (special & CHRDEV) {
769		dev_t dev = *(dev_t *)buf;
770
771		if (!nflag)
772			(void)printf("%s%s%s\n", string, equ,
773			    devname(dev, S_IFCHR));
774		else
775			(void)printf("0x%x\n", dev);
776		return;
777	}
778#ifdef CPU_BIOS
779	if (special & BIOSGEO) {
780		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
781
782		if (!nflag)
783			(void)printf("%s%s", string, equ);
784		(void)printf("bootdev = 0x%x, "
785			     "cylinders = %u, heads = %u, sectors = %u\n",
786			     pdi->bsd_dev, pdi->bios_cylinders,
787			     pdi->bios_heads, pdi->bios_sectors);
788		return;
789	}
790	if (special & BIOSDEV) {
791		int dev = *(int*)buf;
792
793		if (!nflag)
794			(void)printf("%s%s", string, equ);
795		(void) printf("0x%02x\n", dev);
796		return;
797	}
798#endif
799	if (special & UNSIGNED) {
800		if (newsize == 0) {
801			if (!nflag)
802				(void)printf("%s%s", string, equ);
803			(void)printf("%u\n", *(u_int *)buf);
804		} else {
805			if (!qflag) {
806				if (!nflag)
807					(void)printf("%s: %u -> ", string,
808					    *(u_int *)buf);
809				(void)printf("%u\n", *(u_int *)newval);
810			}
811		}
812		return;
813	}
814	if (special & RNDSTATS) {
815		struct rndstats *rndstats = (struct rndstats *)buf;
816		int i;
817
818		if (!nflag)
819			(void)printf("%s%s", string, equ);
820		(void)printf(
821		"%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
822		    (unsigned long long)rndstats->rnd_total,
823		    (unsigned long long)rndstats->rnd_used,
824		    (unsigned long long)rndstats->rnd_reads,
825		    (unsigned long long)rndstats->arc4_reads,
826		    (unsigned long long)rndstats->arc4_nstirs,
827		    (unsigned long long)rndstats->arc4_stirs,
828		    (unsigned long long)rndstats->rnd_pad[0],
829		    (unsigned long long)rndstats->rnd_pad[1],
830		    (unsigned long long)rndstats->rnd_pad[2],
831		    (unsigned long long)rndstats->rnd_pad[3],
832		    (unsigned long long)rndstats->rnd_pad[4],
833		    (unsigned long long)rndstats->rnd_waits,
834		    (unsigned long long)rndstats->rnd_enqs,
835		    (unsigned long long)rndstats->rnd_deqs,
836		    (unsigned long long)rndstats->rnd_drops,
837		    (unsigned long long)rndstats->rnd_drople);
838		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]);
839		    i++)
840			(void)printf(" %llu", (unsigned long long)rndstats->rnd_ed[i]);
841		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]);
842		    i++)
843			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sc[i]);
844		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]);
845		    i++)
846			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sb[i]);
847		printf("\n");
848		return;
849	}
850	if (special & BADDYNAMIC) {
851		in_port_t port, lastport;
852		u_int32_t *baddynamic = (u_int32_t *)buf;
853
854		if (!qflag) {
855			if (!nflag)
856				(void)printf("%s%s", string,
857				    newsize ? ": " : equ);
858			lastport = 0;
859			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
860			    port++)
861				if (DP_ISSET(baddynamic, port)) {
862					(void)printf("%s%hd",
863					    lastport ? "," : "", port);
864					lastport = port;
865				}
866			if (newsize != 0) {
867				if (!nflag)
868					fputs(" -> ", stdout);
869				baddynamic = (u_int32_t *)newval;
870				lastport = 0;
871				for (port = IPPORT_RESERVED/2;
872				    port < IPPORT_RESERVED; port++)
873					if (DP_ISSET(baddynamic, port)) {
874						(void)printf("%s%hd",
875						    lastport ? "," : "", port);
876						lastport = port;
877					}
878			}
879			(void)putchar('\n');
880		}
881		return;
882	}
883	if (special & LONGARRAY) {
884		long *la = (long *)buf;
885		if (!nflag)
886			printf("%s%s", string, equ);
887		while (lal--)
888			printf("%ld%s", *la++, lal? ",":"");
889		putchar('\n');
890		return;
891	}
892	if (special & SENSORS) {
893		struct sensor *s = (struct sensor *)buf;
894
895		if (size > 0) {
896			if (!nflag)
897				printf("%s%s", string, equ);
898			printf("%s, %s, ", s->device, s->desc);
899			switch (s->type) {
900			case SENSOR_TEMP:
901				printf("temp, %.2f degC / %.2f degF",
902				    (s->value - 273150000) / 1000000.0,
903				    (s->value - 273150000) / 1000000.0 * 9 / 5 +
904				    32);
905				break;
906			case SENSOR_FANRPM:
907				printf("fanrpm, %lld RPM", s->value);
908				break;
909			case SENSOR_VOLTS_DC:
910				printf("volts_dc, %.2f V",
911				    s->value / 1000000.0);
912				break;
913			default:
914				printf("unknown");
915			}
916			printf("\n");
917		}
918		return;
919	}
920
921	switch (type) {
922	case CTLTYPE_INT:
923		if (newsize == 0) {
924			if (!nflag)
925				(void)printf("%s%s", string, equ);
926			(void)printf("%d\n", *(int *)buf);
927		} else {
928			if (!qflag) {
929				if (!nflag)
930					(void)printf("%s: %d -> ", string,
931					    *(int *)buf);
932				(void)printf("%d\n", *(int *)newval);
933			}
934		}
935		return;
936
937	case CTLTYPE_STRING:
938		if (newval == NULL) {
939			if (!nflag)
940				(void)printf("%s%s", string, equ);
941			(void)puts(buf);
942		} else {
943			if (!qflag) {
944				if (!nflag)
945					(void)printf("%s: %s -> ", string, buf);
946				(void)puts((char *)newval);
947			}
948		}
949		return;
950
951	case CTLTYPE_QUAD:
952		if (newsize == 0) {
953			long long tmp = *(quad_t *)buf;
954
955			if (!nflag)
956				(void)printf("%s%s", string, equ);
957			(void)printf("%lld\n", tmp);
958		} else {
959			long long tmp = *(quad_t *)buf;
960
961			if (!qflag) {
962				if (!nflag)
963					(void)printf("%s: %lld -> ",
964					    string, tmp);
965				tmp = *(quad_t *)newval;
966				(void)printf("%qd\n", tmp);
967			}
968		}
969		return;
970
971	case CTLTYPE_STRUCT:
972		warnx("%s: unknown structure returned", string);
973		return;
974
975	default:
976	case CTLTYPE_NODE:
977		warnx("%s: unknown type returned", string);
978		return;
979	}
980}
981
982void
983parse_baddynamic(int mib[], size_t len, char *string, void **newvalp,
984    size_t *newsizep, int flags, int nflag)
985{
986	static u_int32_t newbaddynamic[DP_MAPSIZE];
987	in_port_t port;
988	size_t size;
989	char action, *cp;
990
991	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
992		size = sizeof(newbaddynamic);
993		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
994			if (flags == 0)
995				return;
996			if (!nflag)
997				(void)printf("%s: ", string);
998			(void)puts("kernel does contain bad dynamic port tables");
999			return;
1000		}
1001
1002		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1003			if (*cp != '+' && *cp != '-')
1004				errx(1, "cannot mix +/- with full list");
1005			action = *cp++;
1006			port = atoi(cp);
1007			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
1008				errx(1, "invalid port, range is %d to %d",
1009				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
1010			if (action == '+')
1011				DP_SET(newbaddynamic, port);
1012			else
1013				DP_CLR(newbaddynamic, port);
1014		}
1015	} else {
1016		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
1017		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1018			port = atoi(cp);
1019			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
1020				errx(1, "invalid port, range is %d to %d",
1021				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
1022			DP_SET(newbaddynamic, port);
1023		}
1024	}
1025
1026	*newvalp = (void *)newbaddynamic;
1027	*newsizep = sizeof(newbaddynamic);
1028}
1029
1030/*
1031 * Initialize the set of debugging names
1032 */
1033void
1034debuginit(void)
1035{
1036	int mib[3], loc, i;
1037	size_t size;
1038
1039	if (secondlevel[CTL_DEBUG].list != 0)
1040		return;
1041	secondlevel[CTL_DEBUG].list = debugname;
1042	mib[0] = CTL_DEBUG;
1043	mib[2] = CTL_DEBUG_NAME;
1044	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
1045		mib[1] = i;
1046		size = BUFSIZ - loc;
1047		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
1048			continue;
1049		debugname[i].ctl_name = &names[loc];
1050		debugname[i].ctl_type = CTLTYPE_INT;
1051		loc += size;
1052	}
1053	lastused = loc;
1054}
1055
1056struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
1057struct ctlname ffsname[] = FFS_NAMES;
1058struct ctlname nfsname[] = FS_NFS_NAMES;
1059struct list *vfsvars;
1060int *vfs_typenums;
1061
1062/*
1063 * Initialize the set of filesystem names
1064 */
1065void
1066vfsinit(void)
1067{
1068	int mib[4], maxtypenum, cnt, loc, size;
1069	struct vfsconf vfc;
1070	size_t buflen;
1071
1072	if (secondlevel[CTL_VFS].list != 0)
1073		return;
1074	mib[0] = CTL_VFS;
1075	mib[1] = VFS_GENERIC;
1076	mib[2] = VFS_MAXTYPENUM;
1077	buflen = 4;
1078	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
1079		return;
1080	maxtypenum++;	/* + generic */
1081	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
1082		return;
1083	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
1084	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
1085		free(vfs_typenums);
1086		return;
1087	}
1088	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
1089	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
1090		free(vfs_typenums);
1091		free(vfsvars);
1092		return;
1093	}
1094	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
1095	mib[2] = VFS_CONF;
1096	buflen = sizeof vfc;
1097	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
1098		mib[3] = cnt - 1;
1099		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
1100			if (errno == EOPNOTSUPP)
1101				continue;
1102			warn("vfsinit");
1103			free(vfsname);
1104			return;
1105		}
1106		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1107			vfsvars[cnt].list = ffsname;
1108			vfsvars[cnt].size = FFS_MAXID;
1109		}
1110		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1111			vfsvars[cnt].list = nfsname;
1112			vfsvars[cnt].size = NFS_MAXID;
1113		}
1114		vfs_typenums[cnt] = vfc.vfc_typenum;
1115		strlcat(&names[loc], vfc.vfc_name, sizeof names - loc);
1116		vfsname[cnt].ctl_name = &names[loc];
1117		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1118		size = strlen(vfc.vfc_name) + 1;
1119		loc += size;
1120	}
1121	lastused = loc;
1122
1123	vfsname[0].ctl_name = "mounts";
1124	vfsname[0].ctl_type = CTLTYPE_NODE;
1125	vfsvars[0].list = vfsname + 1;
1126	vfsvars[0].size = maxtypenum - 1;
1127
1128	secondlevel[CTL_VFS].list = vfsname;
1129	secondlevel[CTL_VFS].size = maxtypenum;
1130	return;
1131}
1132
1133int
1134sysctl_vfsgen(char *string, char **bufpp, int mib[], int flags, int *typep)
1135{
1136	int indx;
1137	size_t size;
1138	struct vfsconf vfc;
1139
1140	if (*bufpp == NULL) {
1141		listall(string, vfsvars);
1142		return (-1);
1143	}
1144
1145	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1146		return (-1);
1147
1148	mib[1] = VFS_GENERIC;
1149	mib[2] = VFS_CONF;
1150	mib[3] = indx;
1151	size = sizeof vfc;
1152	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
1153		if (errno != EOPNOTSUPP)
1154			warn("vfs print");
1155		return -1;
1156	}
1157	if (flags == 0 && vfc.vfc_refcount == 0)
1158		return -1;
1159	if (!nflag)
1160		fprintf(stdout, "%s has %d mounted instance%s\n",
1161		    string, vfc.vfc_refcount,
1162		    vfc.vfc_refcount != 1 ? "s" : "");
1163	else
1164		fprintf(stdout, "%d\n", vfc.vfc_refcount);
1165
1166	return -1;
1167}
1168
1169int
1170sysctl_vfs(char *string, char **bufpp, int mib[], int flags, int *typep)
1171{
1172	struct list *lp = &vfsvars[mib[1]];
1173	int indx;
1174
1175	if (lp->list == NULL) {
1176		if (flags)
1177			warnx("No variables defined for file system %s", string);
1178		return (-1);
1179	}
1180	if (*bufpp == NULL) {
1181		listall(string, lp);
1182		return (-1);
1183	}
1184	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1185		return (-1);
1186
1187	mib[1] = vfs_typenums[mib[1]];
1188	mib[2] = indx;
1189	*typep = lp->list[indx].ctl_type;
1190	return (3);
1191}
1192
1193struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1194struct list fslist = { posixname, FS_POSIX_MAXID };
1195
1196/*
1197 * handle file system requests
1198 */
1199int
1200sysctl_fs(char *string, char **bufpp, int mib[], int flags, int *typep)
1201{
1202	int indx;
1203
1204	if (*bufpp == NULL) {
1205		listall(string, &fslist);
1206		return (-1);
1207	}
1208	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1209		return (-1);
1210	mib[2] = indx;
1211	*typep = fslist.list[indx].ctl_type;
1212	return (3);
1213}
1214
1215#ifdef CPU_BIOS
1216struct ctlname biosname[] = CTL_BIOS_NAMES;
1217struct list bioslist = { biosname, BIOS_MAXID };
1218
1219/*
1220 * handle BIOS requests
1221 */
1222int
1223sysctl_bios(char *string, char **bufpp, int mib[], int flags, int *typep)
1224{
1225	char *name;
1226	int indx;
1227
1228	if (*bufpp == NULL) {
1229		listall(string, &bioslist);
1230		return (-1);
1231	}
1232	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1233		return (-1);
1234	mib[2] = indx;
1235	if (indx == BIOS_DISKINFO) {
1236		if (*bufpp == NULL) {
1237			char name[BUFSIZ];
1238
1239			/* scan all the bios devices */
1240			for (indx = 0; indx < 256; indx++) {
1241				snprintf(name, sizeof(name), "%s.%u",
1242					 string, indx);
1243				parse(name, 1);
1244			}
1245			return (-1);
1246		}
1247		if ((name = strsep(bufpp, ".")) == NULL) {
1248			warnx("%s: incomplete specification", string);
1249			return (-1);
1250		}
1251		mib[3] = atoi(name);
1252		*typep = CTLTYPE_STRUCT;
1253		return (4);
1254	} else {
1255		*typep = bioslist.list[indx].ctl_type;
1256		return (3);
1257	}
1258}
1259#endif
1260
1261struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1262struct list swpenclist = { swpencname, SWPENC_MAXID };
1263
1264/*
1265 * handle swap encrypt requests
1266 */
1267int
1268sysctl_swpenc(char *string, char **bufpp, int mib[], int flags, int *typep)
1269{
1270	int indx;
1271
1272	if (*bufpp == NULL) {
1273		listall(string, &swpenclist);
1274		return (-1);
1275	}
1276	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1277		return (-1);
1278	mib[2] = indx;
1279	*typep = swpenclist.list[indx].ctl_type;
1280	return (3);
1281}
1282
1283struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1284struct ctlname ipname[] = IPCTL_NAMES;
1285struct ctlname icmpname[] = ICMPCTL_NAMES;
1286struct ctlname ipipname[] = IPIPCTL_NAMES;
1287struct ctlname tcpname[] = TCPCTL_NAMES;
1288struct ctlname udpname[] = UDPCTL_NAMES;
1289struct ctlname espname[] = ESPCTL_NAMES;
1290struct ctlname ahname[] = AHCTL_NAMES;
1291struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1292struct ctlname grename[] = GRECTL_NAMES;
1293struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1294struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1295struct ctlname carpname[] = CARPCTL_NAMES;
1296struct list inetlist = { inetname, IPPROTO_MAXID };
1297struct list inetvars[] = {
1298	{ ipname, IPCTL_MAXID },	/* ip */
1299	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1300	{ 0, 0 },			/* igmp */
1301	{ 0, 0 },			/* ggmp */
1302	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1303	{ 0, 0 },
1304	{ tcpname, TCPCTL_MAXID },	/* tcp */
1305	{ 0, 0 },
1306	{ 0, 0 },			/* egp */
1307	{ 0, 0 },
1308	{ 0, 0 },
1309	{ 0, 0 },
1310	{ 0, 0 },			/* pup */
1311	{ 0, 0 },
1312	{ 0, 0 },
1313	{ 0, 0 },
1314	{ 0, 0 },
1315	{ udpname, UDPCTL_MAXID },	/* udp */
1316	{ 0, 0 },
1317	{ 0, 0 },
1318	{ 0, 0 },
1319	{ 0, 0 },
1320	{ 0, 0 },
1321	{ 0, 0 },
1322	{ 0, 0 },
1323	{ 0, 0 },
1324	{ 0, 0 },
1325	{ 0, 0 },
1326	{ 0, 0 },
1327	{ 0, 0 },
1328	{ 0, 0 },
1329	{ 0, 0 },
1330	{ 0, 0 },
1331	{ 0, 0 },
1332	{ 0, 0 },
1333	{ 0, 0 },
1334	{ 0, 0 },
1335	{ 0, 0 },
1336	{ 0, 0 },
1337	{ 0, 0 },
1338	{ 0, 0 },
1339	{ 0, 0 },
1340	{ 0, 0 },
1341	{ 0, 0 },
1342	{ 0, 0 },
1343	{ 0, 0 },
1344	{ 0, 0 },
1345	{ grename, GRECTL_MAXID }, /* GRE */
1346	{ 0, 0 },
1347	{ 0, 0 },
1348	{ espname, ESPCTL_MAXID },	/* esp */
1349	{ ahname, AHCTL_MAXID },	/* ah */
1350	{ 0, 0 },
1351	{ 0, 0 },
1352	{ 0, 0 },
1353	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1354	{ 0, 0 },
1355	{ 0, 0 },
1356	{ 0, 0 },
1357	{ 0, 0 },
1358	{ 0, 0 },
1359	{ 0, 0 },
1360	{ 0, 0 },
1361	{ 0, 0 },
1362	{ 0, 0 },
1363	{ 0, 0 },
1364	{ 0, 0 },
1365	{ 0, 0 },
1366	{ 0, 0 },
1367	{ 0, 0 },
1368	{ 0, 0 },
1369	{ 0, 0 },
1370	{ 0, 0 },
1371	{ 0, 0 },
1372	{ 0, 0 },
1373	{ 0, 0 },
1374	{ 0, 0 },
1375	{ 0, 0 },
1376	{ 0, 0 },
1377	{ 0, 0 },
1378	{ 0, 0 },
1379	{ 0, 0 },
1380	{ 0, 0 },
1381	{ 0, 0 },
1382	{ 0, 0 },
1383	{ 0, 0 },
1384	{ 0, 0 },
1385	{ 0, 0 },
1386	{ 0, 0 },
1387	{ 0, 0 },
1388	{ 0, 0 },
1389	{ 0, 0 },
1390	{ 0, 0 },
1391	{ 0, 0 },
1392	{ 0, 0 },
1393	{ 0, 0 },
1394	{ 0, 0 },
1395	{ etheripname, ETHERIPCTL_MAXID },
1396	{ 0, 0 },
1397	{ 0, 0 },
1398	{ 0, 0 },
1399	{ 0, 0 },
1400	{ 0, 0 },
1401	{ 0, 0 },
1402	{ 0, 0 },
1403	{ 0, 0 },
1404	{ 0, 0 },
1405	{ 0, 0 },
1406	{ ipcompname, IPCOMPCTL_MAXID },
1407	{ 0, 0 },
1408	{ 0, 0 },
1409	{ 0, 0 },
1410	{ carpname, CARPCTL_MAXID },
1411};
1412
1413struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1414struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1415struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1416struct list ttylist = { ttyname, KERN_TTY_MAXID };
1417struct list semlist = { semname, KERN_SEMINFO_MAXID };
1418struct list shmlist = { shmname, KERN_SHMINFO_MAXID };
1419struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
1420
1421/*
1422 * handle vfs namei cache statistics
1423 */
1424int
1425sysctl_nchstats(char *string, char **bufpp, int mib[], int flags, int *typep)
1426{
1427	static struct nchstats nch;
1428	int indx;
1429	size_t size;
1430	static int keepvalue = 0;
1431
1432	if (*bufpp == NULL) {
1433		bzero(&nch, sizeof(struct nchstats));
1434		listall(string, &nchstatslist);
1435		return (-1);
1436	}
1437	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1438		return (-1);
1439	mib[2] = indx;
1440	if (*bufpp != NULL) {
1441		warnx("fourth level name in %s is invalid", string);
1442		return (-1);
1443	}
1444	if (keepvalue == 0) {
1445		size = sizeof(struct nchstats);
1446		if (sysctl(mib, 2, &nch, &size, NULL, 0) < 0)
1447			return (-1);
1448		keepvalue = 1;
1449	}
1450	if (!nflag)
1451		(void)printf("%s%s", string, equ);
1452	switch (indx) {
1453	case KERN_NCHSTATS_GOODHITS:
1454		(void)printf("%ld\n", nch.ncs_goodhits);
1455		break;
1456	case KERN_NCHSTATS_NEGHITS:
1457		(void)printf("%ld\n", nch.ncs_neghits);
1458		break;
1459	case KERN_NCHSTATS_BADHITS:
1460		(void)printf("%ld\n", nch.ncs_badhits);
1461		break;
1462	case KERN_NCHSTATS_FALSEHITS:
1463		(void)printf("%ld\n", nch.ncs_falsehits);
1464		break;
1465	case KERN_NCHSTATS_MISS:
1466		(void)printf("%ld\n", nch.ncs_miss);
1467		break;
1468	case KERN_NCHSTATS_LONG:
1469		(void)printf("%ld\n", nch.ncs_long);
1470		break;
1471	case KERN_NCHSTATS_PASS2:
1472		(void)printf("%ld\n", nch.ncs_pass2);
1473		break;
1474	case KERN_NCHSTATS_2PASSES:
1475		(void)printf("%ld\n", nch.ncs_2passes);
1476		break;
1477	}
1478	return (-1);
1479}
1480
1481/*
1482 * handle tty statistics
1483 */
1484int
1485sysctl_tty(char *string, char **bufpp, int mib[], int flags, int *typep)
1486{
1487	int indx;
1488
1489	if (*bufpp == NULL) {
1490		listall(string, &ttylist);
1491		return (-1);
1492	}
1493	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1494		return (-1);
1495	mib[2] = indx;
1496	*typep = CTLTYPE_QUAD;
1497	return (3);
1498}
1499
1500/*
1501 * handle fork statistics
1502 */
1503int
1504sysctl_forkstat(char *string, char **bufpp, int mib[], int flags, int *typep)
1505{
1506	static struct forkstat fks;
1507	static int keepvalue = 0;
1508	int indx;
1509	size_t size;
1510
1511	if (*bufpp == NULL) {
1512		bzero(&fks, sizeof(struct forkstat));
1513		listall(string, &forkstatlist);
1514		return (-1);
1515	}
1516	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1517		return (-1);
1518	if (*bufpp != NULL) {
1519		warnx("fourth level name in %s is invalid", string);
1520		return (-1);
1521	}
1522	if (keepvalue == 0) {
1523		size = sizeof(struct forkstat);
1524		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0)
1525			return (-1);
1526		keepvalue = 1;
1527	}
1528	if (!nflag)
1529		(void)printf("%s%s", string, equ);
1530	switch (indx)	{
1531	case KERN_FORKSTAT_FORK:
1532		(void)printf("%d\n", fks.cntfork);
1533		break;
1534	case KERN_FORKSTAT_VFORK:
1535		(void)printf("%d\n", fks.cntvfork);
1536		break;
1537	case KERN_FORKSTAT_RFORK:
1538		(void)printf("%d\n", fks.cntrfork);
1539		break;
1540	case KERN_FORKSTAT_KTHREAD:
1541		(void)printf("%d\n", fks.cntkthread);
1542		break;
1543	case KERN_FORKSTAT_SIZFORK:
1544		(void)printf("%d\n", fks.sizfork);
1545		break;
1546	case KERN_FORKSTAT_SIZVFORK:
1547		(void)printf("%d\n", fks.sizvfork);
1548		break;
1549	case KERN_FORKSTAT_SIZRFORK:
1550		(void)printf("%d\n", fks.sizrfork);
1551		break;
1552	case KERN_FORKSTAT_SIZKTHREAD:
1553		(void)printf("%d\n", fks.sizkthread);
1554		break;
1555	}
1556	return (-1);
1557}
1558
1559/*
1560 * handle malloc statistics
1561 */
1562int
1563sysctl_malloc(char *string, char **bufpp, int mib[], int flags, int *typep)
1564{
1565	int indx, stor, i;
1566	char *name, bufp[BUFSIZ], *buf, *ptr;
1567	struct list lp;
1568	size_t size;
1569
1570	if (*bufpp == NULL) {
1571		listall(string, &kernmalloclist);
1572		return (-1);
1573	}
1574	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1575		return (-1);
1576	mib[2] = indx;
1577	if (mib[2] == KERN_MALLOC_BUCKET) {
1578		if ((name = strsep(bufpp, ".")) == NULL) {
1579			size = BUFSIZ;
1580			stor = mib[2];
1581			mib[2] = KERN_MALLOC_BUCKETS;
1582			buf = bufp;
1583			if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1584				return (-1);
1585			mib[2] = stor;
1586			for (stor = 0, i = 0; i < size; i++)
1587				if (buf[i] == ',')
1588					stor++;
1589			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1590			if (lp.list == NULL)
1591				return (-1);
1592			lp.size = stor + 2;
1593			for (i = 1;
1594			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL;
1595			    i++) {
1596				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1597			}
1598			lp.list[i].ctl_name = buf;
1599			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1600			listall(string, &lp);
1601			free(lp.list);
1602			return (-1);
1603		}
1604		mib[3] = atoi(name);
1605		return (4);
1606	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
1607		*typep = CTLTYPE_STRING;
1608		return (3);
1609	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
1610		size = BUFSIZ;
1611		stor = mib[2];
1612		mib[2] = KERN_MALLOC_KMEMNAMES;
1613		buf = bufp;
1614		if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1615			return (-1);
1616		mib[2] = stor;
1617		if ((name = strsep(bufpp, ".")) == NULL) {
1618			for (stor = 0, i = 0; i < size; i++)
1619				if (buf[i] == ',')
1620					stor++;
1621			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1622			if (lp.list == NULL)
1623				return (-1);
1624			lp.size = stor + 2;
1625			for (i = 1;
1626			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL; i++) {
1627				if (lp.list[i].ctl_name[0] == '\0') {
1628					i--;
1629					continue;
1630				}
1631				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1632			}
1633			lp.list[i].ctl_name = buf;
1634			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1635			listall(string, &lp);
1636			free(lp.list);
1637			return (-1);
1638		}
1639		ptr = strstr(buf, name);
1640 tryagain:
1641		if (ptr == NULL) {
1642		       warnx("fourth level name %s in %s is invalid", name,
1643			     string);
1644		       return (-1);
1645		}
1646		if ((*(ptr + strlen(name)) != ',') &&
1647		    (*(ptr + strlen(name)) != '\0')) {
1648			ptr = strstr(ptr + 1, name); /* retry */
1649			goto tryagain;
1650		}
1651		if ((ptr != buf) && (*(ptr - 1) != ',')) {
1652			ptr = strstr(ptr + 1, name); /* retry */
1653			goto tryagain;
1654		}
1655		for (i = 0, stor = 0; buf + i < ptr; i++)
1656			if (buf[i] == ',')
1657				stor++;
1658		mib[3] = stor;
1659		return (4);
1660	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
1661		*typep = CTLTYPE_STRING;
1662		return (3);
1663	}
1664	return (-1);
1665}
1666
1667#ifdef CPU_CHIPSET
1668/*
1669 * handle machdep.chipset requests
1670 */
1671struct ctlname chipsetname[] = CTL_CHIPSET_NAMES;
1672struct list chipsetlist = { chipsetname, CPU_CHIPSET_MAXID };
1673
1674int
1675sysctl_chipset(char *string, char **bufpp, int mib[], int flags, int *typep)
1676{
1677	int indx, bwx;
1678	static void *q;
1679	size_t len;
1680	char *p;
1681
1682	if (*bufpp == NULL) {
1683		listall(string, &chipsetlist);
1684		return (-1);
1685	}
1686	if ((indx = findname(string, "third", bufpp, &chipsetlist)) == -1)
1687		return (-1);
1688	mib[2] = indx;
1689	if (!nflag)
1690		printf("%s%s", string, equ);
1691	switch(mib[2]) {
1692	case CPU_CHIPSET_MEM:
1693	case CPU_CHIPSET_DENSE:
1694	case CPU_CHIPSET_PORTS:
1695	case CPU_CHIPSET_HAE_MASK:
1696		len = sizeof(void *);
1697		if (sysctl(mib, 3, &q, &len, NULL, 0) < 0)
1698			return (-1);
1699		printf("%p\n", q);
1700		break;
1701	case CPU_CHIPSET_BWX:
1702		len = sizeof(int);
1703		if (sysctl(mib, 3, &bwx, &len, NULL, 0) < 0)
1704			return (-1);
1705		printf("%d\n", bwx);
1706		break;
1707	case CPU_CHIPSET_TYPE:
1708		if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0)
1709			return (-1);
1710		p = malloc(len + 1);
1711		if (p == NULL)
1712			return (-1);
1713		if (sysctl(mib, 3, p, &len, NULL, 0) < 0)
1714			return (-1);
1715		p[len] = '\0';
1716		printf("%s\n", p);
1717		break;
1718	}
1719	return (-1);
1720}
1721#endif
1722/*
1723 * handle internet requests
1724 */
1725int
1726sysctl_inet(char *string, char **bufpp, int mib[], int flags, int *typep)
1727{
1728	struct list *lp;
1729	int indx;
1730
1731	if (*bufpp == NULL) {
1732		listall(string, &inetlist);
1733		return (-1);
1734	}
1735	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1736		return (-1);
1737	mib[2] = indx;
1738	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1739		lp = &inetvars[indx];
1740	else if (!flags)
1741		return (-1);
1742	else {
1743		warnx("%s: no variables defined for this protocol", string);
1744		return (-1);
1745	}
1746	if (*bufpp == NULL) {
1747		listall(string, lp);
1748		return (-1);
1749	}
1750	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1751		return (-1);
1752	mib[3] = indx;
1753	*typep = lp->list[indx].ctl_type;
1754	return (4);
1755}
1756
1757#ifdef INET6
1758struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1759struct ctlname ip6name[] = IPV6CTL_NAMES;
1760struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1761struct ctlname pim6name[] = PIM6CTL_NAMES;
1762struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1763struct list inet6vars[] = {
1764/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1765	{ 0, 0 },
1766	{ 0, 0 },
1767	{ 0, 0 },
1768	{ 0, 0 },
1769	{ 0, 0 },
1770/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1771	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1772/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1773	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1774/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1775	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1776/*40*/	{ 0, 0 },
1777	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1778	{ 0, 0 },
1779	{ 0, 0 },
1780	{ 0, 0 },
1781	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1782/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1783	{ 0, 0 },
1784	{ 0, 0 },
1785	{ 0, 0 },
1786	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1787	{ 0, 0 },
1788/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1789	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1790/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1791	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1792/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1793	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1794/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1795	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1796/*100*/	{ 0, 0 },
1797	{ 0, 0 },
1798	{ 0, 0 },
1799	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
1800};
1801
1802/*
1803 * handle internet6 requests
1804 */
1805int
1806sysctl_inet6(char *string, char **bufpp, int mib[], int flags, int *typep)
1807{
1808	struct list *lp;
1809	int indx;
1810
1811	if (*bufpp == NULL) {
1812		listall(string, &inet6list);
1813		return (-1);
1814	}
1815	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
1816		return (-1);
1817	mib[2] = indx;
1818	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
1819		lp = &inet6vars[indx];
1820	else if (!flags)
1821		return (-1);
1822	else {
1823		warnx("%s: no variables defined for this protocol", string);
1824		return (-1);
1825	}
1826	if (*bufpp == NULL) {
1827		listall(string, lp);
1828		return (-1);
1829	}
1830	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1831		return (-1);
1832	mib[3] = indx;
1833	*typep = lp->list[indx].ctl_type;
1834	return (4);
1835}
1836#endif
1837
1838struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
1839struct ctlname ipxpname[] = IPXCTL_NAMES;
1840struct ctlname spxpname[] = SPXCTL_NAMES;
1841struct list ipxlist = { ipxname, IPXCTL_MAXID };
1842struct list ipxvars[] = {
1843	{ ipxpname, IPXCTL_MAXID },	/* ipx */
1844	{ 0, 0 },
1845	{ 0, 0 },
1846	{ 0, 0 },
1847	{ 0, 0 },
1848	{ spxpname, SPXCTL_MAXID },
1849};
1850
1851/*
1852 * Handle internet requests
1853 */
1854int
1855sysctl_ipx(char *string, char **bufpp, int mib[], int flags, int *typep)
1856{
1857	struct list *lp;
1858	int indx;
1859
1860	if (*bufpp == NULL) {
1861		listall(string, &ipxlist);
1862		return (-1);
1863	}
1864	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1865		return (-1);
1866	mib[2] = indx;
1867	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1868		lp = &ipxvars[indx];
1869	else if (!flags)
1870		return (-1);
1871	else {
1872		warnx("%s: no variables defined for this protocol", string);
1873		return (-1);
1874	}
1875	if (*bufpp == NULL) {
1876		listall(string, lp);
1877		return (-1);
1878	}
1879	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1880		return (-1);
1881	mib[3] = indx;
1882	*typep = lp->list[indx].ctl_type;
1883	return (4);
1884}
1885
1886/*
1887 * Handle SysV semaphore info requests
1888 */
1889int
1890sysctl_seminfo(string, bufpp, mib, flags, typep)
1891	char *string;
1892	char **bufpp;
1893	int mib[];
1894	int flags;
1895	int *typep;
1896{
1897	int indx;
1898
1899	if (*bufpp == NULL) {
1900		listall(string, &semlist);
1901		return (-1);
1902	}
1903	if ((indx = findname(string, "third", bufpp, &semlist)) == -1)
1904		return (-1);
1905	mib[2] = indx;
1906	*typep = CTLTYPE_INT;
1907	return (3);
1908}
1909
1910/*
1911 * Handle SysV shared memory info requests
1912 */
1913int
1914sysctl_shminfo(string, bufpp, mib, flags, typep)
1915	char *string;
1916	char **bufpp;
1917	int mib[];
1918	int flags;
1919	int *typep;
1920{
1921	int indx;
1922
1923	if (*bufpp == NULL) {
1924		listall(string, &shmlist);
1925		return (-1);
1926	}
1927	if ((indx = findname(string, "third", bufpp, &shmlist)) == -1)
1928		return (-1);
1929	mib[2] = indx;
1930	*typep = CTLTYPE_INT;
1931	return (3);
1932}
1933
1934/*
1935 * Handle watchdog support
1936 */
1937int
1938sysctl_watchdog(char *string, char **bufpp, int mib[], int flags,
1939    int *typep)
1940{
1941	int indx;
1942
1943	if (*bufpp == NULL) {
1944		listall(string, &watchdoglist);
1945		return (-1);
1946	}
1947	if ((indx = findname(string, "third", bufpp, &watchdoglist)) == -1)
1948		return (-1);
1949	mib[2] = indx;
1950	*typep = watchdoglist.list[indx].ctl_type;
1951	return (3);
1952}
1953
1954/*
1955 * Handle hardware monitoring sensors support
1956 */
1957int
1958sysctl_sensors(char *string, char **bufpp, int mib[], int flags, int *typep)
1959{
1960	char *name;
1961	int indx;
1962
1963	if (*bufpp == NULL) {
1964		char name[BUFSIZ];
1965
1966		/* scan all sensors */
1967		for (indx = 0; indx < 256; indx++) {
1968			snprintf(name, sizeof(name), "%s.%u", string, indx);
1969			parse(name, 0);
1970		}
1971		return (-1);
1972	}
1973	if ((name = strsep(bufpp, ".")) == NULL) {
1974		warnx("%s: incomplete specification", string);
1975		return (-1);
1976	}
1977	mib[2] = atoi(name);
1978	*typep = CTLTYPE_STRUCT;
1979	return (3);
1980}
1981
1982char	**emul_names;
1983int	emul_num, nemuls;
1984int	emul_init(void);
1985
1986int
1987sysctl_emul(char *string, char *newval, int flags)
1988{
1989	int mib[4], enabled, i, old, print, found = 0;
1990	char *head, *target;
1991	size_t len;
1992
1993	if (emul_init() == -1) {
1994		warnx("emul_init: out of memory");
1995		return (1);
1996	}
1997
1998	mib[0] = CTL_KERN;
1999	mib[1] = KERN_EMUL;
2000	mib[3] = KERN_EMUL_ENABLED;
2001	head = "kern.emul.";
2002
2003	if (aflag || strcmp(string, "kern.emul") == 0) {
2004		if (strcmp(string, "kern.emul") == 0) {
2005			warnx("%s: specification is incomplete", string);
2006			return (1);
2007		}
2008		if (nflag)
2009			printf("%d\n", nemuls);
2010		else
2011			printf("%snemuls%s%d\n", head, equ, nemuls);
2012		for (i = 0; i < emul_num; i++) {
2013			if (emul_names[i] == NULL)
2014				continue;
2015			mib[2] = i + 1;
2016			len = sizeof(int);
2017			if (sysctl(mib, 4, &enabled, &len, NULL, 0) == -1) {
2018				warn("%s", string);
2019				continue;
2020			}
2021			if (nflag)
2022				printf("%d\n", enabled);
2023			else
2024				printf("%s%s%s%d\n", head, emul_names[i], equ,
2025				    enabled);
2026		}
2027		return (0);
2028	}
2029	/* User specified a third level name */
2030	target = strrchr(string, '.');
2031	target++;
2032	if (strcmp(string, "nemuls") == 0) {
2033		if (newval) {
2034			warnx("Operation not permitted");
2035			return (1);
2036		}
2037		if (nflag)
2038			printf("%d\n", nemuls);
2039		else
2040			printf("%snemuls = %d\n", head, nemuls);
2041		return (0);
2042	}
2043	for (i = 0; i < emul_num; i++) {
2044		print = 1;
2045		if (!emul_names[i]) {
2046			print = 0;
2047			if (strcmp(target, emul_names[i-1]))
2048				continue;
2049		} else if (strcmp(target, emul_names[i]))
2050			continue;
2051		found = 1;
2052		mib[2] = i + 1;
2053		len = sizeof(int);
2054		if (newval) {
2055			enabled = atoi(newval);
2056			if (sysctl(mib, 4, &old, &len, &enabled, len) == -1) {
2057				warn("%s", string);
2058				continue;
2059			}
2060			if (print) {
2061				if (nflag)
2062					printf("%d\n", enabled);
2063				else
2064					printf("%s%s: %d -> %d\n", head,
2065					    target, old, enabled);
2066			}
2067		} else {
2068			if (sysctl(mib, 4, &enabled, &len, NULL, 0) == -1) {
2069				warn("%s", string);
2070				continue;
2071			}
2072			if (print) {
2073				if (nflag)
2074					printf("%d\n", enabled);
2075				else
2076					printf("%s%s = %d\n", head, target,
2077					    enabled);
2078			}
2079		}
2080	}
2081	if (!found)
2082		warnx("third level name %s in kern.emul is invalid",
2083		    string);
2084	return (0);
2085
2086
2087}
2088
2089int
2090emul_init(void)
2091{
2092	static int done;
2093	char string[16];
2094	int mib[4], i;
2095	size_t len;
2096
2097	if (done)
2098		return;
2099	done = 1;
2100
2101	mib[0] = CTL_KERN;
2102	mib[1] = KERN_EMUL;
2103	mib[2] = KERN_EMUL_NUM;
2104	len = sizeof(int);
2105	if (sysctl(mib, 3, &emul_num, &len, NULL, 0) == -1)
2106		return (-1);
2107
2108	emul_names = calloc(emul_num, sizeof(char *));
2109	if (emul_names == NULL)
2110		return (-1);
2111
2112	nemuls = emul_num;
2113	for (i = 0; i < emul_num; i++) {
2114		mib[2] = i + 1;
2115		mib[3] = KERN_EMUL_NAME;
2116		len = sizeof(string);
2117		if (sysctl(mib, 4, string, &len, NULL, 0) == -1)
2118			break;
2119		if (i > 0 && emul_names[i - 1] &&
2120		    strcmp(string, emul_names[i - 1]) == 0) {
2121			nemuls--;
2122			continue;
2123		}
2124		emul_names[i] = strdup(string);
2125		if (emul_names[i] == NULL) {
2126			free(emul_names);
2127			return (-1);
2128		}
2129	}
2130	return (0);
2131}
2132
2133/*
2134 * Scan a list of names searching for a particular name.
2135 */
2136int
2137findname(char *string, char *level, char **bufp, struct list *namelist)
2138{
2139	char *name;
2140	int i;
2141
2142	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
2143		warnx("%s: incomplete specification", string);
2144		return (-1);
2145	}
2146	for (i = 0; i < namelist->size; i++)
2147		if (namelist->list[i].ctl_name != NULL &&
2148		    strcmp(name, namelist->list[i].ctl_name) == 0)
2149			break;
2150	if (i == namelist->size) {
2151		warnx("%s level name %s in %s is invalid", level, name, string);
2152		return (-1);
2153	}
2154	return (i);
2155}
2156
2157void
2158usage(void)
2159{
2160
2161	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n",
2162	    "sysctl [-n] variable ...", "sysctl [-nq] -w variable=value ...",
2163	    "sysctl -aA [-n]");
2164	exit(1);
2165}
2166