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