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