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