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