sysctl.c revision 1.246
1/*	$OpenBSD: sysctl.c,v 1.246 2019/07/12 00:04:59 cheloha 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#include <sys/types.h>
34#include <sys/gmon.h>
35#include <sys/mount.h>
36#include <sys/sem.h>
37#include <sys/shm.h>
38#include <sys/sysctl.h>
39#include <sys/socket.h>
40#include <sys/time.h>
41#include <sys/malloc.h>
42#include <sys/uio.h>
43#include <sys/tty.h>
44#include <sys/namei.h>
45#include <sys/sched.h>
46#include <sys/sensors.h>
47#include <sys/vmmeter.h>
48#include <net/route.h>
49#include <net/if.h>
50
51#include <netinet/in.h>
52#include <netinet/ip.h>
53#include <netinet/in_pcb.h>
54#include <netinet/ip_icmp.h>
55#include <netinet/ip_ipip.h>
56#include <netinet/ip_ether.h>
57#include <netinet/ip_ah.h>
58#include <netinet/ip_esp.h>
59#include <netinet/icmp_var.h>
60#include <netinet/igmp_var.h>
61#include <netinet/ip_var.h>
62#include <netinet/udp.h>
63#include <netinet/udp_var.h>
64#include <netinet/tcp.h>
65#include <netinet/tcp_timer.h>
66#include <netinet/tcp_var.h>
67#include <netinet/ip_gre.h>
68#include <netinet/ip_ipcomp.h>
69#include <netinet/ip_carp.h>
70#include <netinet/ip_divert.h>
71
72#include <net/pfvar.h>
73#include <net/if_pfsync.h>
74#include <net/pipex.h>
75
76#include <netinet/ip6.h>
77#include <netinet/icmp6.h>
78#include <netinet6/ip6_var.h>
79#include <netinet6/ip6_divert.h>
80
81#include <netmpls/mpls.h>
82
83#include <uvm/uvm_swap_encrypt.h>
84
85#include <ufs/ufs/quota.h>
86#include <ufs/ufs/inode.h>
87#include <ufs/ffs/ffs_extern.h>
88
89#include <miscfs/fuse/fusefs.h>
90
91#include <nfs/nfsproto.h>
92#include <nfs/nfs.h>
93
94#include <ddb/db_var.h>
95#include <dev/rndvar.h>
96
97#include <ctype.h>
98#include <err.h>
99#include <errno.h>
100#include <limits.h>
101#include <paths.h>
102#include <stdio.h>
103#include <stdlib.h>
104#include <string.h>
105#include <unistd.h>
106
107#include <machine/cpu.h>
108
109#ifdef CPU_BIOS
110#include <machine/biosvar.h>
111#endif
112
113struct ctlname topname[] = CTL_NAMES;
114struct ctlname kernname[] = CTL_KERN_NAMES;
115struct ctlname vmname[] = CTL_VM_NAMES;
116struct ctlname fsname[] = CTL_FS_NAMES;
117struct ctlname netname[] = CTL_NET_NAMES;
118struct ctlname hwname[] = CTL_HW_NAMES;
119struct ctlname debugname[CTL_DEBUG_MAXID];
120struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
121struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
122struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
123struct ctlname ttysname[] = CTL_KERN_TTY_NAMES;
124struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES;
125struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES;
126struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES;
127struct ctlname tcname[] = CTL_KERN_TIMECOUNTER_NAMES;
128struct ctlname *vfsname;
129#ifdef CTL_MACHDEP_NAMES
130struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
131#endif
132struct ctlname ddbname[] = CTL_DDB_NAMES;
133struct ctlname audioname[] = CTL_KERN_AUDIO_NAMES;
134struct ctlname witnessname[] = CTL_KERN_WITNESS_NAMES;
135char names[BUFSIZ];
136int lastused;
137
138/* Maximum size object to expect from sysctl(3) */
139#define SYSCTL_BUFSIZ	8192
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	{ 0, 0 },			/* was CTL_USER */
160	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
161	{ 0, 0 },			/* CTL_VFS */
162};
163
164int	Aflag, aflag, nflag, qflag;
165
166time_t boottime;
167
168/*
169 * Variables requiring special processing.
170 */
171#define	CLOCK		0x00000001
172#define	BOOTTIME	0x00000002
173#define	CHRDEV		0x00000004
174#define	BLKDEV		0x00000008
175#define	BADDYNAMIC	0x00000020
176#define	BIOSGEO		0x00000040
177#define	BIOSDEV		0x00000080
178#define	MAJ2DEV		0x00000100
179#define	UNSIGNED	0x00000200
180#define	KMEMBUCKETS	0x00000400
181#define	LONGARRAY	0x00000800
182#define	KMEMSTATS	0x00001000
183#define	SENSORS		0x00002000
184#define	SMALLBUF	0x00004000
185#define	HEX		0x00008000
186#define	TIMEOUT		0x00010000
187
188/* prototypes */
189void debuginit(void);
190void listall(char *, struct list *);
191int parse_hex_char(char);
192ssize_t parse_hex_string(unsigned char *, size_t, const char *);
193void parse(char *, int);
194void parse_baddynamic(int *, size_t, char *, void **, size_t *, int, int);
195void usage(void);
196int findname(char *, char *, char **, struct list *);
197int sysctl_inet(char *, char **, int *, int, int *);
198int sysctl_inet6(char *, char **, int *, int, int *);
199int sysctl_link(char *, char **, int *, int, int *);
200int sysctl_bpf(char *, char **, int *, int, int *);
201int sysctl_mpls(char *, char **, int *, int, int *);
202int sysctl_pipex(char *, char **, int *, int, int *);
203int sysctl_fs(char *, char **, int *, int, int *);
204static int sysctl_vfs(char *, char **, int[], int, int *);
205static int sysctl_vfsgen(char *, char **, int[], int, int *);
206int sysctl_bios(char *, char **, int *, int, int *);
207int sysctl_swpenc(char *, char **, int *, int, int *);
208int sysctl_forkstat(char *, char **, int *, int, int *);
209int sysctl_tty(char *, char **, int *, int, int *);
210int sysctl_nchstats(char *, char **, int *, int, int *);
211int sysctl_malloc(char *, char **, int *, int, int *);
212int sysctl_seminfo(char *, char **, int *, int, int *);
213int sysctl_shminfo(char *, char **, int *, int, int *);
214int sysctl_watchdog(char *, char **, int *, int, int *);
215int sysctl_tc(char *, char **, int *, int, int *);
216int sysctl_sensors(char *, char **, int *, int, int *);
217void print_sensordev(char *, int *, u_int, struct sensordev *);
218void print_sensor(struct sensor *);
219#ifdef CPU_CHIPSET
220int sysctl_chipset(char *, char **, int *, int, int *);
221#endif
222int sysctl_audio(char *, char **, int *, int, int *);
223int sysctl_witness(char *, char **, int *, int, int *);
224void vfsinit(void);
225
226char *equ = "=";
227
228int
229main(int argc, char *argv[])
230{
231	int ch, lvl1;
232
233	while ((ch = getopt(argc, argv, "Aanqw")) != -1) {
234		switch (ch) {
235
236		case 'A':
237			Aflag = 1;
238			break;
239
240		case 'a':
241			aflag = 1;
242			break;
243
244		case 'n':
245			nflag = 1;
246			break;
247
248		case 'q':
249			qflag = 1;
250			break;
251
252		case 'w':
253			/* flag no longer needed; var=value implies write */
254			break;
255
256		default:
257			usage();
258		}
259	}
260	argc -= optind;
261	argv += optind;
262
263	ctime(&boottime); /* satisfy potential $TZ expansion before unveil() */
264
265	if (unveil(_PATH_DEVDB, "r") == -1)
266		err(1,"unveil");
267	if (unveil("/dev", "r") == -1)
268		err(1, "unveil");
269	if (unveil(NULL, NULL) == -1)
270		err(1, "unveil");
271
272	if (argc == 0 || (Aflag || aflag)) {
273		debuginit();
274		vfsinit();
275		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
276			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
277		return (0);
278	}
279	for (; *argv != NULL; ++argv)
280		parse(*argv, 1);
281	return (0);
282}
283
284/*
285 * List all variables known to the system.
286 */
287void
288listall(char *prefix, struct list *lp)
289{
290	char *cp, name[BUFSIZ];
291	int lvl2, len;
292
293	if (lp->list == NULL)
294		return;
295	if ((len = strlcpy(name, prefix, sizeof(name))) >= sizeof(name))
296		errx(1, "%s: name too long", prefix);
297	cp = name + len++;
298	*cp++ = '.';
299	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
300		if (lp->list[lvl2].ctl_name == NULL)
301			continue;
302		if (strlcpy(cp, lp->list[lvl2].ctl_name,
303		    sizeof(name) - len) >= sizeof(name) - len)
304			warn("%s: name too long", lp->list[lvl2].ctl_name);
305		parse(name, Aflag);
306	}
307}
308
309int
310parse_hex_char(char ch)
311{
312	if (ch >= '0' && ch <= '9')
313		return (ch - '0');
314
315	ch = tolower((unsigned char)ch);
316	if (ch >= 'a' && ch <= 'f')
317		return (ch - 'a' + 10);
318
319	return (-1);
320}
321
322ssize_t
323parse_hex_string(unsigned char *dst, size_t dstlen, const char *src)
324{
325	ssize_t len = 0;
326	int digit;
327
328	while (len < dstlen) {
329		if (*src == '\0')
330			return (len);
331
332		digit = parse_hex_char(*src++);
333		if (digit == -1)
334			return (-1);
335		dst[len] = digit << 4;
336
337		digit = parse_hex_char(*src++);
338		if (digit == -1)
339			return (-1);
340
341		dst[len] |= digit;
342		len++;
343	}
344
345	while (*src != '\0') {
346		if (parse_hex_char(*src++) == -1 ||
347		    parse_hex_char(*src++) == -1)
348			return (-1);
349
350		len++;
351	}
352
353	return (len);
354}
355
356/*
357 * Parse a name into a MIB entry.
358 * Lookup and print out the MIB entry if it exists.
359 * Set a new value if requested.
360 */
361void
362parse(char *string, int flags)
363{
364	int indx, type, state, intval, len;
365	size_t size, newsize = 0;
366	int lal = 0, special = 0;
367	void *newval = NULL;
368	int64_t quadval;
369	struct list *lp;
370	int mib[CTL_MAXNAME];
371	char *cp, *bufp, buf[SYSCTL_BUFSIZ];
372	unsigned char hex[SYSCTL_BUFSIZ];
373
374	(void)strlcpy(buf, string, sizeof(buf));
375	bufp = buf;
376	if ((cp = strchr(string, '=')) != NULL) {
377		*strchr(buf, '=') = '\0';
378		*cp++ = '\0';
379		while (isspace((unsigned char)*cp))
380			cp++;
381		newval = cp;
382		newsize = strlen(cp);
383	}
384	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
385		return;
386	mib[0] = indx;
387	if (indx == CTL_VFS)
388		vfsinit();
389	if (indx == CTL_DEBUG)
390		debuginit();
391	lp = &secondlevel[indx];
392	if (lp->list == 0) {
393		warnx("%s: class is not implemented", topname[indx].ctl_name);
394		return;
395	}
396	if (bufp == NULL) {
397		listall(topname[indx].ctl_name, lp);
398		return;
399	}
400	if ((indx = findname(string, "second", &bufp, lp)) == -1)
401		return;
402	mib[1] = indx;
403	type = lp->list[indx].ctl_type;
404	len = 2;
405	switch (mib[0]) {
406
407	case CTL_KERN:
408		switch (mib[1]) {
409		case KERN_PROF:
410			mib[2] = GPROF_STATE;
411			mib[3] = 0; /* Assume CPU ID 0 is always valid. */
412			size = sizeof(state);
413			if (sysctl(mib, 4, &state, &size, NULL, 0) == -1) {
414				if (flags == 0)
415					return;
416				if (!nflag)
417					(void)printf("%s: ", string);
418				(void)puts("kernel is not compiled for profiling");
419				return;
420			}
421			if (!nflag)
422				(void)printf("%s = %s\n", string,
423				    state == GMON_PROF_OFF ? "off" : "running");
424			return;
425		case KERN_FORKSTAT:
426			sysctl_forkstat(string, &bufp, mib, flags, &type);
427			return;
428		case KERN_TTY:
429			len = sysctl_tty(string, &bufp, mib, flags, &type);
430			if (len < 0)
431				return;
432			break;
433		case KERN_NCHSTATS:
434			sysctl_nchstats(string, &bufp, mib, flags, &type);
435			return;
436		case KERN_MALLOCSTATS:
437			len = sysctl_malloc(string, &bufp, mib, flags, &type);
438			if (len < 0)
439				return;
440			if (mib[2] == KERN_MALLOC_BUCKET)
441				special |= KMEMBUCKETS;
442			if (mib[2] == KERN_MALLOC_KMEMSTATS)
443				special |= KMEMSTATS;
444			newsize = 0;
445			break;
446		case KERN_MBSTAT:
447			if (flags == 0)
448				return;
449			warnx("use netstat to view %s", string);
450			return;
451		case KERN_MSGBUF:
452			if (flags == 0)
453				return;
454			warnx("use dmesg to view %s", string);
455			return;
456		case KERN_PROC:
457			if (flags == 0)
458				return;
459			warnx("use ps to view %s information", string);
460			return;
461		case KERN_CLOCKRATE:
462			special |= CLOCK;
463			break;
464		case KERN_BOOTTIME:
465			special |= BOOTTIME;
466			break;
467		case KERN_HOSTID:
468			special |= UNSIGNED;
469			special |= SMALLBUF;
470			break;
471		case KERN_CPTIME:
472			special |= LONGARRAY;
473			lal = CPUSTATES;
474			break;
475		case KERN_SEMINFO:
476			len = sysctl_seminfo(string, &bufp, mib, flags, &type);
477			if (len < 0)
478				return;
479			break;
480		case KERN_SHMINFO:
481			len = sysctl_shminfo(string, &bufp, mib, flags, &type);
482			if (len < 0)
483				return;
484			break;
485		case KERN_INTRCNT:
486			if (flags == 0)
487				return;
488			warnx("use vmstat or systat to view %s information",
489			    string);
490			return;
491		case KERN_WATCHDOG:
492			len = sysctl_watchdog(string, &bufp, mib, flags,
493			    &type);
494			if (len < 0)
495				return;
496			break;
497		case KERN_TIMECOUNTER:
498			len = sysctl_tc(string, &bufp, mib, flags,
499			    &type);
500			if (len < 0)
501				return;
502			break;
503		case KERN_FILE:
504			if (flags == 0)
505				return;
506			warnx("use fstat to view %s information", string);
507			return;
508		case KERN_CONSDEV:
509			special |= CHRDEV;
510			break;
511		case KERN_NETLIVELOCKS:
512		case KERN_SOMAXCONN:
513		case KERN_SOMINCONN:
514			special |= UNSIGNED;
515			break;
516		case KERN_AUDIO:
517			len = sysctl_audio(string, &bufp, mib, flags, &type);
518			if (len < 0)
519				return;
520			break;
521		case KERN_WITNESS:
522			len = sysctl_witness(string, &bufp, mib, flags, &type);
523			if (len < 0)
524				return;
525			break;
526		case KERN_PFSTATUS:
527			if (flags == 0)
528				return;
529			warnx("use pfctl to view %s information", string);
530			return;
531		case KERN_TIMEOUT_STATS:
532			special |= TIMEOUT;
533			break;
534		}
535		break;
536
537	case CTL_HW:
538		switch (mib[1]) {
539		case HW_DISKSTATS:
540			/*
541			 * Only complain if someone asks explicitly for this,
542			 * otherwise "fail" silently.
543			 */
544			if (flags)
545				warnx("use vmstat to view %s information",
546				    string);
547			return;
548		case HW_SENSORS:
549			special |= SENSORS;
550			len = sysctl_sensors(string, &bufp, mib, flags, &type);
551			if (len < 0)
552				return;
553			break;
554		case HW_PHYSMEM:
555		case HW_USERMEM:
556			/*
557			 * Don't print these; we'll print the 64-bit
558			 * variants instead.
559			 */
560			return;
561		}
562		break;
563
564	case CTL_VM:
565		if (mib[1] == VM_LOADAVG) {
566			double loads[3];
567
568			getloadavg(loads, 3);
569			if (!nflag)
570				(void)printf("%s%s", string, equ);
571			(void)printf("%.2f %.2f %.2f\n", loads[0],
572			    loads[1], loads[2]);
573			return;
574		} else if (mib[1] == VM_PSSTRINGS) {
575			struct _ps_strings _ps;
576
577			size = sizeof(_ps);
578			if (sysctl(mib, 2, &_ps, &size, NULL, 0) == -1) {
579				if (flags == 0)
580					return;
581				if (!nflag)
582					(void)printf("%s: ", string);
583				(void)puts("can't find ps strings");
584				return;
585			}
586			if (!nflag)
587				(void)printf("%s%s", string, equ);
588			(void)printf("%p\n", _ps.val);
589			return;
590		} else if (mib[1] == VM_SWAPENCRYPT) {
591			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
592			if (len < 0)
593				return;
594
595			break;
596		} else if (mib[1] == VM_NKMEMPAGES ||
597		    mib[1] == VM_ANONMIN ||
598		    mib[1] == VM_VTEXTMIN ||
599		    mib[1] == VM_VNODEMIN ||
600		    mib[1] == VM_MALLOC_CONF) {
601			break;
602		}
603		if (flags == 0)
604			return;
605		warnx("use vmstat or systat to view %s information", string);
606		return;
607
608		break;
609
610	case CTL_NET:
611		if (mib[1] == PF_INET) {
612			len = sysctl_inet(string, &bufp, mib, flags, &type);
613			if (len < 0)
614				return;
615
616			if ((mib[2] == IPPROTO_IP && mib[3] == IPCTL_MRTSTATS) ||
617			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_STATS) ||
618			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_MRTMFC) ||
619			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_MRTVIF) ||
620			    (mib[2] == IPPROTO_TCP && mib[3] == TCPCTL_STATS) ||
621			    (mib[2] == IPPROTO_UDP && mib[3] == UDPCTL_STATS) ||
622			    (mib[2] == IPPROTO_ESP && mib[3] == ESPCTL_STATS) ||
623			    (mib[2] == IPPROTO_AH && mib[3] == AHCTL_STATS) ||
624			    (mib[2] == IPPROTO_IGMP && mib[3] == IGMPCTL_STATS) ||
625			    (mib[2] == IPPROTO_ETHERIP && mib[3] == ETHERIPCTL_STATS) ||
626			    (mib[2] == IPPROTO_IPIP && mib[3] == IPIPCTL_STATS) ||
627			    (mib[2] == IPPROTO_IPCOMP && mib[3] == IPCOMPCTL_STATS) ||
628			    (mib[2] == IPPROTO_ICMP && mib[3] == ICMPCTL_STATS) ||
629			    (mib[2] == IPPROTO_CARP && mib[3] == CARPCTL_STATS) ||
630			    (mib[2] == IPPROTO_PFSYNC && mib[3] == PFSYNCCTL_STATS) ||
631			    (mib[2] == IPPROTO_DIVERT && mib[3] == DIVERTCTL_STATS)) {
632				if (flags == 0)
633					return;
634				warnx("use netstat to view %s information",
635				    string);
636				return;
637			} else if ((mib[2] == IPPROTO_TCP &&
638			    (mib[3] == TCPCTL_BADDYNAMIC ||
639			    mib[3] == TCPCTL_ROOTONLY)) ||
640			    (mib[2] == IPPROTO_UDP &&
641			    (mib[3] == UDPCTL_BADDYNAMIC ||
642			    mib[3] == UDPCTL_ROOTONLY))) {
643
644				special |= BADDYNAMIC;
645
646				if (newval != NULL)
647					parse_baddynamic(mib, len, string,
648					    &newval, &newsize, flags, nflag);
649			}
650			break;
651		}
652		if (mib[1] == PF_INET6) {
653			len = sysctl_inet6(string, &bufp, mib, flags, &type);
654			if (len < 0)
655				return;
656
657			if (mib[2] == IPPROTO_IPV6 &&
658			    mib[3] == IPV6CTL_SOIIKEY)
659				special |= HEX;
660
661			if ((mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_MRTMFC) ||
662			    (mib[2] == IPPROTO_IPV6 && mib[3] == IPV6CTL_MRTMIF) ||
663			    (mib[2] == IPPROTO_DIVERT && mib[3] == DIVERT6CTL_STATS)) {
664				if (flags == 0)
665					return;
666				warnx("use netstat to view %s information",
667				    string);
668				return;
669			}
670			break;
671		}
672		if (mib[1] == PF_LINK) {
673			len = sysctl_link(string, &bufp, mib, flags, &type);
674			if (len < 0)
675				return;
676			break;
677		}
678		if (mib[1] == PF_BPF) {
679			len = sysctl_bpf(string, &bufp, mib, flags, &type);
680			if (len < 0)
681				return;
682			break;
683		}
684		if (mib[1] == PF_MPLS) {
685			len = sysctl_mpls(string, &bufp, mib, flags, &type);
686			if (len < 0)
687				return;
688			break;
689		}
690		if (mib[1] == PF_PIPEX) {
691			len = sysctl_pipex(string, &bufp, mib, flags, &type);
692			if (len < 0)
693				return;
694			break;
695		}
696		if (flags == 0)
697			return;
698		warnx("use netstat to view %s information", string);
699		return;
700
701	case CTL_DEBUG:
702		mib[2] = CTL_DEBUG_VALUE;
703		len = 3;
704		break;
705
706	case CTL_MACHDEP:
707#ifdef CPU_CONSDEV
708		if (mib[1] == CPU_CONSDEV)
709			special |= CHRDEV;
710#endif
711#ifdef CPU_CPUID
712		if (mib[1] == CPU_CPUID)
713			special |= HEX;
714#endif
715#ifdef CPU_CPUFEATURE
716		if (mib[1] == CPU_CPUFEATURE)
717			special |= HEX;
718#endif
719#ifdef CPU_BLK2CHR
720		if (mib[1] == CPU_BLK2CHR) {
721			if (bufp == NULL)
722				return;
723			mib[2] = makedev(atoi(bufp),0);
724			bufp = NULL;
725			len = 3;
726			special |= CHRDEV;
727			break;
728		}
729#endif
730#ifdef CPU_CHR2BLK
731		if (mib[1] == CPU_CHR2BLK) {
732			if (bufp == NULL)
733				return;
734			mib[2] = makedev(atoi(bufp),0);
735			bufp = NULL;
736			len = 3;
737			special |= BLKDEV;
738			break;
739		}
740#endif
741#ifdef CPU_BIOS
742		if (mib[1] == CPU_BIOS) {
743			len = sysctl_bios(string, &bufp, mib, flags, &type);
744			if (len < 0)
745				return;
746			if (mib[2] == BIOS_DEV)
747				special |= BIOSDEV;
748			if (mib[2] == BIOS_DISKINFO)
749				special |= BIOSGEO;
750			break;
751		}
752#endif
753#ifdef CPU_CHIPSET
754		if (mib[1] == CPU_CHIPSET) {
755			len = sysctl_chipset(string, &bufp, mib, flags, &type);
756			if (len < 0)
757				return;
758			break;
759		}
760#endif
761		break;
762
763	case CTL_FS:
764		len = sysctl_fs(string, &bufp, mib, flags, &type);
765		if (len >= 0)
766			break;
767		return;
768
769	case CTL_VFS:
770		if (mib[1])
771			len = sysctl_vfs(string, &bufp, mib, flags, &type);
772		else
773			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
774		if (len >= 0) {
775			if (type == CTLTYPE_STRUCT) {
776				if (flags)
777					warnx("use nfsstat to view %s information",
778					    MOUNT_NFS);
779				return;
780			} else
781				break;
782		}
783		return;
784
785	case CTL_DDB:
786		break;
787
788	default:
789		warnx("illegal top level value: %d", mib[0]);
790		return;
791
792	}
793	if (bufp) {
794		warnx("name %s in %s is unknown", bufp, string);
795		return;
796	}
797	if (newsize > 0) {
798		const char *errstr;
799
800		switch (type) {
801		case CTLTYPE_INT:
802			if (special & UNSIGNED)
803				intval = strtonum(newval, 0, UINT_MAX, &errstr);
804			else
805				intval = strtonum(newval, INT_MIN, INT_MAX,
806				    &errstr);
807			if (errstr != NULL) {
808				warnx("%s: value is %s: %s", string, errstr,
809				    (char *)newval);
810				return;
811			}
812			newval = &intval;
813			newsize = sizeof(intval);
814			break;
815
816		case CTLTYPE_QUAD:
817			(void)sscanf(newval, "%lld", &quadval);
818			newval = &quadval;
819			newsize = sizeof(quadval);
820			break;
821		case CTLTYPE_STRING:
822			if (special & HEX) {
823				ssize_t len;
824
825				len = parse_hex_string(hex, sizeof(hex),
826				    newval);
827				if (len == -1) {
828					warnx("%s: hex string %s: invalid",
829					    string, newval);
830					return;
831				}
832				if (len > sizeof(hex)) {
833					warnx("%s: hex string %s: too long",
834					    string, newval);
835					return;
836				}
837
838				newval = hex;
839				newsize = len;
840			}
841			break;
842		}
843	}
844	size = (special & SMALLBUF) ? 512 : SYSCTL_BUFSIZ;
845	if (sysctl(mib, len, buf, &size, newval, newsize) == -1) {
846		if (flags == 0)
847			return;
848		switch (errno) {
849		case EOPNOTSUPP:
850			warnx("%s: value is not available", string);
851			return;
852		case ENOTDIR:
853			warnx("%s: specification is incomplete", string);
854			return;
855		case ENOMEM:
856			warnx("%s: type is unknown to this program", string);
857			return;
858		case ENXIO:
859			if (special & BIOSGEO)
860				return;
861		default:
862			warn("%s", string);
863			return;
864		}
865	}
866	if (special & KMEMBUCKETS) {
867		struct kmembuckets *kb = (struct kmembuckets *)buf;
868		if (!nflag)
869			(void)printf("%s%s", string, equ);
870		printf("(");
871		printf("calls = %llu ", (long long)kb->kb_calls);
872		printf("total_allocated = %llu ", (long long)kb->kb_total);
873		printf("total_free = %lld ", (long long)kb->kb_totalfree);
874		printf("elements = %lld ", (long long)kb->kb_elmpercl);
875		printf("high watermark = %lld ", (long long)kb->kb_highwat);
876		printf("could_free = %lld", (long long)kb->kb_couldfree);
877		printf(")\n");
878		return;
879	}
880	if (special & KMEMSTATS) {
881		struct kmemstats *km = (struct kmemstats *)buf;
882		int j, first = 1;
883
884		if (!nflag)
885			(void)printf("%s%s", string, equ);
886		(void)printf("(inuse = %ld, calls = %ld, memuse = %ldK, "
887		    "limblocks = %d, mapblocks = %d, maxused = %ldK, "
888		    "limit = %ldK, spare = %ld, sizes = (",
889		    km->ks_inuse, km->ks_calls,
890		    (km->ks_memuse + 1023) / 1024, km->ks_limblocks,
891		    km->ks_mapblocks, (km->ks_maxused + 1023) / 1024,
892		    (km->ks_limit + 1023) / 1024, km->ks_spare);
893		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
894			if ((km->ks_size & j ) == 0)
895				continue;
896			if (first)
897				(void)printf("%d", j);
898			else
899				(void)printf(",%d", j);
900			first = 0;
901		}
902		if (first)
903			(void)printf("none");
904		(void)printf("))\n");
905		return;
906	}
907	if (special & CLOCK) {
908		struct clockinfo *clkp = (struct clockinfo *)buf;
909
910		if (!nflag)
911			(void)printf("%s%s", string, equ);
912		(void)printf(
913		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
914		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
915		return;
916	}
917	if (special & BOOTTIME) {
918		struct timeval *btp = (struct timeval *)buf;
919
920		if (!nflag) {
921			boottime = btp->tv_sec;
922			(void)printf("%s%s%s", string, equ, ctime(&boottime));
923		} else
924			(void)printf("%lld\n", (long long)btp->tv_sec);
925		return;
926	}
927	if (special & BLKDEV) {
928		dev_t dev = *(dev_t *)buf;
929
930		if (!nflag)
931			(void)printf("%s%s%s\n", string, equ,
932			    devname(dev, S_IFBLK));
933		else
934			(void)printf("0x%x\n", dev);
935		return;
936	}
937	if (special & CHRDEV) {
938		dev_t dev = *(dev_t *)buf;
939
940		if (!nflag)
941			(void)printf("%s%s%s\n", string, equ,
942			    devname(dev, S_IFCHR));
943		else
944			(void)printf("0x%x\n", dev);
945		return;
946	}
947#ifdef CPU_BIOS
948	if (special & BIOSGEO) {
949		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
950
951		if (!nflag)
952			(void)printf("%s%s", string, equ);
953		(void)printf("bootdev = 0x%x, "
954		    "cylinders = %u, heads = %u, sectors = %u\n",
955		    pdi->bsd_dev, pdi->bios_cylinders,
956		    pdi->bios_heads, pdi->bios_sectors);
957		return;
958	}
959	if (special & BIOSDEV) {
960		int dev = *(int*)buf;
961
962		if (!nflag)
963			(void)printf("%s%s", string, equ);
964		(void) printf("0x%02x\n", dev);
965		return;
966	}
967#endif
968	if (special & UNSIGNED) {
969		if (newsize == 0) {
970			if (!nflag)
971				(void)printf("%s%s", string, equ);
972			(void)printf("%u\n", *(u_int *)buf);
973		} else {
974			if (!qflag) {
975				if (!nflag)
976					(void)printf("%s: %u -> ", string,
977					    *(u_int *)buf);
978				(void)printf("%u\n", *(u_int *)newval);
979			}
980		}
981		return;
982	}
983	if (special & BADDYNAMIC) {
984		u_int port, lastport;
985		u_int32_t *baddynamic = (u_int32_t *)buf;
986
987		if (!qflag) {
988			if (!nflag)
989				(void)printf("%s%s", string,
990				    newsize ? ": " : equ);
991			lastport = 0;
992			for (port = 0; port < 65536; port++)
993				if (DP_ISSET(baddynamic, port)) {
994					(void)printf("%s%u",
995					    lastport ? "," : "", port);
996					lastport = port;
997				}
998			if (newsize != 0) {
999				if (!nflag)
1000					fputs(" -> ", stdout);
1001				baddynamic = (u_int32_t *)newval;
1002				lastport = 0;
1003				for (port = 0; port < 65536; port++)
1004					if (DP_ISSET(baddynamic, port)) {
1005						(void)printf("%s%u",
1006						    lastport ? "," : "", port);
1007						lastport = port;
1008					}
1009			}
1010			(void)putchar('\n');
1011		}
1012		return;
1013	}
1014	if (special & LONGARRAY) {
1015		long *la = (long *)buf;
1016		if (!nflag)
1017			printf("%s%s", string, equ);
1018		while (lal--)
1019			printf("%ld%s", *la++, lal? ",":"");
1020		putchar('\n');
1021		return;
1022	}
1023	if (special & SENSORS) {
1024		struct sensor *s = (struct sensor *)buf;
1025
1026		if (size > 0 && (s->flags & SENSOR_FINVALID) == 0) {
1027			if (!nflag)
1028				printf("%s%s", string, equ);
1029			print_sensor(s);
1030			printf("\n");
1031		}
1032		return;
1033	}
1034	if (special & TIMEOUT) {
1035		struct timeoutstat *tstat = (struct timeoutstat *)buf;
1036
1037		if (!nflag)
1038			printf("%s%s", string, equ);
1039		printf("added = %llu, cancelled = %llu, deleted = %llu, "
1040		    "late = %llu, pending = %llu, readded = %llu, "
1041		    "rescheduled = %llu, run_softclock = %llu, "
1042		    "run_thread = %llu, softclocks = %llu, "
1043		    "thread_wakeups = %llu\n",
1044		    tstat->tos_added, tstat->tos_cancelled, tstat->tos_deleted,
1045		    tstat->tos_late, tstat->tos_pending, tstat->tos_readded,
1046		    tstat->tos_rescheduled, tstat->tos_run_softclock,
1047		    tstat->tos_run_thread, tstat->tos_softclocks,
1048		    tstat->tos_thread_wakeups);
1049		return;
1050	}
1051	switch (type) {
1052	case CTLTYPE_INT:
1053		if (newsize == 0) {
1054			if (!nflag)
1055				(void)printf("%s%s", string, equ);
1056			if (special & HEX)
1057				(void)printf("0x%x\n", *(int *)buf);
1058			else
1059				(void)printf("%d\n", *(int *)buf);
1060		} else {
1061			if (!qflag) {
1062				if (!nflag)
1063					(void)printf("%s: %d -> ", string,
1064					    *(int *)buf);
1065				if (special & HEX)
1066					(void)printf("0x%x\n", *(int *)newval);
1067				else
1068					(void)printf("%d\n", *(int *)newval);
1069			}
1070		}
1071		return;
1072
1073	case CTLTYPE_STRING:
1074		if (newval == NULL) {
1075			if (!nflag)
1076				(void)printf("%s%s", string, equ);
1077			if (special & HEX) {
1078				size_t i;
1079				for (i = 0; i < size; i++) {
1080					(void)printf("%02x",
1081					    (unsigned char)buf[i]);
1082				}
1083				(void)printf("\n");
1084			} else
1085				(void)puts(buf);
1086		} else if (!qflag) {
1087			if (!nflag) {
1088				(void)printf("%s: ", string);
1089				if (special & HEX) {
1090					size_t i;
1091					for (i = 0; i < size; i++) {
1092						(void)printf("%02x",
1093						    (unsigned char)buf[i]);
1094					}
1095				} else
1096					(void)printf("%s", buf);
1097
1098				(void)printf(" -> ");
1099			}
1100			(void)puts(cp);
1101		}
1102		return;
1103
1104	case CTLTYPE_QUAD:
1105		if (newsize == 0) {
1106			int64_t tmp;
1107
1108			memcpy(&tmp, buf, sizeof tmp);
1109			if (!nflag)
1110				(void)printf("%s%s", string, equ);
1111			(void)printf("%lld\n", tmp);
1112		} else {
1113			int64_t tmp;
1114
1115			memcpy(&tmp, buf, sizeof tmp);
1116			if (!qflag) {
1117				if (!nflag)
1118					(void)printf("%s: %lld -> ",
1119					    string, tmp);
1120				memcpy(&tmp, newval, sizeof tmp);
1121				(void)printf("%lld\n", tmp);
1122			}
1123		}
1124		return;
1125
1126	case CTLTYPE_STRUCT:
1127		warnx("%s: unknown structure returned", string);
1128		return;
1129
1130	default:
1131	case CTLTYPE_NODE:
1132		warnx("%s: unknown type returned", string);
1133		return;
1134	}
1135}
1136
1137static void
1138parse_ports(char *portspec, int *port, int *high_port)
1139{
1140	char *dash;
1141	const char *errstr;
1142
1143	if ((dash = strchr(portspec, '-')) != NULL)
1144		*dash++ = '\0';
1145	*port = strtonum(portspec, 0, 65535, &errstr);
1146	if (errstr != NULL)
1147		errx(1, "port is %s: %s", errstr, portspec);
1148	if (dash != NULL) {
1149		*high_port = strtonum(dash, 0, 65535, &errstr);
1150		if (errstr != NULL)
1151			errx(1, "high port is %s: %s", errstr, dash);
1152		if (*high_port < *port)
1153			errx(1, "high port %d is lower than %d",
1154			    *high_port, *port);
1155	} else
1156		*high_port = *port;
1157}
1158
1159void
1160parse_baddynamic(int mib[], size_t len, char *string, void **newvalp,
1161    size_t *newsizep, int flags, int nflag)
1162{
1163	static u_int32_t newbaddynamic[DP_MAPSIZE];
1164	int port, high_port, baddynamic_loaded = 0, full_list_set = 0;
1165	size_t size;
1166	char action, *cp;
1167
1168	while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1169		if (*cp == '+' || *cp == '-') {
1170			if (full_list_set)
1171				errx(1, "cannot mix +/- with full list");
1172			action = *cp++;
1173			if (!baddynamic_loaded) {
1174				size = sizeof(newbaddynamic);
1175				if (sysctl(mib, len, newbaddynamic,
1176				    &size, 0, 0) == -1) {
1177					if (flags == 0)
1178						return;
1179					if (!nflag)
1180						printf("%s: ", string);
1181					puts("kernel does not contain bad "
1182					    "dynamic port tables");
1183					return;
1184				}
1185				baddynamic_loaded = 1;
1186			}
1187			parse_ports(cp, &port, &high_port);
1188			for (; port <= high_port; port++) {
1189				if (action == '+')
1190					DP_SET(newbaddynamic, port);
1191				else
1192					DP_CLR(newbaddynamic, port);
1193			}
1194		} else {
1195			if (baddynamic_loaded)
1196				errx(1, "cannot mix +/- with full list");
1197			if (!full_list_set) {
1198				bzero(newbaddynamic, sizeof(newbaddynamic));
1199				full_list_set = 1;
1200			}
1201			parse_ports(cp, &port, &high_port);
1202			for (; port <= high_port; port++)
1203				DP_SET(newbaddynamic, port);
1204		}
1205	}
1206	*newvalp = (void *)newbaddynamic;
1207	*newsizep = sizeof(newbaddynamic);
1208}
1209
1210/*
1211 * Initialize the set of debugging names
1212 */
1213void
1214debuginit(void)
1215{
1216	int mib[3], loc, i;
1217	size_t size;
1218
1219	if (secondlevel[CTL_DEBUG].list != 0)
1220		return;
1221	secondlevel[CTL_DEBUG].list = debugname;
1222	mib[0] = CTL_DEBUG;
1223	mib[2] = CTL_DEBUG_NAME;
1224	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
1225		mib[1] = i;
1226		size = BUFSIZ - loc;
1227		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
1228			continue;
1229		debugname[i].ctl_name = &names[loc];
1230		debugname[i].ctl_type = CTLTYPE_INT;
1231		loc += size;
1232	}
1233	lastused = loc;
1234}
1235
1236struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
1237struct ctlname ffsname[] = FFS_NAMES;
1238struct ctlname nfsname[] = FS_NFS_NAMES;
1239struct ctlname fusefsname[] = FUSEFS_NAMES;
1240struct list *vfsvars;
1241int *vfs_typenums;
1242
1243/*
1244 * Initialize the set of filesystem names
1245 */
1246void
1247vfsinit(void)
1248{
1249	int mib[4], maxtypenum, cnt, loc, size;
1250	struct vfsconf vfc;
1251	size_t buflen;
1252
1253	if (secondlevel[CTL_VFS].list != 0)
1254		return;
1255	mib[0] = CTL_VFS;
1256	mib[1] = VFS_GENERIC;
1257	mib[2] = VFS_MAXTYPENUM;
1258	buflen = 4;
1259	if (sysctl(mib, 3, &maxtypenum, &buflen, NULL, 0) == -1)
1260		return;
1261	/*
1262         * We need to do 0..maxtypenum so add one, and then we offset them
1263	 * all by (another) one by inserting VFS_GENERIC entries at zero
1264	 */
1265	maxtypenum += 2;
1266	if ((vfs_typenums = calloc(maxtypenum, sizeof(int))) == NULL)
1267		return;
1268	if ((vfsvars = calloc(maxtypenum, sizeof(*vfsvars))) == NULL) {
1269		free(vfs_typenums);
1270		return;
1271	}
1272	if ((vfsname = calloc(maxtypenum, sizeof(*vfsname))) == NULL) {
1273		free(vfs_typenums);
1274		free(vfsvars);
1275		return;
1276	}
1277	mib[2] = VFS_CONF;
1278	buflen = sizeof vfc;
1279	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
1280		mib[3] = cnt - 1;
1281		if (sysctl(mib, 4, &vfc, &buflen, NULL, 0) == -1) {
1282			if (errno == EOPNOTSUPP)
1283				continue;
1284			warn("vfsinit");
1285			free(vfsname);
1286			free(vfsvars);
1287			free(vfs_typenums);
1288			return;
1289		}
1290		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1291			vfsvars[cnt].list = ffsname;
1292			vfsvars[cnt].size = FFS_MAXID;
1293		}
1294		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1295			vfsvars[cnt].list = nfsname;
1296			vfsvars[cnt].size = NFS_MAXID;
1297		}
1298		if (!strcmp(vfc.vfc_name, MOUNT_FUSEFS)) {
1299			vfsvars[cnt].list = fusefsname;
1300			vfsvars[cnt].size = FUSEFS_MAXID;
1301		}
1302		vfs_typenums[cnt] = vfc.vfc_typenum;
1303		strlcat(&names[loc], vfc.vfc_name, sizeof names - loc);
1304		vfsname[cnt].ctl_name = &names[loc];
1305		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1306		size = strlen(vfc.vfc_name) + 1;
1307		loc += size;
1308	}
1309	lastused = loc;
1310
1311	vfsname[0].ctl_name = "mounts";
1312	vfsname[0].ctl_type = CTLTYPE_NODE;
1313	vfsvars[0].list = vfsname + 1;
1314	vfsvars[0].size = maxtypenum - 1;
1315
1316	secondlevel[CTL_VFS].list = vfsname;
1317	secondlevel[CTL_VFS].size = maxtypenum;
1318	return;
1319}
1320
1321int
1322sysctl_vfsgen(char *string, char **bufpp, int mib[], int flags, int *typep)
1323{
1324	int indx;
1325	size_t size;
1326	struct vfsconf vfc;
1327
1328	if (*bufpp == NULL) {
1329		listall(string, vfsvars);
1330		return (-1);
1331	}
1332
1333	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1334		return (-1);
1335
1336	mib[1] = VFS_GENERIC;
1337	mib[2] = VFS_CONF;
1338	mib[3] = indx;
1339	size = sizeof vfc;
1340	if (sysctl(mib, 4, &vfc, &size, NULL, 0) == -1) {
1341		if (errno != EOPNOTSUPP)
1342			warn("vfs print");
1343		return -1;
1344	}
1345	if (flags == 0 && vfc.vfc_refcount == 0)
1346		return -1;
1347	if (!nflag)
1348		fprintf(stdout, "%s has %u mounted instance%s\n",
1349		    string, vfc.vfc_refcount,
1350		    vfc.vfc_refcount != 1 ? "s" : "");
1351	else
1352		fprintf(stdout, "%u\n", vfc.vfc_refcount);
1353
1354	return -1;
1355}
1356
1357int
1358sysctl_vfs(char *string, char **bufpp, int mib[], int flags, int *typep)
1359{
1360	struct list *lp = &vfsvars[mib[1]];
1361	int indx;
1362
1363	if (lp->list == NULL) {
1364		if (flags)
1365			warnx("No variables defined for file system %s", string);
1366		return (-1);
1367	}
1368	if (*bufpp == NULL) {
1369		listall(string, lp);
1370		return (-1);
1371	}
1372	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1373		return (-1);
1374
1375	mib[1] = vfs_typenums[mib[1]];
1376	mib[2] = indx;
1377	*typep = lp->list[indx].ctl_type;
1378	return (3);
1379}
1380
1381struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1382struct list fslist = { posixname, FS_POSIX_MAXID };
1383
1384/*
1385 * handle file system requests
1386 */
1387int
1388sysctl_fs(char *string, char **bufpp, int mib[], int flags, int *typep)
1389{
1390	int indx;
1391
1392	if (*bufpp == NULL) {
1393		listall(string, &fslist);
1394		return (-1);
1395	}
1396	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1397		return (-1);
1398	mib[2] = indx;
1399	*typep = fslist.list[indx].ctl_type;
1400	return (3);
1401}
1402
1403#ifdef CPU_BIOS
1404struct ctlname biosname[] = CTL_BIOS_NAMES;
1405struct list bioslist = { biosname, BIOS_MAXID };
1406
1407/*
1408 * handle BIOS requests
1409 */
1410int
1411sysctl_bios(char *string, char **bufpp, int mib[], int flags, int *typep)
1412{
1413	char *name;
1414	int indx;
1415
1416	if (*bufpp == NULL) {
1417		listall(string, &bioslist);
1418		return (-1);
1419	}
1420	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1421		return (-1);
1422	mib[2] = indx;
1423	if (indx == BIOS_DISKINFO) {
1424		const char *errstr;
1425
1426		if (*bufpp == NULL) {
1427			char name[BUFSIZ];
1428
1429			/* scan all the bios devices */
1430			for (indx = 0; indx < 256; indx++) {
1431				snprintf(name, sizeof(name), "%s.%u",
1432				    string, indx);
1433				parse(name, 1);
1434			}
1435			return (-1);
1436		}
1437		if ((name = strsep(bufpp, ".")) == NULL) {
1438			warnx("%s: incomplete specification", string);
1439			return (-1);
1440		}
1441		mib[3] = strtonum(name, 0, INT_MAX, &errstr);
1442		if (errstr) {
1443			warnx("%s: %s", string, errstr);
1444			return (-1);
1445		}
1446		*typep = CTLTYPE_STRUCT;
1447		return (4);
1448	} else {
1449		*typep = bioslist.list[indx].ctl_type;
1450		return (3);
1451	}
1452}
1453#endif
1454
1455struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1456struct list swpenclist = { swpencname, SWPENC_MAXID };
1457
1458/*
1459 * handle swap encrypt requests
1460 */
1461int
1462sysctl_swpenc(char *string, char **bufpp, int mib[], int flags, int *typep)
1463{
1464	int indx;
1465
1466	if (*bufpp == NULL) {
1467		listall(string, &swpenclist);
1468		return (-1);
1469	}
1470	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1471		return (-1);
1472	mib[2] = indx;
1473	*typep = swpenclist.list[indx].ctl_type;
1474	return (3);
1475}
1476
1477struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1478struct ctlname ipname[] = IPCTL_NAMES;
1479struct ctlname icmpname[] = ICMPCTL_NAMES;
1480struct ctlname igmpname[] = IGMPCTL_NAMES;
1481struct ctlname ipipname[] = IPIPCTL_NAMES;
1482struct ctlname tcpname[] = TCPCTL_NAMES;
1483struct ctlname udpname[] = UDPCTL_NAMES;
1484struct ctlname espname[] = ESPCTL_NAMES;
1485struct ctlname ahname[] = AHCTL_NAMES;
1486struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1487struct ctlname grename[] = GRECTL_NAMES;
1488struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1489struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1490struct ctlname carpname[] = CARPCTL_NAMES;
1491struct ctlname pfsyncname[] = PFSYNCCTL_NAMES;
1492struct ctlname divertname[] = DIVERTCTL_NAMES;
1493struct ctlname bpfname[] = CTL_NET_BPF_NAMES;
1494struct ctlname ifqname[] = CTL_IFQ_NAMES;
1495struct ctlname pipexname[] = PIPEXCTL_NAMES;
1496struct list inetlist = { inetname, IPPROTO_MAXID };
1497struct list inetvars[] = {
1498	{ ipname, IPCTL_MAXID },	/* ip */
1499	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1500	{ igmpname, IGMPCTL_MAXID },	/* igmp */
1501	{ 0, 0 },			/* ggmp */
1502	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1503	{ 0, 0 },
1504	{ tcpname, TCPCTL_MAXID },	/* tcp */
1505	{ 0, 0 },
1506	{ 0, 0 },			/* egp */
1507	{ 0, 0 },
1508	{ 0, 0 },
1509	{ 0, 0 },
1510	{ 0, 0 },			/* pup */
1511	{ 0, 0 },
1512	{ 0, 0 },
1513	{ 0, 0 },
1514	{ 0, 0 },
1515	{ udpname, UDPCTL_MAXID },	/* udp */
1516	{ 0, 0 },
1517	{ 0, 0 },
1518	{ 0, 0 },
1519	{ 0, 0 },
1520	{ 0, 0 },
1521	{ 0, 0 },
1522	{ 0, 0 },
1523	{ 0, 0 },
1524	{ 0, 0 },
1525	{ 0, 0 },
1526	{ 0, 0 },
1527	{ 0, 0 },
1528	{ 0, 0 },
1529	{ 0, 0 },
1530	{ 0, 0 },
1531	{ 0, 0 },
1532	{ 0, 0 },
1533	{ 0, 0 },
1534	{ 0, 0 },
1535	{ 0, 0 },
1536	{ 0, 0 },
1537	{ 0, 0 },
1538	{ 0, 0 },
1539	{ 0, 0 },
1540	{ 0, 0 },
1541	{ 0, 0 },
1542	{ 0, 0 },
1543	{ 0, 0 },
1544	{ 0, 0 },
1545	{ grename, GRECTL_MAXID },	/* gre */
1546	{ 0, 0 },
1547	{ 0, 0 },
1548	{ espname, ESPCTL_MAXID },	/* esp */
1549	{ ahname, AHCTL_MAXID },	/* ah */
1550	{ 0, 0 },
1551	{ 0, 0 },
1552	{ 0, 0 },
1553	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1554	{ 0, 0 },
1555	{ 0, 0 },
1556	{ 0, 0 },
1557	{ 0, 0 },
1558	{ 0, 0 },
1559	{ 0, 0 },
1560	{ 0, 0 },
1561	{ 0, 0 },
1562	{ 0, 0 },
1563	{ 0, 0 },
1564	{ 0, 0 },
1565	{ 0, 0 },
1566	{ 0, 0 },
1567	{ 0, 0 },
1568	{ 0, 0 },
1569	{ 0, 0 },
1570	{ 0, 0 },
1571	{ 0, 0 },
1572	{ 0, 0 },
1573	{ 0, 0 },
1574	{ 0, 0 },
1575	{ 0, 0 },
1576	{ 0, 0 },
1577	{ 0, 0 },
1578	{ 0, 0 },
1579	{ 0, 0 },
1580	{ 0, 0 },
1581	{ 0, 0 },
1582	{ 0, 0 },
1583	{ 0, 0 },
1584	{ 0, 0 },
1585	{ 0, 0 },
1586	{ 0, 0 },
1587	{ 0, 0 },
1588	{ 0, 0 },
1589	{ 0, 0 },
1590	{ 0, 0 },
1591	{ 0, 0 },
1592	{ 0, 0 },
1593	{ 0, 0 },
1594	{ 0, 0 },
1595	{ etheripname, ETHERIPCTL_MAXID },
1596	{ 0, 0 },
1597	{ 0, 0 },
1598	{ 0, 0 },
1599	{ 0, 0 },
1600	{ 0, 0 },
1601	{ 0, 0 },
1602	{ 0, 0 },
1603	{ 0, 0 },
1604	{ 0, 0 },
1605	{ 0, 0 },
1606	{ ipcompname, IPCOMPCTL_MAXID },
1607	{ 0, 0 },
1608	{ 0, 0 },
1609	{ 0, 0 },
1610	{ carpname, CARPCTL_MAXID },
1611	{ 0, 0 },
1612	{ 0, 0 },
1613	{ 0, 0 },
1614	{ 0, 0 },
1615	{ 0, 0 },
1616	{ 0, 0 },
1617	{ 0, 0 },
1618	{ 0, 0 },
1619	{ 0, 0 },
1620	{ 0, 0 },
1621	{ 0, 0 },
1622	{ 0, 0 },
1623	{ 0, 0 },
1624	{ 0, 0 },
1625	{ 0, 0 },
1626	{ 0, 0 },
1627	{ 0, 0 },
1628	{ 0, 0 },
1629	{ 0, 0 },
1630	{ 0, 0 },
1631	{ 0, 0 },
1632	{ 0, 0 },
1633	{ 0, 0 },
1634	{ 0, 0 },
1635	{ 0, 0 },
1636	{ 0, 0 },
1637	{ 0, 0 },
1638	{ 0, 0 },
1639	{ 0, 0 },
1640	{ 0, 0 },
1641	{ 0, 0 },
1642	{ 0, 0 },
1643	{ 0, 0 },
1644	{ 0, 0 },
1645	{ 0, 0 },
1646	{ 0, 0 },
1647	{ 0, 0 },
1648	{ 0, 0 },
1649	{ 0, 0 },
1650	{ 0, 0 },
1651	{ 0, 0 },
1652	{ 0, 0 },
1653	{ 0, 0 },
1654	{ 0, 0 },
1655	{ 0, 0 },
1656	{ 0, 0 },
1657	{ 0, 0 },
1658	{ 0, 0 },
1659	{ 0, 0 },
1660	{ 0, 0 },
1661	{ 0, 0 },
1662	{ 0, 0 },
1663	{ 0, 0 },
1664	{ 0, 0 },
1665	{ 0, 0 },
1666	{ 0, 0 },
1667	{ 0, 0 },
1668	{ 0, 0 },
1669	{ 0, 0 },
1670	{ 0, 0 },
1671	{ 0, 0 },
1672	{ 0, 0 },
1673	{ 0, 0 },
1674	{ 0, 0 },
1675	{ 0, 0 },
1676	{ 0, 0 },
1677	{ 0, 0 },
1678	{ 0, 0 },
1679	{ 0, 0 },
1680	{ 0, 0 },
1681	{ 0, 0 },
1682	{ 0, 0 },
1683	{ 0, 0 },
1684	{ 0, 0 },
1685	{ 0, 0 },
1686	{ 0, 0 },
1687	{ 0, 0 },
1688	{ 0, 0 },
1689	{ 0, 0 },
1690	{ 0, 0 },
1691	{ 0, 0 },
1692	{ 0, 0 },
1693	{ 0, 0 },
1694	{ 0, 0 },
1695	{ 0, 0 },
1696	{ 0, 0 },
1697	{ 0, 0 },
1698	{ 0, 0 },
1699	{ 0, 0 },
1700	{ 0, 0 },
1701	{ 0, 0 },
1702	{ 0, 0 },
1703	{ 0, 0 },
1704	{ 0, 0 },
1705	{ 0, 0 },
1706	{ 0, 0 },
1707	{ 0, 0 },
1708	{ 0, 0 },
1709	{ 0, 0 },
1710	{ 0, 0 },
1711	{ 0, 0 },
1712	{ 0, 0 },
1713	{ 0, 0 },
1714	{ 0, 0 },
1715	{ 0, 0 },
1716	{ 0, 0 },
1717	{ 0, 0 },
1718	{ 0, 0 },
1719	{ 0, 0 },
1720	{ 0, 0 },
1721	{ 0, 0 },
1722	{ 0, 0 },
1723	{ 0, 0 },
1724	{ 0, 0 },
1725	{ 0, 0 },
1726	{ 0, 0 },
1727	{ 0, 0 },
1728	{ 0, 0 },
1729	{ 0, 0 },
1730	{ 0, 0 },
1731	{ 0, 0 },
1732	{ 0, 0 },
1733	{ 0, 0 },
1734	{ 0, 0 },
1735	{ 0, 0 },
1736	{ 0, 0 },
1737	{ 0, 0 },
1738	{ 0, 0 },
1739	{ 0, 0 },
1740	{ 0, 0 },
1741	{ 0, 0 },
1742	{ 0, 0 },
1743	{ 0, 0 },
1744	{ 0, 0 },
1745	{ 0, 0 },
1746	{ 0, 0 },
1747	{ pfsyncname, PFSYNCCTL_MAXID },
1748	{ 0, 0 },
1749	{ 0, 0 },
1750	{ 0, 0 },
1751	{ 0, 0 },
1752	{ 0, 0 },
1753	{ 0, 0 },
1754	{ 0, 0 },
1755	{ 0, 0 },
1756	{ divertname, DIVERTCTL_MAXID },
1757};
1758struct list bpflist = { bpfname, NET_BPF_MAXID };
1759struct list ifqlist = { ifqname, IFQCTL_MAXID };
1760struct list pipexlist = { pipexname, PIPEXCTL_MAXID };
1761
1762struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1763struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1764struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1765struct list ttylist = { ttysname, KERN_TTY_MAXID };
1766struct list semlist = { semname, KERN_SEMINFO_MAXID };
1767struct list shmlist = { shmname, KERN_SHMINFO_MAXID };
1768struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
1769struct list tclist = { tcname, KERN_TIMECOUNTER_MAXID };
1770struct list audiolist = { audioname, KERN_AUDIO_MAXID };
1771struct list witnesslist = { witnessname, KERN_WITNESS_MAXID };
1772
1773/*
1774 * handle vfs namei cache statistics
1775 */
1776int
1777sysctl_nchstats(char *string, char **bufpp, int mib[], int flags, int *typep)
1778{
1779	static struct nchstats nch;
1780	int indx;
1781	size_t size;
1782	static int keepvalue = 0;
1783
1784	if (*bufpp == NULL) {
1785		bzero(&nch, sizeof(struct nchstats));
1786		listall(string, &nchstatslist);
1787		return (-1);
1788	}
1789	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1790		return (-1);
1791	mib[2] = indx;
1792	if (*bufpp != NULL) {
1793		warnx("fourth level name in %s is invalid", string);
1794		return (-1);
1795	}
1796	if (keepvalue == 0) {
1797		size = sizeof(struct nchstats);
1798		if (sysctl(mib, 2, &nch, &size, NULL, 0) == -1)
1799			return (-1);
1800		keepvalue = 1;
1801	}
1802	if (!nflag)
1803		(void)printf("%s%s", string, equ);
1804	switch (indx) {
1805	case KERN_NCHSTATS_GOODHITS:
1806		(void)printf("%llu\n", nch.ncs_goodhits);
1807		break;
1808	case KERN_NCHSTATS_NEGHITS:
1809		(void)printf("%llu\n", nch.ncs_neghits);
1810		break;
1811	case KERN_NCHSTATS_BADHITS:
1812		(void)printf("%llu\n", nch.ncs_badhits);
1813		break;
1814	case KERN_NCHSTATS_FALSEHITS:
1815		(void)printf("%llu\n", nch.ncs_falsehits);
1816		break;
1817	case KERN_NCHSTATS_MISS:
1818		(void)printf("%llu\n", nch.ncs_miss);
1819		break;
1820	case KERN_NCHSTATS_LONG:
1821		(void)printf("%llu\n", nch.ncs_long);
1822		break;
1823	case KERN_NCHSTATS_PASS2:
1824		(void)printf("%llu\n", nch.ncs_pass2);
1825		break;
1826	case KERN_NCHSTATS_2PASSES:
1827		(void)printf("%llu\n", nch.ncs_2passes);
1828		break;
1829	case KERN_NCHSTATS_REVHITS:
1830		(void)printf("%llu\n", nch.ncs_revhits);
1831		break;
1832	case KERN_NCHSTATS_REVMISS:
1833		(void)printf("%llu\n", nch.ncs_revmiss);
1834		break;
1835	case KERN_NCHSTATS_DOTHITS:
1836		(void)printf("%llu\n", nch.ncs_dothits);
1837		break;
1838	case KERN_NCHSTATS_DOTDOTHITS:
1839		(void)printf("%llu\n", nch.ncs_dotdothits);
1840		break;
1841	}
1842	return (-1);
1843}
1844
1845/*
1846 * handle tty statistics
1847 */
1848int
1849sysctl_tty(char *string, char **bufpp, int mib[], int flags, int *typep)
1850{
1851	int indx;
1852
1853	if (*bufpp == NULL) {
1854		listall(string, &ttylist);
1855		return (-1);
1856	}
1857	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1858		return (-1);
1859	mib[2] = indx;
1860
1861	if ((*typep = ttylist.list[indx].ctl_type) == CTLTYPE_STRUCT) {
1862		if (flags)
1863			warnx("use pstat -t to view %s information",
1864			    string);
1865		return (-1);
1866	}
1867	return (3);
1868}
1869
1870/*
1871 * handle fork statistics
1872 */
1873int
1874sysctl_forkstat(char *string, char **bufpp, int mib[], int flags, int *typep)
1875{
1876	static struct forkstat fks;
1877	static int keepvalue = 0;
1878	int indx;
1879	size_t size;
1880
1881	if (*bufpp == NULL) {
1882		bzero(&fks, sizeof(struct forkstat));
1883		listall(string, &forkstatlist);
1884		return (-1);
1885	}
1886	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1887		return (-1);
1888	if (*bufpp != NULL) {
1889		warnx("fourth level name in %s is invalid", string);
1890		return (-1);
1891	}
1892	if (keepvalue == 0) {
1893		size = sizeof(struct forkstat);
1894		if (sysctl(mib, 2, &fks, &size, NULL, 0) == -1)
1895			return (-1);
1896		keepvalue = 1;
1897	}
1898	if (!nflag)
1899		(void)printf("%s%s", string, equ);
1900	switch (indx)	{
1901	case KERN_FORKSTAT_FORK:
1902		(void)printf("%u\n", fks.cntfork);
1903		break;
1904	case KERN_FORKSTAT_VFORK:
1905		(void)printf("%u\n", fks.cntvfork);
1906		break;
1907	case KERN_FORKSTAT_TFORK:
1908		(void)printf("%u\n", fks.cnttfork);
1909		break;
1910	case KERN_FORKSTAT_KTHREAD:
1911		(void)printf("%u\n", fks.cntkthread);
1912		break;
1913	case KERN_FORKSTAT_SIZFORK:
1914		(void)printf("%llu\n", fks.sizfork);
1915		break;
1916	case KERN_FORKSTAT_SIZVFORK:
1917		(void)printf("%llu\n", fks.sizvfork);
1918		break;
1919	case KERN_FORKSTAT_SIZTFORK:
1920		(void)printf("%llu\n", fks.siztfork);
1921		break;
1922	case KERN_FORKSTAT_SIZKTHREAD:
1923		(void)printf("%llu\n", fks.sizkthread);
1924		break;
1925	}
1926	return (-1);
1927}
1928
1929/*
1930 * handle malloc statistics
1931 */
1932int
1933sysctl_malloc(char *string, char **bufpp, int mib[], int flags, int *typep)
1934{
1935	int indx, stor, i;
1936	char *name, bufp[SYSCTL_BUFSIZ], *buf, *ptr;
1937	const char *errstr;
1938	struct list lp;
1939	size_t size;
1940
1941	if (*bufpp == NULL) {
1942		listall(string, &kernmalloclist);
1943		return (-1);
1944	}
1945	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1946		return (-1);
1947	mib[2] = indx;
1948	if (mib[2] == KERN_MALLOC_BUCKET) {
1949		if ((name = strsep(bufpp, ".")) == NULL) {
1950			size = SYSCTL_BUFSIZ;
1951			stor = mib[2];
1952			mib[2] = KERN_MALLOC_BUCKETS;
1953			buf = bufp;
1954			if (sysctl(mib, 3, buf, &size, NULL, 0) == -1)
1955				return (-1);
1956			mib[2] = stor;
1957			for (stor = 0, i = 0; i < size; i++)
1958				if (buf[i] == ',')
1959					stor++;
1960			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1961			if (lp.list == NULL)
1962				return (-1);
1963			lp.size = stor + 2;
1964			for (i = 1; (ptr = strsep(&buf, ",")) != NULL; i++) {
1965			        lp.list[i].ctl_name = ptr;
1966				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1967			}
1968			listall(string, &lp);
1969			free(lp.list);
1970			return (-1);
1971		}
1972		mib[3] = strtonum(name, 0, INT_MAX, &errstr);
1973		if (errstr)
1974			return -1;
1975		return (4);
1976	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
1977		*typep = CTLTYPE_STRING;
1978		return (3);
1979	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
1980		size = SYSCTL_BUFSIZ;
1981		stor = mib[2];
1982		mib[2] = KERN_MALLOC_KMEMNAMES;
1983		buf = bufp;
1984		if (sysctl(mib, 3, buf, &size, NULL, 0) == -1)
1985			return (-1);
1986		mib[2] = stor;
1987		if ((name = strsep(bufpp, ".")) == NULL) {
1988			for (stor = 0, i = 0; i < size; i++)
1989				if (buf[i] == ',')
1990					stor++;
1991			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1992			if (lp.list == NULL)
1993				return (-1);
1994			lp.size = stor + 2;
1995			for (i = 1; (ptr = strsep(&buf, ",")) != NULL; i++) {
1996				if (ptr[0] == '\0') {
1997					i--;
1998					continue;
1999				}
2000			    	lp.list[i].ctl_name = ptr;
2001				lp.list[i].ctl_type = CTLTYPE_STRUCT;
2002			}
2003			listall(string, &lp);
2004			free(lp.list);
2005			return (-1);
2006		}
2007		ptr = strstr(buf, name);
2008 tryagain:
2009		if (ptr == NULL) {
2010			warnx("fourth level name %s in %s is invalid", name,
2011			    string);
2012			return (-1);
2013		}
2014		if ((*(ptr + strlen(name)) != ',') &&
2015		    (*(ptr + strlen(name)) != '\0')) {
2016			ptr = strstr(ptr + 1, name); /* retry */
2017			goto tryagain;
2018		}
2019		if ((ptr != buf) && (*(ptr - 1) != ',')) {
2020			ptr = strstr(ptr + 1, name); /* retry */
2021			goto tryagain;
2022		}
2023		for (i = 0, stor = 0; buf + i < ptr; i++)
2024			if (buf[i] == ',')
2025				stor++;
2026		mib[3] = stor;
2027		return (4);
2028	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
2029		*typep = CTLTYPE_STRING;
2030		return (3);
2031	}
2032	return (-1);
2033}
2034
2035#ifdef CPU_CHIPSET
2036/*
2037 * handle machdep.chipset requests
2038 */
2039struct ctlname chipsetname[] = CTL_CHIPSET_NAMES;
2040struct list chipsetlist = { chipsetname, CPU_CHIPSET_MAXID };
2041
2042int
2043sysctl_chipset(char *string, char **bufpp, int mib[], int flags, int *typep)
2044{
2045	int indx, bwx;
2046	static void *q;
2047	size_t len;
2048	char *p;
2049
2050	if (*bufpp == NULL) {
2051		listall(string, &chipsetlist);
2052		return (-1);
2053	}
2054	if ((indx = findname(string, "third", bufpp, &chipsetlist)) == -1)
2055		return (-1);
2056	mib[2] = indx;
2057	if (!nflag)
2058		printf("%s%s", string, equ);
2059	switch(mib[2]) {
2060	case CPU_CHIPSET_MEM:
2061	case CPU_CHIPSET_DENSE:
2062	case CPU_CHIPSET_PORTS:
2063	case CPU_CHIPSET_HAE_MASK:
2064		len = sizeof(void *);
2065		if (sysctl(mib, 3, &q, &len, NULL, 0) == -1)
2066			goto done;
2067		printf("%p", q);
2068		break;
2069	case CPU_CHIPSET_BWX:
2070		len = sizeof(int);
2071		if (sysctl(mib, 3, &bwx, &len, NULL, 0) == -1)
2072			goto done;
2073		printf("%d", bwx);
2074		break;
2075	case CPU_CHIPSET_TYPE:
2076		if (sysctl(mib, 3, NULL, &len, NULL, 0) == -1)
2077			goto done;
2078		p = malloc(len + 1);
2079		if (p == NULL)
2080			goto done;
2081		if (sysctl(mib, 3, p, &len, NULL, 0) == -1) {
2082			free(p);
2083			goto done;
2084		}
2085		p[len] = '\0';
2086		printf("%s", p);
2087		free(p);
2088		break;
2089	}
2090done:
2091	printf("\n");
2092	return (-1);
2093}
2094#endif
2095/*
2096 * handle internet requests
2097 */
2098int
2099sysctl_inet(char *string, char **bufpp, int mib[], int flags, int *typep)
2100{
2101	struct list *lp;
2102	int indx;
2103
2104	if (*bufpp == NULL) {
2105		listall(string, &inetlist);
2106		return (-1);
2107	}
2108	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
2109		return (-1);
2110	mib[2] = indx;
2111	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
2112		lp = &inetvars[indx];
2113	else if (!flags)
2114		return (-1);
2115	else {
2116		warnx("%s: no variables defined for this protocol", string);
2117		return (-1);
2118	}
2119	if (*bufpp == NULL) {
2120		listall(string, lp);
2121		return (-1);
2122	}
2123	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2124		return (-1);
2125	mib[3] = indx;
2126	*typep = lp->list[indx].ctl_type;
2127	if (*typep == CTLTYPE_NODE) {
2128		int tindx;
2129
2130		if (*bufpp == NULL) {
2131			listall(string, &ifqlist);
2132			return(-1);
2133		}
2134		lp = &ifqlist;
2135		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
2136			return (-1);
2137		mib[4] = tindx;
2138		*typep = lp->list[tindx].ctl_type;
2139		return(5);
2140	}
2141	return (4);
2142}
2143
2144struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
2145struct ctlname ip6name[] = IPV6CTL_NAMES;
2146struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
2147struct ctlname divert6name[] = DIVERT6CTL_NAMES;
2148struct list inet6list = { inet6name, IPV6PROTO_MAXID };
2149struct list inet6vars[] = {
2150/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2151	{ 0, 0 },
2152	{ 0, 0 },
2153	{ 0, 0 },
2154	{ 0, 0 },
2155	{ 0, 0 },
2156/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2157	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2158/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2159	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2160/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2161	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2162/*40*/	{ 0, 0 },
2163	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
2164	{ 0, 0 },
2165	{ 0, 0 },
2166	{ 0, 0 },
2167	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2168/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2169	{ 0, 0 },
2170	{ 0, 0 },
2171	{ 0, 0 },
2172	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
2173	{ 0, 0 },
2174/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2175	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2176/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2177	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2178/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2179	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2180/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2181	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2182/*100*/	{ 0, 0 },
2183	{ 0, 0 },
2184	{ 0, 0 },
2185	{ 0, 0 },	/* pim6 */
2186	{ 0, 0 },
2187	{ 0, 0 },
2188	{ 0, 0 },
2189	{ 0, 0 },
2190	{ 0, 0 },
2191	{ 0, 0 },
2192/*110*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2193	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2194/*120*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2195	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2196/*130*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2197	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2198/*140*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2199	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2200/*150*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2201	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2202/*160*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2203	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2204/*170*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2205	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2206/*180*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2207	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2208/*190*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2209	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2210/*200*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2211	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2212/*210*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2213	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2214/*220*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2215	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2216/*230*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2217	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2218/*240*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2219	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2220/*250*/	{ 0, 0 },
2221	{ 0, 0 },
2222	{ 0, 0 },
2223	{ 0, 0 },
2224	{ 0, 0 },
2225	{ 0, 0 },
2226	{ 0, 0 },
2227	{ 0, 0 },
2228	{ divert6name, DIVERT6CTL_MAXID },
2229};
2230
2231/*
2232 * handle internet6 requests
2233 */
2234int
2235sysctl_inet6(char *string, char **bufpp, int mib[], int flags, int *typep)
2236{
2237	struct list *lp;
2238	int indx;
2239
2240	if (*bufpp == NULL) {
2241		listall(string, &inet6list);
2242		return (-1);
2243	}
2244	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
2245		return (-1);
2246	mib[2] = indx;
2247	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
2248		lp = &inet6vars[indx];
2249	else if (!flags)
2250		return (-1);
2251	else {
2252		warnx("%s: no variables defined for this protocol", string);
2253		return (-1);
2254	}
2255	if (*bufpp == NULL) {
2256		listall(string, lp);
2257		return (-1);
2258	}
2259	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2260		return (-1);
2261	mib[3] = indx;
2262	*typep = lp->list[indx].ctl_type;
2263	if (*typep == CTLTYPE_NODE) {
2264		int tindx;
2265
2266		if (*bufpp == NULL) {
2267			listall(string, &ifqlist);
2268			return(-1);
2269		}
2270		lp = &ifqlist;
2271		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
2272			return (-1);
2273		mib[4] = tindx;
2274		*typep = lp->list[tindx].ctl_type;
2275		return(5);
2276	}
2277	return (4);
2278}
2279
2280/* handle net.link requests */
2281struct ctlname netlinkname[] = CTL_NET_LINK_NAMES;
2282struct ctlname ifrxqname[] = CTL_NET_LINK_IFRXQ_NAMES;
2283struct list netlinklist = { netlinkname, NET_LINK_MAXID };
2284struct list netlinkvars[] = {
2285	[NET_LINK_IFRXQ] = { ifrxqname, NET_LINK_IFRXQ_MAXID },
2286};
2287
2288int
2289sysctl_link(char *string, char **bufpp, int mib[], int flags, int *typep)
2290{
2291	struct list *lp;
2292	int indx;
2293
2294	if (*bufpp == NULL) {
2295		listall(string, &netlinklist);
2296		return (-1);
2297	}
2298	if ((indx = findname(string, "third", bufpp, &netlinklist)) == -1)
2299		return (-1);
2300	mib[2] = indx;
2301	if (indx < NET_LINK_MAXID && netlinkvars[indx].list != NULL)
2302		lp = &netlinkvars[indx];
2303	else if (!flags)
2304		return (-1);
2305	else {
2306		warnx("%s: no variables defined for this protocol", string);
2307		return (-1);
2308	}
2309	if (*bufpp == NULL) {
2310		listall(string, lp);
2311		return (-1);
2312	}
2313	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2314		return (-1);
2315	mib[3] = indx;
2316	*typep = lp->list[indx].ctl_type;
2317	return (4);
2318}
2319
2320/* handle bpf requests */
2321int
2322sysctl_bpf(char *string, char **bufpp, int mib[], int flags, int *typep)
2323{
2324	int indx;
2325
2326	if (*bufpp == NULL) {
2327		listall(string, &bpflist);
2328		return (-1);
2329	}
2330	if ((indx = findname(string, "third", bufpp, &bpflist)) == -1)
2331		return (-1);
2332	mib[2] = indx;
2333	*typep = CTLTYPE_INT;
2334	return (3);
2335}
2336
2337struct ctlname mplsname[] = MPLSCTL_NAMES;
2338struct list mplslist = { mplsname, MPLSCTL_MAXID };
2339
2340/* handle MPLS requests */
2341int
2342sysctl_mpls(char *string, char **bufpp, int mib[], int flags, int *typep)
2343{
2344	struct list *lp;
2345	int indx;
2346
2347	if (*bufpp == NULL) {
2348		listall(string, &mplslist);
2349		return (-1);
2350	}
2351	if ((indx = findname(string, "third", bufpp, &mplslist)) == -1)
2352		return (-1);
2353	mib[2] = indx;
2354	*typep = mplslist.list[indx].ctl_type;
2355	if (*typep == CTLTYPE_NODE) {
2356		int tindx;
2357
2358		if (*bufpp == NULL) {
2359			listall(string, &ifqlist);
2360			return(-1);
2361		}
2362		lp = &ifqlist;
2363		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
2364			return (-1);
2365		mib[3] = tindx;
2366		*typep = lp->list[tindx].ctl_type;
2367		return(4);
2368	}
2369	return (3);
2370}
2371
2372/* handle PIPEX requests */
2373int
2374sysctl_pipex(char *string, char **bufpp, int mib[], int flags, int *typep)
2375{
2376	struct list *lp;
2377	int indx;
2378
2379	if (*bufpp == NULL) {
2380		listall(string, &pipexlist);
2381		return (-1);
2382	}
2383	if ((indx = findname(string, "third", bufpp, &pipexlist)) == -1)
2384		return (-1);
2385	mib[2] = indx;
2386	*typep = pipexlist.list[indx].ctl_type;
2387	if (*typep == CTLTYPE_NODE) {
2388		int tindx;
2389
2390		if (*bufpp == NULL) {
2391			listall(string, &ifqlist);
2392			return(-1);
2393		}
2394		lp = &ifqlist;
2395		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
2396			return (-1);
2397		mib[3] = tindx;
2398		*typep = lp->list[tindx].ctl_type;
2399		return(4);
2400	}
2401	return (3);
2402}
2403
2404/*
2405 * Handle SysV semaphore info requests
2406 */
2407int
2408sysctl_seminfo(char *string, char **bufpp, int mib[], int flags, int *typep)
2409{
2410	int indx;
2411
2412	if (*bufpp == NULL) {
2413		listall(string, &semlist);
2414		return (-1);
2415	}
2416	if ((indx = findname(string, "third", bufpp, &semlist)) == -1)
2417		return (-1);
2418	mib[2] = indx;
2419	*typep = CTLTYPE_INT;
2420	return (3);
2421}
2422
2423/*
2424 * Handle SysV shared memory info requests
2425 */
2426int
2427sysctl_shminfo(char *string, char **bufpp, int mib[], int flags, int *typep)
2428{
2429	int indx;
2430
2431	if (*bufpp == NULL) {
2432		listall(string, &shmlist);
2433		return (-1);
2434	}
2435	if ((indx = findname(string, "third", bufpp, &shmlist)) == -1)
2436		return (-1);
2437	mib[2] = indx;
2438	*typep = CTLTYPE_INT;
2439	return (3);
2440}
2441
2442/*
2443 * Handle watchdog support
2444 */
2445int
2446sysctl_watchdog(char *string, char **bufpp, int mib[], int flags,
2447    int *typep)
2448{
2449	int indx;
2450
2451	if (*bufpp == NULL) {
2452		listall(string, &watchdoglist);
2453		return (-1);
2454	}
2455	if ((indx = findname(string, "third", bufpp, &watchdoglist)) == -1)
2456		return (-1);
2457	mib[2] = indx;
2458	*typep = watchdoglist.list[indx].ctl_type;
2459	return (3);
2460}
2461
2462/*
2463 * Handle timecounter support
2464 */
2465int
2466sysctl_tc(char *string, char **bufpp, int mib[], int flags,
2467    int *typep)
2468{
2469	int indx;
2470
2471	if (*bufpp == NULL) {
2472		listall(string, &tclist);
2473		return (-1);
2474	}
2475	if ((indx = findname(string, "third", bufpp, &tclist)) == -1)
2476		return (-1);
2477	mib[2] = indx;
2478	*typep = tclist.list[indx].ctl_type;
2479	return (3);
2480}
2481
2482/*
2483 * Handle hardware monitoring sensors support
2484 */
2485int
2486sysctl_sensors(char *string, char **bufpp, int mib[], int flags, int *typep)
2487{
2488	char *devname, *typename;
2489	int dev, numt, i;
2490	enum sensor_type type;
2491	struct sensordev snsrdev;
2492	size_t sdlen = sizeof(snsrdev);
2493
2494	if (*bufpp == NULL) {
2495		char buf[SYSCTL_BUFSIZ];
2496
2497		/* scan all sensor devices */
2498		for (dev = 0; ; dev++) {
2499			mib[2] = dev;
2500			if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1) {
2501				if (errno == ENXIO)
2502					continue;
2503				if (errno == ENOENT)
2504					break;
2505				warn("sensors dev %d", dev);
2506				return (-1);
2507			}
2508			snprintf(buf, sizeof(buf), "%s.%s",
2509			    string, snsrdev.xname);
2510			print_sensordev(buf, mib, 3, &snsrdev);
2511		}
2512		return (-1);
2513	}
2514
2515	/*
2516	 * If we get this far, it means that some arguments were
2517	 * provided below hw.sensors tree.
2518	 * The first branch of hw.sensors tree is the device name.
2519	 */
2520	if ((devname = strsep(bufpp, ".")) == NULL) {
2521		warnx("%s: incomplete specification", string);
2522		return (-1);
2523	}
2524	/* convert sensor device string to an integer */
2525	for (dev = 0; ; dev++) {
2526		mib[2] = dev;
2527		if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1) {
2528			if (errno == ENXIO)
2529				continue;
2530			if (errno == ENOENT)
2531				break;
2532			warn("sensors dev %d", dev);
2533			return (-1);
2534		}
2535		if (strcmp(devname, snsrdev.xname) == 0)
2536			break;
2537	}
2538	if (strcmp(devname, snsrdev.xname) != 0) {
2539		warnx("%s: sensor device not found: %s", string, devname);
2540		return (-1);
2541	}
2542	if (*bufpp == NULL) {
2543		/* only device name was provided -- let's print all sensors
2544		 * that are attached to the specified device
2545		 */
2546		print_sensordev(string, mib, 3, &snsrdev);
2547		return (-1);
2548	}
2549
2550	/*
2551	 * At this point we have identified the sensor device,
2552	 * now let's go further and identify sensor type.
2553	 */
2554	if ((typename = strsep(bufpp, ".")) == NULL) {
2555		warnx("%s: incomplete specification", string);
2556		return (-1);
2557	}
2558	numt = -1;
2559	for (i = 0; typename[i] != '\0'; i++)
2560		if (isdigit((unsigned char)typename[i])) {
2561			const char *errstr;
2562
2563			numt = strtonum(&typename[i], 0, INT_MAX, &errstr);
2564			if (errstr) {
2565				warnx("%s: %s", string, errstr);
2566				return (-1);
2567			}
2568			typename[i] = '\0';
2569			break;
2570		}
2571	for (type = 0; type < SENSOR_MAX_TYPES; type++)
2572		if (strcmp(typename, sensor_type_s[type]) == 0)
2573			break;
2574	if (type == SENSOR_MAX_TYPES) {
2575		warnx("%s: sensor type not recognised: %s", string, typename);
2576		return (-1);
2577	}
2578	mib[3] = type;
2579
2580	/*
2581	 * If no integer was provided after sensor_type, let's
2582	 * print all sensors of the specified type.
2583	 */
2584	if (numt == -1) {
2585		print_sensordev(string, mib, 4, &snsrdev);
2586		return (-1);
2587	}
2588
2589	/*
2590	 * At this point we know that we have received a direct request
2591	 * via command-line for a specific sensor. Let's have the parse()
2592	 * function deal with it further, and report any errors if such
2593	 * sensor node does not exist.
2594	 */
2595	mib[4] = numt;
2596	*typep = CTLTYPE_STRUCT;
2597	return (5);
2598}
2599
2600/*
2601 * Print sensors from the specified device.
2602 */
2603
2604void
2605print_sensordev(char *string, int mib[], u_int mlen, struct sensordev *snsrdev)
2606{
2607	char buf[SYSCTL_BUFSIZ];
2608	enum sensor_type type;
2609
2610	if (mlen == 3) {
2611		for (type = 0; type < SENSOR_MAX_TYPES; type++) {
2612			mib[3] = type;
2613			snprintf(buf, sizeof(buf), "%s.%s",
2614			    string, sensor_type_s[type]);
2615			print_sensordev(buf, mib, mlen+1, snsrdev);
2616		}
2617		return;
2618	}
2619
2620	if (mlen == 4) {
2621		int numt;
2622
2623		type = mib[3];
2624		for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
2625			mib[4] = numt;
2626			snprintf(buf, sizeof(buf), "%s%u", string, numt);
2627			print_sensordev(buf, mib, mlen+1, snsrdev);
2628		}
2629		return;
2630	}
2631
2632	if (mlen == 5) {
2633		struct sensor snsr;
2634		size_t slen = sizeof(snsr);
2635
2636		/* this function is only printing sensors in bulk, so we
2637		 * do not return any error messages if the requested sensor
2638		 * is not found by sysctl(3)
2639		 */
2640		if (sysctl(mib, 5, &snsr, &slen, NULL, 0) == -1)
2641			return;
2642
2643		if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0) {
2644			if (!nflag)
2645				printf("%s%s", string, equ);
2646			print_sensor(&snsr);
2647			printf("\n");
2648		}
2649		return;
2650	}
2651}
2652
2653void
2654print_sensor(struct sensor *s)
2655{
2656	const char *name;
2657
2658	if (s->flags & SENSOR_FUNKNOWN)
2659		printf("unknown");
2660	else {
2661		switch (s->type) {
2662		case SENSOR_TEMP:
2663			printf("%.2f degC",
2664			    (s->value - 273150000) / 1000000.0);
2665			break;
2666		case SENSOR_FANRPM:
2667			printf("%lld RPM", s->value);
2668			break;
2669		case SENSOR_VOLTS_DC:
2670			printf("%.2f VDC", s->value / 1000000.0);
2671			break;
2672		case SENSOR_VOLTS_AC:
2673			printf("%.2f VAC", s->value / 1000000.0);
2674			break;
2675		case SENSOR_OHMS:
2676			printf("%lld ohm", s->value);
2677			break;
2678		case SENSOR_WATTS:
2679			printf("%.2f W", s->value / 1000000.0);
2680			break;
2681		case SENSOR_AMPS:
2682			printf("%.2f A", s->value / 1000000.0);
2683			break;
2684		case SENSOR_WATTHOUR:
2685			printf("%.2f Wh", s->value / 1000000.0);
2686			break;
2687		case SENSOR_AMPHOUR:
2688			printf("%.2f Ah", s->value / 1000000.0);
2689			break;
2690		case SENSOR_INDICATOR:
2691			printf("%s", s->value ? "On" : "Off");
2692			break;
2693		case SENSOR_INTEGER:
2694			printf("%lld", s->value);
2695			break;
2696		case SENSOR_PERCENT:
2697			printf("%.2f%%", s->value / 1000.0);
2698			break;
2699		case SENSOR_LUX:
2700			printf("%.2f lx", s->value / 1000000.0);
2701			break;
2702		case SENSOR_DRIVE:
2703			switch (s->value) {
2704			case SENSOR_DRIVE_EMPTY:
2705				name = "empty";
2706				break;
2707			case SENSOR_DRIVE_READY:
2708				name = "ready";
2709				break;
2710			case SENSOR_DRIVE_POWERUP:
2711				name = "powering up";
2712				break;
2713			case SENSOR_DRIVE_ONLINE:
2714				name = "online";
2715				break;
2716			case SENSOR_DRIVE_IDLE:
2717				name = "idle";
2718				break;
2719			case SENSOR_DRIVE_ACTIVE:
2720				name = "active";
2721				break;
2722			case SENSOR_DRIVE_REBUILD:
2723				name = "rebuilding";
2724				break;
2725			case SENSOR_DRIVE_POWERDOWN:
2726				name = "powering down";
2727				break;
2728			case SENSOR_DRIVE_FAIL:
2729				name = "failed";
2730				break;
2731			case SENSOR_DRIVE_PFAIL:
2732				name = "degraded";
2733				break;
2734			default:
2735				name = "unknown";
2736				break;
2737			}
2738			printf("%s", name);
2739			break;
2740		case SENSOR_TIMEDELTA:
2741			printf("%.6f secs", s->value / 1000000000.0);
2742			break;
2743		case SENSOR_HUMIDITY:
2744			printf("%.2f%%", s->value / 1000.0);
2745			break;
2746		case SENSOR_FREQ:
2747			printf("%.2f Hz", s->value / 1000000.0);
2748			break;
2749		case SENSOR_ANGLE:
2750			printf("%3.4f degrees", s->value / 1000000.0);
2751			break;
2752		case SENSOR_DISTANCE:
2753			printf("%.3f m", s->value / 1000000.0);
2754			break;
2755		case SENSOR_PRESSURE:
2756			printf("%.2f Pa", s->value / 1000.0);
2757			break;
2758		case SENSOR_ACCEL:
2759			printf("%2.4f m/s^2", s->value / 1000000.0);
2760			break;
2761		case SENSOR_VELOCITY:
2762			printf("%4.3f m/s", s->value / 1000000.0);
2763			break;
2764		default:
2765			printf("unknown");
2766		}
2767	}
2768
2769	if (s->desc[0] != '\0')
2770		printf(" (%s)", s->desc);
2771
2772	switch (s->status) {
2773	case SENSOR_S_UNSPEC:
2774		break;
2775	case SENSOR_S_OK:
2776		printf(", OK");
2777		break;
2778	case SENSOR_S_WARN:
2779		printf(", WARNING");
2780		break;
2781	case SENSOR_S_CRIT:
2782		printf(", CRITICAL");
2783		break;
2784	case SENSOR_S_UNKNOWN:
2785		printf(", UNKNOWN");
2786		break;
2787	}
2788
2789	if (s->tv.tv_sec) {
2790		time_t t = s->tv.tv_sec;
2791		char ct[26];
2792
2793		ctime_r(&t, ct);
2794		ct[19] = '\0';
2795		printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
2796	}
2797}
2798
2799/*
2800 * Handle audio support
2801 */
2802int
2803sysctl_audio(char *string, char **bufpp, int mib[], int flags, int *typep)
2804{
2805	int indx;
2806
2807	if (*bufpp == NULL) {
2808		listall(string, &audiolist);
2809		return (-1);
2810	}
2811	if ((indx = findname(string, "third", bufpp, &audiolist)) == -1)
2812		return (-1);
2813	mib[2] = indx;
2814	*typep = audiolist.list[indx].ctl_type;
2815	return (3);
2816}
2817
2818/*
2819 * Handle witness support
2820 */
2821int
2822sysctl_witness(char *string, char **bufpp, int mib[], int flags, int *typep)
2823{
2824	int indx;
2825
2826	if (*bufpp == NULL) {
2827		listall(string, &witnesslist);
2828		return (-1);
2829	}
2830	if ((indx = findname(string, "third", bufpp, &witnesslist)) == -1)
2831		return (-1);
2832	mib[2] = indx;
2833	*typep = witnesslist.list[indx].ctl_type;
2834	return (3);
2835}
2836
2837/*
2838 * Scan a list of names searching for a particular name.
2839 */
2840int
2841findname(char *string, char *level, char **bufp, struct list *namelist)
2842{
2843	char *name;
2844	int i;
2845
2846	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
2847		warnx("%s: incomplete specification", string);
2848		return (-1);
2849	}
2850	for (i = 0; i < namelist->size; i++)
2851		if (namelist->list[i].ctl_name != NULL &&
2852		    strcmp(name, namelist->list[i].ctl_name) == 0)
2853			break;
2854	if (i == namelist->size) {
2855		warnx("%s level name %s in %s is invalid", level, name, string);
2856		return (-1);
2857	}
2858	return (i);
2859}
2860
2861void
2862usage(void)
2863{
2864
2865	(void)fprintf(stderr,
2866	    "usage: sysctl [-Aanq] [name[=value]]\n");
2867	exit(1);
2868}
2869