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