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