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