1/*	$OpenBSD: sysctl.c,v 1.261 2024/05/09 08:35:40 florian 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			char *ct;
941			boottime = btp->tv_sec;
942			ct = ctime(&boottime);
943			if (ct)
944				(void)printf("%s%s%s", string, equ, ct);
945			else
946				(void)printf("%s%s%lld\n", string, equ,
947				    boottime);
948		} else
949			(void)printf("%lld\n", (long long)btp->tv_sec);
950		return;
951	}
952	if (special & BLKDEV) {
953		dev_t dev = *(dev_t *)buf;
954
955		if (!nflag)
956			(void)printf("%s%s%s\n", string, equ,
957			    devname(dev, S_IFBLK));
958		else
959			(void)printf("0x%x\n", dev);
960		return;
961	}
962	if (special & CHRDEV) {
963		dev_t dev = *(dev_t *)buf;
964
965		if (!nflag)
966			(void)printf("%s%s%s\n", string, equ,
967			    devname(dev, S_IFCHR));
968		else
969			(void)printf("0x%x\n", dev);
970		return;
971	}
972#ifdef CPU_BIOS
973	if (special & BIOSGEO) {
974		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
975
976		if (!nflag)
977			(void)printf("%s%s", string, equ);
978		(void)printf("bootdev = 0x%x, "
979		    "cylinders = %u, heads = %u, sectors = %u\n",
980		    pdi->bsd_dev, pdi->bios_cylinders,
981		    pdi->bios_heads, pdi->bios_sectors);
982		return;
983	}
984	if (special & BIOSDEV) {
985		int dev = *(int*)buf;
986
987		if (!nflag)
988			(void)printf("%s%s", string, equ);
989		(void) printf("0x%02x\n", dev);
990		return;
991	}
992#endif
993	if (special & UNSIGNED) {
994		if (newsize == 0) {
995			if (!nflag)
996				(void)printf("%s%s", string, equ);
997			(void)printf("%u\n", *(u_int *)buf);
998		} else {
999			if (!qflag) {
1000				if (!nflag)
1001					(void)printf("%s: %u -> ", string,
1002					    *(u_int *)buf);
1003				(void)printf("%u\n", *(u_int *)newval);
1004			}
1005		}
1006		return;
1007	}
1008	if (special & BADDYNAMIC) {
1009		u_int port, lastport;
1010		u_int32_t *baddynamic = (u_int32_t *)buf;
1011
1012		if (!qflag) {
1013			if (!nflag)
1014				(void)printf("%s%s", string,
1015				    newsize ? ": " : equ);
1016			lastport = 0;
1017			for (port = 0; port < 65536; port++)
1018				if (DP_ISSET(baddynamic, port)) {
1019					(void)printf("%s%u",
1020					    lastport ? "," : "", port);
1021					lastport = port;
1022				}
1023			if (newsize != 0) {
1024				if (!nflag)
1025					fputs(" -> ", stdout);
1026				baddynamic = (u_int32_t *)newval;
1027				lastport = 0;
1028				for (port = 0; port < 65536; port++)
1029					if (DP_ISSET(baddynamic, port)) {
1030						(void)printf("%s%u",
1031						    lastport ? "," : "", port);
1032						lastport = port;
1033					}
1034			}
1035			(void)putchar('\n');
1036		}
1037		return;
1038	}
1039	if (special & LONGARRAY) {
1040		long *la = (long *)buf;
1041		if (!nflag)
1042			printf("%s%s", string, equ);
1043		while (lal--)
1044			printf("%ld%s", *la++, lal? ",":"");
1045		putchar('\n');
1046		return;
1047	}
1048	if (special & SENSORS) {
1049		struct sensor *s = (struct sensor *)buf;
1050
1051		if (size > 0 && (s->flags & SENSOR_FINVALID) == 0) {
1052			if (!nflag)
1053				printf("%s%s", string, equ);
1054			print_sensor(s);
1055			printf("\n");
1056		}
1057		return;
1058	}
1059	if (special & TIMEOUT) {
1060		struct timeoutstat *tstat = (struct timeoutstat *)buf;
1061
1062		if (!nflag)
1063			printf("%s%s", string, equ);
1064		printf("added = %llu, cancelled = %llu, deleted = %llu, "
1065		    "late = %llu, pending = %llu, readded = %llu, "
1066		    "scheduled = %llu, rescheduled = %llu, "
1067		    "run_softclock = %llu, run_thread = %llu, "
1068		    "softclocks = %llu, thread_wakeups = %llu\n",
1069		    tstat->tos_added, tstat->tos_cancelled, tstat->tos_deleted,
1070		    tstat->tos_late, tstat->tos_pending, tstat->tos_readded,
1071		    tstat->tos_scheduled, tstat->tos_rescheduled,
1072		    tstat->tos_run_softclock, tstat->tos_run_thread,
1073		    tstat->tos_softclocks, tstat->tos_thread_wakeups);
1074		return;
1075	}
1076	switch (type) {
1077	case CTLTYPE_INT:
1078		if (newsize == 0) {
1079			if (!nflag)
1080				(void)printf("%s%s", string, equ);
1081			if (special & HEX)
1082				(void)printf("0x%x\n", *(int *)buf);
1083			else
1084				(void)printf("%d\n", *(int *)buf);
1085		} else {
1086			if (!qflag) {
1087				if (!nflag)
1088					(void)printf("%s: %d -> ", string,
1089					    *(int *)buf);
1090				if (special & HEX)
1091					(void)printf("0x%x\n", *(int *)newval);
1092				else
1093					(void)printf("%d\n", *(int *)newval);
1094			}
1095		}
1096		return;
1097
1098	case CTLTYPE_STRING:
1099		if (newval == NULL) {
1100			if (!nflag)
1101				(void)printf("%s%s", string, equ);
1102			if (special & HEX) {
1103				size_t i;
1104				for (i = 0; i < size; i++) {
1105					(void)printf("%02x",
1106					    (unsigned char)buf[i]);
1107				}
1108				(void)printf("\n");
1109			} else
1110				(void)puts(buf);
1111		} else if (!qflag) {
1112			if (!nflag) {
1113				(void)printf("%s: ", string);
1114				if (special & HEX) {
1115					size_t i;
1116					for (i = 0; i < size; i++) {
1117						(void)printf("%02x",
1118						    (unsigned char)buf[i]);
1119					}
1120				} else
1121					(void)printf("%s", buf);
1122
1123				(void)printf(" -> ");
1124			}
1125			(void)puts(cp);
1126		}
1127		return;
1128
1129	case CTLTYPE_QUAD:
1130		if (newsize == 0) {
1131			int64_t tmp;
1132
1133			memcpy(&tmp, buf, sizeof tmp);
1134			if (!nflag)
1135				(void)printf("%s%s", string, equ);
1136			(void)printf("%lld\n", tmp);
1137		} else {
1138			int64_t tmp;
1139
1140			memcpy(&tmp, buf, sizeof tmp);
1141			if (!qflag) {
1142				if (!nflag)
1143					(void)printf("%s: %lld -> ",
1144					    string, tmp);
1145				memcpy(&tmp, newval, sizeof tmp);
1146				(void)printf("%lld\n", tmp);
1147			}
1148		}
1149		return;
1150
1151	case CTLTYPE_STRUCT:
1152		warnx("%s: unknown structure returned", string);
1153		return;
1154
1155	default:
1156	case CTLTYPE_NODE:
1157		warnx("%s: unknown type returned", string);
1158		return;
1159	}
1160}
1161
1162static void
1163parse_ports(char *portspec, int *port, int *high_port)
1164{
1165	char *dash;
1166	const char *errstr;
1167
1168	if ((dash = strchr(portspec, '-')) != NULL)
1169		*dash++ = '\0';
1170	*port = strtonum(portspec, 0, 65535, &errstr);
1171	if (errstr != NULL)
1172		errx(1, "port is %s: %s", errstr, portspec);
1173	if (dash != NULL) {
1174		*high_port = strtonum(dash, 0, 65535, &errstr);
1175		if (errstr != NULL)
1176			errx(1, "high port is %s: %s", errstr, dash);
1177		if (*high_port < *port)
1178			errx(1, "high port %d is lower than %d",
1179			    *high_port, *port);
1180	} else
1181		*high_port = *port;
1182}
1183
1184void
1185parse_baddynamic(int mib[], size_t len, char *string, void **newvalp,
1186    size_t *newsizep, int flags, int nflag)
1187{
1188	static u_int32_t newbaddynamic[DP_MAPSIZE];
1189	int port, high_port, baddynamic_loaded = 0, full_list_set = 0;
1190	size_t size;
1191	char action, *cp;
1192
1193	while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1194		if (*cp == '+' || *cp == '-') {
1195			if (full_list_set)
1196				errx(1, "cannot mix +/- with full list");
1197			action = *cp++;
1198			if (!baddynamic_loaded) {
1199				size = sizeof(newbaddynamic);
1200				if (sysctl(mib, len, newbaddynamic,
1201				    &size, 0, 0) == -1) {
1202					if (flags == 0)
1203						return;
1204					if (!nflag)
1205						printf("%s: ", string);
1206					puts("kernel does not contain bad "
1207					    "dynamic port tables");
1208					return;
1209				}
1210				baddynamic_loaded = 1;
1211			}
1212			parse_ports(cp, &port, &high_port);
1213			for (; port <= high_port; port++) {
1214				if (action == '+')
1215					DP_SET(newbaddynamic, port);
1216				else
1217					DP_CLR(newbaddynamic, port);
1218			}
1219		} else {
1220			if (baddynamic_loaded)
1221				errx(1, "cannot mix +/- with full list");
1222			if (!full_list_set) {
1223				bzero(newbaddynamic, sizeof(newbaddynamic));
1224				full_list_set = 1;
1225			}
1226			parse_ports(cp, &port, &high_port);
1227			for (; port <= high_port; port++)
1228				DP_SET(newbaddynamic, port);
1229		}
1230	}
1231	*newvalp = (void *)newbaddynamic;
1232	*newsizep = sizeof(newbaddynamic);
1233}
1234
1235/*
1236 * Initialize the set of debugging names
1237 */
1238void
1239debuginit(void)
1240{
1241	int mib[3], loc, i;
1242	size_t size;
1243
1244	if (secondlevel[CTL_DEBUG].list != 0)
1245		return;
1246	secondlevel[CTL_DEBUG].list = debugname;
1247	mib[0] = CTL_DEBUG;
1248	mib[2] = CTL_DEBUG_NAME;
1249	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
1250		mib[1] = i;
1251		size = BUFSIZ - loc;
1252		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
1253			continue;
1254		debugname[i].ctl_name = &names[loc];
1255		debugname[i].ctl_type = CTLTYPE_INT;
1256		loc += size;
1257	}
1258	lastused = loc;
1259}
1260
1261struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
1262struct ctlname ffsname[] = FFS_NAMES;
1263struct ctlname nfsname[] = FS_NFS_NAMES;
1264struct ctlname fusefsname[] = FUSEFS_NAMES;
1265struct list *vfsvars;
1266int *vfs_typenums;
1267
1268/*
1269 * Initialize the set of filesystem names
1270 */
1271void
1272vfsinit(void)
1273{
1274	int mib[4], maxtypenum, cnt, loc, size;
1275	struct vfsconf vfc;
1276	size_t buflen;
1277
1278	if (secondlevel[CTL_VFS].list != 0)
1279		return;
1280	mib[0] = CTL_VFS;
1281	mib[1] = VFS_GENERIC;
1282	mib[2] = VFS_MAXTYPENUM;
1283	buflen = 4;
1284	if (sysctl(mib, 3, &maxtypenum, &buflen, NULL, 0) == -1)
1285		return;
1286	/*
1287         * We need to do 0..maxtypenum so add one, and then we offset them
1288	 * all by (another) one by inserting VFS_GENERIC entries at zero
1289	 */
1290	maxtypenum += 2;
1291	if ((vfs_typenums = calloc(maxtypenum, sizeof(int))) == NULL)
1292		return;
1293	if ((vfsvars = calloc(maxtypenum, sizeof(*vfsvars))) == NULL) {
1294		free(vfs_typenums);
1295		return;
1296	}
1297	if ((vfsname = calloc(maxtypenum, sizeof(*vfsname))) == NULL) {
1298		free(vfs_typenums);
1299		free(vfsvars);
1300		return;
1301	}
1302	mib[2] = VFS_CONF;
1303	buflen = sizeof vfc;
1304	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
1305		mib[3] = cnt - 1;
1306		if (sysctl(mib, 4, &vfc, &buflen, NULL, 0) == -1) {
1307			if (errno == EOPNOTSUPP)
1308				continue;
1309			warn("vfsinit");
1310			free(vfsname);
1311			free(vfsvars);
1312			free(vfs_typenums);
1313			return;
1314		}
1315		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1316			vfsvars[cnt].list = ffsname;
1317			vfsvars[cnt].size = FFS_MAXID;
1318		}
1319		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1320			vfsvars[cnt].list = nfsname;
1321			vfsvars[cnt].size = NFS_MAXID;
1322		}
1323		if (!strcmp(vfc.vfc_name, MOUNT_FUSEFS)) {
1324			vfsvars[cnt].list = fusefsname;
1325			vfsvars[cnt].size = FUSEFS_MAXID;
1326		}
1327		vfs_typenums[cnt] = vfc.vfc_typenum;
1328		strlcat(&names[loc], vfc.vfc_name, sizeof names - loc);
1329		vfsname[cnt].ctl_name = &names[loc];
1330		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1331		size = strlen(vfc.vfc_name) + 1;
1332		loc += size;
1333	}
1334	lastused = loc;
1335
1336	vfsname[0].ctl_name = "mounts";
1337	vfsname[0].ctl_type = CTLTYPE_NODE;
1338	vfsvars[0].list = vfsname + 1;
1339	vfsvars[0].size = maxtypenum - 1;
1340
1341	secondlevel[CTL_VFS].list = vfsname;
1342	secondlevel[CTL_VFS].size = maxtypenum;
1343	return;
1344}
1345
1346int
1347sysctl_vfsgen(char *string, char **bufpp, int mib[], int flags, int *typep)
1348{
1349	int indx;
1350	size_t size;
1351	struct vfsconf vfc;
1352
1353	if (*bufpp == NULL) {
1354		listall(string, vfsvars);
1355		return (-1);
1356	}
1357
1358	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1359		return (-1);
1360
1361	mib[1] = VFS_GENERIC;
1362	mib[2] = VFS_CONF;
1363	mib[3] = indx;
1364	size = sizeof vfc;
1365	if (sysctl(mib, 4, &vfc, &size, NULL, 0) == -1) {
1366		if (errno != EOPNOTSUPP)
1367			warn("vfs print");
1368		return -1;
1369	}
1370	if (flags == 0 && vfc.vfc_refcount == 0)
1371		return -1;
1372	if (!nflag)
1373		fprintf(stdout, "%s has %u mounted instance%s\n",
1374		    string, vfc.vfc_refcount,
1375		    vfc.vfc_refcount != 1 ? "s" : "");
1376	else
1377		fprintf(stdout, "%u\n", vfc.vfc_refcount);
1378
1379	return -1;
1380}
1381
1382int
1383sysctl_vfs(char *string, char **bufpp, int mib[], int flags, int *typep)
1384{
1385	struct list *lp = &vfsvars[mib[1]];
1386	int indx;
1387
1388	if (lp->list == NULL) {
1389		if (flags)
1390			warnx("No variables defined for file system %s", string);
1391		return (-1);
1392	}
1393	if (*bufpp == NULL) {
1394		listall(string, lp);
1395		return (-1);
1396	}
1397	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1398		return (-1);
1399
1400	mib[1] = vfs_typenums[mib[1]];
1401	mib[2] = indx;
1402	*typep = lp->list[indx].ctl_type;
1403	return (3);
1404}
1405
1406struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1407struct list fslist = { posixname, FS_POSIX_MAXID };
1408
1409/*
1410 * handle file system requests
1411 */
1412int
1413sysctl_fs(char *string, char **bufpp, int mib[], int flags, int *typep)
1414{
1415	int indx;
1416
1417	if (*bufpp == NULL) {
1418		listall(string, &fslist);
1419		return (-1);
1420	}
1421	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1422		return (-1);
1423	mib[2] = indx;
1424	*typep = fslist.list[indx].ctl_type;
1425	return (3);
1426}
1427
1428#ifdef CPU_BIOS
1429struct ctlname biosname[] = CTL_BIOS_NAMES;
1430struct list bioslist = { biosname, BIOS_MAXID };
1431
1432/*
1433 * handle BIOS requests
1434 */
1435int
1436sysctl_bios(char *string, char **bufpp, int mib[], int flags, int *typep)
1437{
1438	char *name;
1439	int indx;
1440
1441	if (*bufpp == NULL) {
1442		listall(string, &bioslist);
1443		return (-1);
1444	}
1445	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1446		return (-1);
1447	mib[2] = indx;
1448	if (indx == BIOS_DISKINFO) {
1449		const char *errstr;
1450
1451		if (*bufpp == NULL) {
1452			char name[BUFSIZ];
1453
1454			/* scan all the bios devices */
1455			for (indx = 0; indx < 256; indx++) {
1456				snprintf(name, sizeof(name), "%s.%u",
1457				    string, indx);
1458				parse(name, 1);
1459			}
1460			return (-1);
1461		}
1462		if ((name = strsep(bufpp, ".")) == NULL) {
1463			warnx("%s: incomplete specification", string);
1464			return (-1);
1465		}
1466		mib[3] = strtonum(name, 0, INT_MAX, &errstr);
1467		if (errstr) {
1468			warnx("%s: %s", string, errstr);
1469			return (-1);
1470		}
1471		*typep = CTLTYPE_STRUCT;
1472		return (4);
1473	} else {
1474		*typep = bioslist.list[indx].ctl_type;
1475		return (3);
1476	}
1477}
1478#endif
1479
1480struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1481struct list swpenclist = { swpencname, SWPENC_MAXID };
1482
1483/*
1484 * handle swap encrypt requests
1485 */
1486int
1487sysctl_swpenc(char *string, char **bufpp, int mib[], int flags, int *typep)
1488{
1489	int indx;
1490
1491	if (*bufpp == NULL) {
1492		listall(string, &swpenclist);
1493		return (-1);
1494	}
1495	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1496		return (-1);
1497	mib[2] = indx;
1498	*typep = swpenclist.list[indx].ctl_type;
1499	return (3);
1500}
1501
1502struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1503struct ctlname ipname[] = IPCTL_NAMES;
1504struct ctlname icmpname[] = ICMPCTL_NAMES;
1505struct ctlname igmpname[] = IGMPCTL_NAMES;
1506struct ctlname ipipname[] = IPIPCTL_NAMES;
1507struct ctlname tcpname[] = TCPCTL_NAMES;
1508struct ctlname udpname[] = UDPCTL_NAMES;
1509struct ctlname espname[] = ESPCTL_NAMES;
1510struct ctlname ahname[] = AHCTL_NAMES;
1511struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1512struct ctlname grename[] = GRECTL_NAMES;
1513struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1514struct ctlname carpname[] = CARPCTL_NAMES;
1515struct ctlname pfsyncname[] = PFSYNCCTL_NAMES;
1516struct ctlname divertname[] = DIVERTCTL_NAMES;
1517struct ctlname bpfname[] = CTL_NET_BPF_NAMES;
1518struct ctlname ifqname[] = CTL_IFQ_NAMES;
1519struct ctlname pipexname[] = PIPEXCTL_NAMES;
1520struct list inetlist = { inetname, IPPROTO_MAXID };
1521struct list inetvars[] = {
1522	{ ipname, IPCTL_MAXID },	/* ip */
1523	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1524	{ igmpname, IGMPCTL_MAXID },	/* igmp */
1525	{ 0, 0 },			/* ggmp */
1526	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1527	{ 0, 0 },
1528	{ tcpname, TCPCTL_MAXID },	/* tcp */
1529	{ 0, 0 },
1530	{ 0, 0 },			/* egp */
1531	{ 0, 0 },
1532	{ 0, 0 },
1533	{ 0, 0 },
1534	{ 0, 0 },			/* pup */
1535	{ 0, 0 },
1536	{ 0, 0 },
1537	{ 0, 0 },
1538	{ 0, 0 },
1539	{ udpname, UDPCTL_MAXID },	/* udp */
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	{ 0, 0 },
1564	{ 0, 0 },
1565	{ 0, 0 },
1566	{ 0, 0 },
1567	{ 0, 0 },
1568	{ 0, 0 },
1569	{ grename, GRECTL_MAXID },	/* gre */
1570	{ 0, 0 },
1571	{ 0, 0 },
1572	{ espname, ESPCTL_MAXID },	/* esp */
1573	{ ahname, AHCTL_MAXID },	/* ah */
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	{ 0, 0 },
1614	{ 0, 0 },
1615	{ 0, 0 },
1616	{ 0, 0 },
1617	{ 0, 0 },
1618	{ 0, 0 },
1619	{ etheripname, ETHERIPCTL_MAXID },
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	{ ipcompname, IPCOMPCTL_MAXID },
1631	{ 0, 0 },
1632	{ 0, 0 },
1633	{ 0, 0 },
1634	{ carpname, CARPCTL_MAXID },
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	{ 0, 0 },
1766	{ 0, 0 },
1767	{ 0, 0 },
1768	{ 0, 0 },
1769	{ 0, 0 },
1770	{ 0, 0 },
1771	{ pfsyncname, PFSYNCCTL_MAXID },
1772	{ 0, 0 },
1773	{ 0, 0 },
1774	{ 0, 0 },
1775	{ 0, 0 },
1776	{ 0, 0 },
1777	{ 0, 0 },
1778	{ 0, 0 },
1779	{ 0, 0 },
1780	{ divertname, DIVERTCTL_MAXID },
1781};
1782struct list bpflist = { bpfname, NET_BPF_MAXID };
1783struct list ifqlist = { ifqname, IFQCTL_MAXID };
1784struct list pipexlist = { pipexname, PIPEXCTL_MAXID };
1785
1786struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1787struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1788struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1789struct list ttylist = { ttysname, KERN_TTY_MAXID };
1790struct list semlist = { semname, KERN_SEMINFO_MAXID };
1791struct list shmlist = { shmname, KERN_SHMINFO_MAXID };
1792struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
1793struct list tclist = { tcname, KERN_TIMECOUNTER_MAXID };
1794struct list audiolist = { audioname, KERN_AUDIO_MAXID };
1795struct list videolist = { videoname, KERN_VIDEO_MAXID };
1796struct list witnesslist = { witnessname, KERN_WITNESS_MAXID };
1797struct list batterylist = { batteryname, HW_BATTERY_MAXID };
1798
1799/*
1800 * handle vfs namei cache statistics
1801 */
1802int
1803sysctl_nchstats(char *string, char **bufpp, int mib[], int flags, int *typep)
1804{
1805	static struct nchstats nch;
1806	int indx;
1807	size_t size;
1808	static int keepvalue = 0;
1809
1810	if (*bufpp == NULL) {
1811		bzero(&nch, sizeof(struct nchstats));
1812		listall(string, &nchstatslist);
1813		return (-1);
1814	}
1815	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1816		return (-1);
1817	mib[2] = indx;
1818	if (*bufpp != NULL) {
1819		warnx("fourth level name in %s is invalid", string);
1820		return (-1);
1821	}
1822	if (keepvalue == 0) {
1823		size = sizeof(struct nchstats);
1824		if (sysctl(mib, 2, &nch, &size, NULL, 0) == -1)
1825			return (-1);
1826		keepvalue = 1;
1827	}
1828	if (!nflag)
1829		(void)printf("%s%s", string, equ);
1830	switch (indx) {
1831	case KERN_NCHSTATS_GOODHITS:
1832		(void)printf("%llu\n", nch.ncs_goodhits);
1833		break;
1834	case KERN_NCHSTATS_NEGHITS:
1835		(void)printf("%llu\n", nch.ncs_neghits);
1836		break;
1837	case KERN_NCHSTATS_BADHITS:
1838		(void)printf("%llu\n", nch.ncs_badhits);
1839		break;
1840	case KERN_NCHSTATS_FALSEHITS:
1841		(void)printf("%llu\n", nch.ncs_falsehits);
1842		break;
1843	case KERN_NCHSTATS_MISS:
1844		(void)printf("%llu\n", nch.ncs_miss);
1845		break;
1846	case KERN_NCHSTATS_LONG:
1847		(void)printf("%llu\n", nch.ncs_long);
1848		break;
1849	case KERN_NCHSTATS_PASS2:
1850		(void)printf("%llu\n", nch.ncs_pass2);
1851		break;
1852	case KERN_NCHSTATS_2PASSES:
1853		(void)printf("%llu\n", nch.ncs_2passes);
1854		break;
1855	case KERN_NCHSTATS_REVHITS:
1856		(void)printf("%llu\n", nch.ncs_revhits);
1857		break;
1858	case KERN_NCHSTATS_REVMISS:
1859		(void)printf("%llu\n", nch.ncs_revmiss);
1860		break;
1861	case KERN_NCHSTATS_DOTHITS:
1862		(void)printf("%llu\n", nch.ncs_dothits);
1863		break;
1864	case KERN_NCHSTATS_DOTDOTHITS:
1865		(void)printf("%llu\n", nch.ncs_dotdothits);
1866		break;
1867	}
1868	return (-1);
1869}
1870
1871/*
1872 * handle tty statistics
1873 */
1874int
1875sysctl_tty(char *string, char **bufpp, int mib[], int flags, int *typep)
1876{
1877	int indx;
1878
1879	if (*bufpp == NULL) {
1880		listall(string, &ttylist);
1881		return (-1);
1882	}
1883	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1884		return (-1);
1885	mib[2] = indx;
1886
1887	if ((*typep = ttylist.list[indx].ctl_type) == CTLTYPE_STRUCT) {
1888		if (flags)
1889			warnx("use pstat -t to view %s information",
1890			    string);
1891		return (-1);
1892	}
1893	return (3);
1894}
1895
1896/*
1897 * handle fork statistics
1898 */
1899int
1900sysctl_forkstat(char *string, char **bufpp, int mib[], int flags, int *typep)
1901{
1902	static struct forkstat fks;
1903	static int keepvalue = 0;
1904	int indx;
1905	size_t size;
1906
1907	if (*bufpp == NULL) {
1908		bzero(&fks, sizeof(struct forkstat));
1909		listall(string, &forkstatlist);
1910		return (-1);
1911	}
1912	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1913		return (-1);
1914	if (*bufpp != NULL) {
1915		warnx("fourth level name in %s is invalid", string);
1916		return (-1);
1917	}
1918	if (keepvalue == 0) {
1919		size = sizeof(struct forkstat);
1920		if (sysctl(mib, 2, &fks, &size, NULL, 0) == -1)
1921			return (-1);
1922		keepvalue = 1;
1923	}
1924	if (!nflag)
1925		(void)printf("%s%s", string, equ);
1926	switch (indx)	{
1927	case KERN_FORKSTAT_FORK:
1928		(void)printf("%u\n", fks.cntfork);
1929		break;
1930	case KERN_FORKSTAT_VFORK:
1931		(void)printf("%u\n", fks.cntvfork);
1932		break;
1933	case KERN_FORKSTAT_TFORK:
1934		(void)printf("%u\n", fks.cnttfork);
1935		break;
1936	case KERN_FORKSTAT_KTHREAD:
1937		(void)printf("%u\n", fks.cntkthread);
1938		break;
1939	case KERN_FORKSTAT_SIZFORK:
1940		(void)printf("%llu\n", fks.sizfork);
1941		break;
1942	case KERN_FORKSTAT_SIZVFORK:
1943		(void)printf("%llu\n", fks.sizvfork);
1944		break;
1945	case KERN_FORKSTAT_SIZTFORK:
1946		(void)printf("%llu\n", fks.siztfork);
1947		break;
1948	case KERN_FORKSTAT_SIZKTHREAD:
1949		(void)printf("%llu\n", fks.sizkthread);
1950		break;
1951	}
1952	return (-1);
1953}
1954
1955/*
1956 * handle malloc statistics
1957 */
1958int
1959sysctl_malloc(char *string, char **bufpp, int mib[], int flags, int *typep)
1960{
1961	int indx, stor, i;
1962	char *name, bufp[SYSCTL_BUFSIZ], *buf, *ptr;
1963	const char *errstr;
1964	struct list lp;
1965	size_t size;
1966
1967	if (*bufpp == NULL) {
1968		listall(string, &kernmalloclist);
1969		return (-1);
1970	}
1971	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1972		return (-1);
1973	mib[2] = indx;
1974	if (mib[2] == KERN_MALLOC_BUCKET) {
1975		if ((name = strsep(bufpp, ".")) == NULL) {
1976			size = SYSCTL_BUFSIZ;
1977			stor = mib[2];
1978			mib[2] = KERN_MALLOC_BUCKETS;
1979			buf = bufp;
1980			if (sysctl(mib, 3, buf, &size, NULL, 0) == -1)
1981				return (-1);
1982			mib[2] = stor;
1983			for (stor = 0, i = 0; i < size; i++)
1984				if (buf[i] == ',')
1985					stor++;
1986			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1987			if (lp.list == NULL)
1988				return (-1);
1989			lp.size = stor + 2;
1990			for (i = 1; (ptr = strsep(&buf, ",")) != NULL; i++) {
1991			        lp.list[i].ctl_name = ptr;
1992				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1993			}
1994			listall(string, &lp);
1995			free(lp.list);
1996			return (-1);
1997		}
1998		mib[3] = strtonum(name, 0, INT_MAX, &errstr);
1999		if (errstr)
2000			return -1;
2001		return (4);
2002	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
2003		*typep = CTLTYPE_STRING;
2004		return (3);
2005	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
2006		size = SYSCTL_BUFSIZ;
2007		stor = mib[2];
2008		mib[2] = KERN_MALLOC_KMEMNAMES;
2009		buf = bufp;
2010		if (sysctl(mib, 3, buf, &size, NULL, 0) == -1)
2011			return (-1);
2012		mib[2] = stor;
2013		if ((name = strsep(bufpp, ".")) == NULL) {
2014			for (stor = 0, i = 0; i < size; i++)
2015				if (buf[i] == ',')
2016					stor++;
2017			lp.list = calloc(stor + 2, sizeof(struct ctlname));
2018			if (lp.list == NULL)
2019				return (-1);
2020			lp.size = stor + 2;
2021			for (i = 1; (ptr = strsep(&buf, ",")) != NULL; i++) {
2022				if (ptr[0] == '\0') {
2023					i--;
2024					continue;
2025				}
2026			    	lp.list[i].ctl_name = ptr;
2027				lp.list[i].ctl_type = CTLTYPE_STRUCT;
2028			}
2029			listall(string, &lp);
2030			free(lp.list);
2031			return (-1);
2032		}
2033		ptr = strstr(buf, name);
2034 tryagain:
2035		if (ptr == NULL) {
2036			warnx("fourth level name %s in %s is invalid", name,
2037			    string);
2038			return (-1);
2039		}
2040		if ((*(ptr + strlen(name)) != ',') &&
2041		    (*(ptr + strlen(name)) != '\0')) {
2042			ptr = strstr(ptr + 1, name); /* retry */
2043			goto tryagain;
2044		}
2045		if ((ptr != buf) && (*(ptr - 1) != ',')) {
2046			ptr = strstr(ptr + 1, name); /* retry */
2047			goto tryagain;
2048		}
2049		for (i = 0, stor = 0; buf + i < ptr; i++)
2050			if (buf[i] == ',')
2051				stor++;
2052		mib[3] = stor;
2053		return (4);
2054	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
2055		*typep = CTLTYPE_STRING;
2056		return (3);
2057	}
2058	return (-1);
2059}
2060
2061#ifdef CPU_CHIPSET
2062/*
2063 * handle machdep.chipset requests
2064 */
2065struct ctlname chipsetname[] = CTL_CHIPSET_NAMES;
2066struct list chipsetlist = { chipsetname, CPU_CHIPSET_MAXID };
2067
2068int
2069sysctl_chipset(char *string, char **bufpp, int mib[], int flags, int *typep)
2070{
2071	int indx, bwx;
2072	static void *q;
2073	size_t len;
2074	char *p;
2075
2076	if (*bufpp == NULL) {
2077		listall(string, &chipsetlist);
2078		return (-1);
2079	}
2080	if ((indx = findname(string, "third", bufpp, &chipsetlist)) == -1)
2081		return (-1);
2082	mib[2] = indx;
2083	if (!nflag)
2084		printf("%s%s", string, equ);
2085	switch(mib[2]) {
2086	case CPU_CHIPSET_MEM:
2087	case CPU_CHIPSET_DENSE:
2088	case CPU_CHIPSET_PORTS:
2089	case CPU_CHIPSET_HAE_MASK:
2090		len = sizeof(void *);
2091		if (sysctl(mib, 3, &q, &len, NULL, 0) == -1)
2092			goto done;
2093		printf("%p", q);
2094		break;
2095	case CPU_CHIPSET_BWX:
2096		len = sizeof(int);
2097		if (sysctl(mib, 3, &bwx, &len, NULL, 0) == -1)
2098			goto done;
2099		printf("%d", bwx);
2100		break;
2101	case CPU_CHIPSET_TYPE:
2102		if (sysctl(mib, 3, NULL, &len, NULL, 0) == -1)
2103			goto done;
2104		p = malloc(len + 1);
2105		if (p == NULL)
2106			goto done;
2107		if (sysctl(mib, 3, p, &len, NULL, 0) == -1) {
2108			free(p);
2109			goto done;
2110		}
2111		p[len] = '\0';
2112		printf("%s", p);
2113		free(p);
2114		break;
2115	}
2116done:
2117	printf("\n");
2118	return (-1);
2119}
2120#endif
2121/*
2122 * handle internet requests
2123 */
2124int
2125sysctl_inet(char *string, char **bufpp, int mib[], int flags, int *typep)
2126{
2127	struct list *lp;
2128	int indx;
2129
2130	if (*bufpp == NULL) {
2131		listall(string, &inetlist);
2132		return (-1);
2133	}
2134	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
2135		return (-1);
2136	mib[2] = indx;
2137	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
2138		lp = &inetvars[indx];
2139	else if (!flags)
2140		return (-1);
2141	else {
2142		warnx("%s: no variables defined for this protocol", string);
2143		return (-1);
2144	}
2145	if (*bufpp == NULL) {
2146		listall(string, lp);
2147		return (-1);
2148	}
2149	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2150		return (-1);
2151	mib[3] = indx;
2152	*typep = lp->list[indx].ctl_type;
2153	if (*typep == CTLTYPE_NODE) {
2154		int tindx;
2155
2156		if (*bufpp == NULL) {
2157			listall(string, &ifqlist);
2158			return(-1);
2159		}
2160		lp = &ifqlist;
2161		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
2162			return (-1);
2163		mib[4] = tindx;
2164		*typep = lp->list[tindx].ctl_type;
2165		return(5);
2166	}
2167	return (4);
2168}
2169
2170struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
2171struct ctlname ip6name[] = IPV6CTL_NAMES;
2172struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
2173struct ctlname divert6name[] = DIVERT6CTL_NAMES;
2174struct list inet6list = { inet6name, IPV6PROTO_MAXID };
2175struct list inet6vars[] = {
2176/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2177	{ 0, 0 },
2178	{ 0, 0 },
2179	{ 0, 0 },
2180	{ 0, 0 },
2181	{ 0, 0 },
2182/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2183	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2184/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2185	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2186/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2187	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2188/*40*/	{ 0, 0 },
2189	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
2190	{ 0, 0 },
2191	{ 0, 0 },
2192	{ 0, 0 },
2193	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2194/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2195	{ 0, 0 },
2196	{ 0, 0 },
2197	{ 0, 0 },
2198	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
2199	{ 0, 0 },
2200/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2201	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2202/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2203	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2204/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2205	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2206/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2207	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2208/*100*/	{ 0, 0 },
2209	{ 0, 0 },
2210	{ 0, 0 },
2211	{ 0, 0 },	/* pim6 */
2212	{ 0, 0 },
2213	{ 0, 0 },
2214	{ 0, 0 },
2215	{ 0, 0 },
2216	{ 0, 0 },
2217	{ 0, 0 },
2218/*110*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2219	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2220/*120*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2221	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2222/*130*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2223	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2224/*140*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2225	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2226/*150*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2227	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2228/*160*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2229	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2230/*170*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2231	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2232/*180*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2233	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2234/*190*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2235	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2236/*200*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2237	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2238/*210*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2239	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2240/*220*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2241	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2242/*230*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2243	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2244/*240*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2245	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2246/*250*/	{ 0, 0 },
2247	{ 0, 0 },
2248	{ 0, 0 },
2249	{ 0, 0 },
2250	{ 0, 0 },
2251	{ 0, 0 },
2252	{ 0, 0 },
2253	{ 0, 0 },
2254	{ divert6name, DIVERT6CTL_MAXID },
2255};
2256
2257/*
2258 * handle internet6 requests
2259 */
2260int
2261sysctl_inet6(char *string, char **bufpp, int mib[], int flags, int *typep)
2262{
2263	struct list *lp;
2264	int indx;
2265
2266	if (*bufpp == NULL) {
2267		listall(string, &inet6list);
2268		return (-1);
2269	}
2270	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
2271		return (-1);
2272	mib[2] = indx;
2273	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
2274		lp = &inet6vars[indx];
2275	else if (!flags)
2276		return (-1);
2277	else {
2278		warnx("%s: no variables defined for this protocol", string);
2279		return (-1);
2280	}
2281	if (*bufpp == NULL) {
2282		listall(string, lp);
2283		return (-1);
2284	}
2285	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2286		return (-1);
2287	mib[3] = indx;
2288	*typep = lp->list[indx].ctl_type;
2289	if (*typep == CTLTYPE_NODE) {
2290		int tindx;
2291
2292		if (*bufpp == NULL) {
2293			listall(string, &ifqlist);
2294			return(-1);
2295		}
2296		lp = &ifqlist;
2297		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
2298			return (-1);
2299		mib[4] = tindx;
2300		*typep = lp->list[tindx].ctl_type;
2301		return(5);
2302	}
2303	return (4);
2304}
2305
2306/* handle net.unix requests */
2307struct ctlname netunixname[] = CTL_NET_UNIX_NAMES;
2308struct ctlname netunixprotoname[] = CTL_NET_UNIX_PROTO_NAMES;
2309struct list netunixlist = { netunixname, NET_UNIX_MAXID };
2310struct list netunixvars[] = {
2311	[SOCK_STREAM] = { netunixprotoname, NET_UNIX_PROTO_MAXID },
2312	[SOCK_DGRAM] = { netunixprotoname, NET_UNIX_PROTO_MAXID },
2313	[SOCK_SEQPACKET] = { netunixprotoname, NET_UNIX_PROTO_MAXID },
2314	[NET_UNIX_MAXID] = { 0, 0 },
2315};
2316
2317int
2318sysctl_unix(char *string, char **bufpp, int mib[], int flags, int *typep)
2319{
2320	struct list *lp;
2321	int indx;
2322
2323	if (*bufpp == NULL) {
2324		listall(string, &netunixlist);
2325		return (-1);
2326	}
2327	if ((indx = findname(string, "third", bufpp, &netunixlist)) == -1)
2328		return (-1);
2329	mib[2] = indx;
2330	*typep = netunixname[indx].ctl_type;
2331
2332	if (indx < NET_UNIX_MAXID && netunixvars[indx].list != NULL)
2333		lp = &netunixvars[indx];
2334	else
2335		return (3);
2336
2337	if (*bufpp == NULL) {
2338		listall(string, lp);
2339		return (-1);
2340	}
2341	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2342		return (-1);
2343	mib[3] = indx;
2344	*typep = lp->list[indx].ctl_type;
2345	return (4);
2346}
2347
2348/* handle net.link requests */
2349struct ctlname netlinkname[] = CTL_NET_LINK_NAMES;
2350struct ctlname ifrxqname[] = CTL_NET_LINK_IFRXQ_NAMES;
2351struct list netlinklist = { netlinkname, NET_LINK_MAXID };
2352struct list netlinkvars[] = {
2353	[NET_LINK_IFRXQ] = { ifrxqname, NET_LINK_IFRXQ_MAXID },
2354};
2355
2356int
2357sysctl_link(char *string, char **bufpp, int mib[], int flags, int *typep)
2358{
2359	struct list *lp;
2360	int indx;
2361
2362	if (*bufpp == NULL) {
2363		listall(string, &netlinklist);
2364		return (-1);
2365	}
2366	if ((indx = findname(string, "third", bufpp, &netlinklist)) == -1)
2367		return (-1);
2368	mib[2] = indx;
2369	if (indx < NET_LINK_MAXID && netlinkvars[indx].list != NULL)
2370		lp = &netlinkvars[indx];
2371	else if (!flags)
2372		return (-1);
2373	else {
2374		warnx("%s: no variables defined for this protocol", string);
2375		return (-1);
2376	}
2377	if (*bufpp == NULL) {
2378		listall(string, lp);
2379		return (-1);
2380	}
2381	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2382		return (-1);
2383	mib[3] = indx;
2384	*typep = lp->list[indx].ctl_type;
2385	return (4);
2386}
2387
2388/* handle bpf requests */
2389int
2390sysctl_bpf(char *string, char **bufpp, int mib[], int flags, int *typep)
2391{
2392	int indx;
2393
2394	if (*bufpp == NULL) {
2395		listall(string, &bpflist);
2396		return (-1);
2397	}
2398	if ((indx = findname(string, "third", bufpp, &bpflist)) == -1)
2399		return (-1);
2400	mib[2] = indx;
2401	*typep = CTLTYPE_INT;
2402	return (3);
2403}
2404
2405struct ctlname mplsname[] = MPLSCTL_NAMES;
2406struct list mplslist = { mplsname, MPLSCTL_MAXID };
2407
2408/* handle MPLS requests */
2409int
2410sysctl_mpls(char *string, char **bufpp, int mib[], int flags, int *typep)
2411{
2412	struct list *lp;
2413	int indx;
2414
2415	if (*bufpp == NULL) {
2416		listall(string, &mplslist);
2417		return (-1);
2418	}
2419	if ((indx = findname(string, "third", bufpp, &mplslist)) == -1)
2420		return (-1);
2421	mib[2] = indx;
2422	*typep = mplslist.list[indx].ctl_type;
2423	if (*typep == CTLTYPE_NODE) {
2424		int tindx;
2425
2426		if (*bufpp == NULL) {
2427			listall(string, &ifqlist);
2428			return(-1);
2429		}
2430		lp = &ifqlist;
2431		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
2432			return (-1);
2433		mib[3] = tindx;
2434		*typep = lp->list[tindx].ctl_type;
2435		return(4);
2436	}
2437	return (3);
2438}
2439
2440/* handle PIPEX requests */
2441int
2442sysctl_pipex(char *string, char **bufpp, int mib[], int flags, int *typep)
2443{
2444	struct list *lp;
2445	int indx;
2446
2447	if (*bufpp == NULL) {
2448		listall(string, &pipexlist);
2449		return (-1);
2450	}
2451	if ((indx = findname(string, "third", bufpp, &pipexlist)) == -1)
2452		return (-1);
2453	mib[2] = indx;
2454	*typep = pipexlist.list[indx].ctl_type;
2455	if (*typep == CTLTYPE_NODE) {
2456		int tindx;
2457
2458		if (*bufpp == NULL) {
2459			listall(string, &ifqlist);
2460			return(-1);
2461		}
2462		lp = &ifqlist;
2463		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
2464			return (-1);
2465		mib[3] = tindx;
2466		*typep = lp->list[tindx].ctl_type;
2467		return(4);
2468	}
2469	return (3);
2470}
2471
2472/*
2473 * Handle SysV semaphore info requests
2474 */
2475int
2476sysctl_seminfo(char *string, char **bufpp, int mib[], int flags, int *typep)
2477{
2478	int indx;
2479
2480	if (*bufpp == NULL) {
2481		listall(string, &semlist);
2482		return (-1);
2483	}
2484	if ((indx = findname(string, "third", bufpp, &semlist)) == -1)
2485		return (-1);
2486	mib[2] = indx;
2487	*typep = CTLTYPE_INT;
2488	return (3);
2489}
2490
2491/*
2492 * Handle SysV shared memory info requests
2493 */
2494int
2495sysctl_shminfo(char *string, char **bufpp, int mib[], int flags, int *typep)
2496{
2497	int indx;
2498
2499	if (*bufpp == NULL) {
2500		listall(string, &shmlist);
2501		return (-1);
2502	}
2503	if ((indx = findname(string, "third", bufpp, &shmlist)) == -1)
2504		return (-1);
2505	mib[2] = indx;
2506	*typep = CTLTYPE_INT;
2507	return (3);
2508}
2509
2510/*
2511 * Handle watchdog support
2512 */
2513int
2514sysctl_watchdog(char *string, char **bufpp, int mib[], int flags,
2515    int *typep)
2516{
2517	int indx;
2518
2519	if (*bufpp == NULL) {
2520		listall(string, &watchdoglist);
2521		return (-1);
2522	}
2523	if ((indx = findname(string, "third", bufpp, &watchdoglist)) == -1)
2524		return (-1);
2525	mib[2] = indx;
2526	*typep = watchdoglist.list[indx].ctl_type;
2527	return (3);
2528}
2529
2530/*
2531 * Handle timecounter support
2532 */
2533int
2534sysctl_tc(char *string, char **bufpp, int mib[], int flags,
2535    int *typep)
2536{
2537	int indx;
2538
2539	if (*bufpp == NULL) {
2540		listall(string, &tclist);
2541		return (-1);
2542	}
2543	if ((indx = findname(string, "third", bufpp, &tclist)) == -1)
2544		return (-1);
2545	mib[2] = indx;
2546	*typep = tclist.list[indx].ctl_type;
2547	return (3);
2548}
2549
2550/*
2551 * Handle hardware monitoring sensors support
2552 */
2553int
2554sysctl_sensors(char *string, char **bufpp, int mib[], int flags, int *typep)
2555{
2556	char *devname, *typename;
2557	int dev, numt, i;
2558	enum sensor_type type;
2559	struct sensordev snsrdev;
2560	size_t sdlen = sizeof(snsrdev);
2561
2562	if (*bufpp == NULL) {
2563		char buf[SYSCTL_BUFSIZ];
2564
2565		/* scan all sensor devices */
2566		for (dev = 0; ; dev++) {
2567			mib[2] = dev;
2568			if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1) {
2569				if (errno == ENXIO)
2570					continue;
2571				if (errno == ENOENT)
2572					break;
2573				warn("sensors dev %d", dev);
2574				return (-1);
2575			}
2576			snprintf(buf, sizeof(buf), "%s.%s",
2577			    string, snsrdev.xname);
2578			print_sensordev(buf, mib, 3, &snsrdev);
2579		}
2580		return (-1);
2581	}
2582
2583	/*
2584	 * If we get this far, it means that some arguments were
2585	 * provided below hw.sensors tree.
2586	 * The first branch of hw.sensors tree is the device name.
2587	 */
2588	if ((devname = strsep(bufpp, ".")) == NULL) {
2589		warnx("%s: incomplete specification", string);
2590		return (-1);
2591	}
2592	/* convert sensor device string to an integer */
2593	for (dev = 0; ; dev++) {
2594		mib[2] = dev;
2595		if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1) {
2596			if (errno == ENXIO)
2597				continue;
2598			if (errno == ENOENT)
2599				break;
2600			warn("sensors dev %d", dev);
2601			return (-1);
2602		}
2603		if (strcmp(devname, snsrdev.xname) == 0)
2604			break;
2605	}
2606	if (strcmp(devname, snsrdev.xname) != 0) {
2607		warnx("%s: sensor device not found: %s", string, devname);
2608		return (-1);
2609	}
2610	if (*bufpp == NULL) {
2611		/* only device name was provided -- let's print all sensors
2612		 * that are attached to the specified device
2613		 */
2614		print_sensordev(string, mib, 3, &snsrdev);
2615		return (-1);
2616	}
2617
2618	/*
2619	 * At this point we have identified the sensor device,
2620	 * now let's go further and identify sensor type.
2621	 */
2622	if ((typename = strsep(bufpp, ".")) == NULL) {
2623		warnx("%s: incomplete specification", string);
2624		return (-1);
2625	}
2626	numt = -1;
2627	for (i = 0; typename[i] != '\0'; i++)
2628		if (isdigit((unsigned char)typename[i])) {
2629			const char *errstr;
2630
2631			numt = strtonum(&typename[i], 0, INT_MAX, &errstr);
2632			if (errstr) {
2633				warnx("%s: %s", string, errstr);
2634				return (-1);
2635			}
2636			typename[i] = '\0';
2637			break;
2638		}
2639	for (type = 0; type < SENSOR_MAX_TYPES; type++)
2640		if (strcmp(typename, sensor_type_s[type]) == 0)
2641			break;
2642	if (type == SENSOR_MAX_TYPES) {
2643		warnx("%s: sensor type not recognised: %s", string, typename);
2644		return (-1);
2645	}
2646	mib[3] = type;
2647
2648	/*
2649	 * If no integer was provided after sensor_type, let's
2650	 * print all sensors of the specified type.
2651	 */
2652	if (numt == -1) {
2653		print_sensordev(string, mib, 4, &snsrdev);
2654		return (-1);
2655	}
2656
2657	/*
2658	 * At this point we know that we have received a direct request
2659	 * via command-line for a specific sensor. Let's have the parse()
2660	 * function deal with it further, and report any errors if such
2661	 * sensor node does not exist.
2662	 */
2663	mib[4] = numt;
2664	*typep = CTLTYPE_STRUCT;
2665	return (5);
2666}
2667
2668/*
2669 * Print sensors from the specified device.
2670 */
2671
2672void
2673print_sensordev(char *string, int mib[], u_int mlen, struct sensordev *snsrdev)
2674{
2675	char buf[SYSCTL_BUFSIZ];
2676	enum sensor_type type;
2677
2678	if (mlen == 3) {
2679		for (type = 0; type < SENSOR_MAX_TYPES; type++) {
2680			mib[3] = type;
2681			snprintf(buf, sizeof(buf), "%s.%s",
2682			    string, sensor_type_s[type]);
2683			print_sensordev(buf, mib, mlen+1, snsrdev);
2684		}
2685		return;
2686	}
2687
2688	if (mlen == 4) {
2689		int numt;
2690
2691		type = mib[3];
2692		for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
2693			mib[4] = numt;
2694			snprintf(buf, sizeof(buf), "%s%u", string, numt);
2695			print_sensordev(buf, mib, mlen+1, snsrdev);
2696		}
2697		return;
2698	}
2699
2700	if (mlen == 5) {
2701		struct sensor snsr;
2702		size_t slen = sizeof(snsr);
2703
2704		/* this function is only printing sensors in bulk, so we
2705		 * do not return any error messages if the requested sensor
2706		 * is not found by sysctl(3)
2707		 */
2708		if (sysctl(mib, 5, &snsr, &slen, NULL, 0) == -1)
2709			return;
2710
2711		if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0) {
2712			if (!nflag)
2713				printf("%s%s", string, equ);
2714			print_sensor(&snsr);
2715			printf("\n");
2716		}
2717		return;
2718	}
2719}
2720
2721void
2722print_sensor(struct sensor *s)
2723{
2724	const char *name;
2725
2726	if (s->flags & SENSOR_FUNKNOWN)
2727		printf("unknown");
2728	else {
2729		switch (s->type) {
2730		case SENSOR_TEMP:
2731			printf("%.2f degC",
2732			    (s->value - 273150000) / 1000000.0);
2733			break;
2734		case SENSOR_FANRPM:
2735			printf("%lld RPM", s->value);
2736			break;
2737		case SENSOR_VOLTS_DC:
2738			printf("%.2f VDC", s->value / 1000000.0);
2739			break;
2740		case SENSOR_VOLTS_AC:
2741			printf("%.2f VAC", s->value / 1000000.0);
2742			break;
2743		case SENSOR_OHMS:
2744			printf("%lld ohm", s->value);
2745			break;
2746		case SENSOR_WATTS:
2747			printf("%.2f W", s->value / 1000000.0);
2748			break;
2749		case SENSOR_AMPS:
2750			printf("%.2f A", s->value / 1000000.0);
2751			break;
2752		case SENSOR_WATTHOUR:
2753			printf("%.2f Wh", s->value / 1000000.0);
2754			break;
2755		case SENSOR_AMPHOUR:
2756			printf("%.2f Ah", s->value / 1000000.0);
2757			break;
2758		case SENSOR_INDICATOR:
2759			printf("%s", s->value ? "On" : "Off");
2760			break;
2761		case SENSOR_INTEGER:
2762			printf("%lld", s->value);
2763			break;
2764		case SENSOR_PERCENT:
2765			printf("%.2f%%", s->value / 1000.0);
2766			break;
2767		case SENSOR_LUX:
2768			printf("%.2f lx", s->value / 1000000.0);
2769			break;
2770		case SENSOR_DRIVE:
2771			switch (s->value) {
2772			case SENSOR_DRIVE_EMPTY:
2773				name = "empty";
2774				break;
2775			case SENSOR_DRIVE_READY:
2776				name = "ready";
2777				break;
2778			case SENSOR_DRIVE_POWERUP:
2779				name = "powering up";
2780				break;
2781			case SENSOR_DRIVE_ONLINE:
2782				name = "online";
2783				break;
2784			case SENSOR_DRIVE_IDLE:
2785				name = "idle";
2786				break;
2787			case SENSOR_DRIVE_ACTIVE:
2788				name = "active";
2789				break;
2790			case SENSOR_DRIVE_REBUILD:
2791				name = "rebuilding";
2792				break;
2793			case SENSOR_DRIVE_POWERDOWN:
2794				name = "powering down";
2795				break;
2796			case SENSOR_DRIVE_FAIL:
2797				name = "failed";
2798				break;
2799			case SENSOR_DRIVE_PFAIL:
2800				name = "degraded";
2801				break;
2802			default:
2803				name = "unknown";
2804				break;
2805			}
2806			printf("%s", name);
2807			break;
2808		case SENSOR_TIMEDELTA:
2809			printf("%.6f secs", s->value / 1000000000.0);
2810			break;
2811		case SENSOR_HUMIDITY:
2812			printf("%.2f%%", s->value / 1000.0);
2813			break;
2814		case SENSOR_FREQ:
2815			printf("%.2f Hz", s->value / 1000000.0);
2816			break;
2817		case SENSOR_ANGLE:
2818			printf("%3.4f degrees", s->value / 1000000.0);
2819			break;
2820		case SENSOR_DISTANCE:
2821			printf("%.3f m", s->value / 1000000.0);
2822			break;
2823		case SENSOR_PRESSURE:
2824			printf("%.2f Pa", s->value / 1000.0);
2825			break;
2826		case SENSOR_ACCEL:
2827			printf("%2.4f m/s^2", s->value / 1000000.0);
2828			break;
2829		case SENSOR_VELOCITY:
2830			printf("%4.3f m/s", s->value / 1000000.0);
2831			break;
2832		case SENSOR_ENERGY:
2833			printf("%.2f J", s->value / 1000000.0);
2834			break;
2835		default:
2836			printf("unknown");
2837		}
2838	}
2839
2840	if (s->desc[0] != '\0')
2841		printf(" (%s)", s->desc);
2842
2843	switch (s->status) {
2844	case SENSOR_S_UNSPEC:
2845		break;
2846	case SENSOR_S_OK:
2847		printf(", OK");
2848		break;
2849	case SENSOR_S_WARN:
2850		printf(", WARNING");
2851		break;
2852	case SENSOR_S_CRIT:
2853		printf(", CRITICAL");
2854		break;
2855	case SENSOR_S_UNKNOWN:
2856		printf(", UNKNOWN");
2857		break;
2858	}
2859
2860	if (s->tv.tv_sec) {
2861		time_t t = s->tv.tv_sec;
2862		char ct[26];
2863
2864		if (ctime_r(&t, ct)) {
2865			ct[19] = '\0';
2866			printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
2867		} else
2868			printf(", %lld.%03ld", t, s->tv.tv_usec / 1000);
2869	}
2870}
2871
2872/*
2873 * Handle audio support
2874 */
2875int
2876sysctl_audio(char *string, char **bufpp, int mib[], int flags, int *typep)
2877{
2878	int indx;
2879
2880	if (*bufpp == NULL) {
2881		listall(string, &audiolist);
2882		return (-1);
2883	}
2884	if ((indx = findname(string, "third", bufpp, &audiolist)) == -1)
2885		return (-1);
2886	mib[2] = indx;
2887	*typep = audiolist.list[indx].ctl_type;
2888	return (3);
2889}
2890
2891/*
2892 * Handle video support
2893 */
2894int
2895sysctl_video(char *string, char **bufpp, int mib[], int flags, int *typep)
2896{
2897	int indx;
2898
2899	if (*bufpp == NULL) {
2900		listall(string, &videolist);
2901		return (-1);
2902	}
2903	if ((indx = findname(string, "third", bufpp, &videolist)) == -1)
2904		return (-1);
2905	mib[2] = indx;
2906	*typep = videolist.list[indx].ctl_type;
2907	return (3);
2908}
2909
2910/*
2911 * Handle witness support
2912 */
2913int
2914sysctl_witness(char *string, char **bufpp, int mib[], int flags, int *typep)
2915{
2916	int indx;
2917
2918	if (*bufpp == NULL) {
2919		listall(string, &witnesslist);
2920		return (-1);
2921	}
2922	if ((indx = findname(string, "third", bufpp, &witnesslist)) == -1)
2923		return (-1);
2924	mib[2] = indx;
2925	*typep = witnesslist.list[indx].ctl_type;
2926	return (3);
2927}
2928
2929/*
2930 * Handle battery support
2931 */
2932int
2933sysctl_battery(char *string, char **bufpp, int mib[], int flags,
2934    int *typep)
2935{
2936	int indx;
2937
2938	if (*bufpp == NULL) {
2939		listall(string, &batterylist);
2940		return (-1);
2941	}
2942	if ((indx = findname(string, "third", bufpp, &batterylist)) == -1)
2943		return (-1);
2944	mib[2] = indx;
2945	*typep = batterylist.list[indx].ctl_type;
2946	return (3);
2947}
2948
2949/*
2950 * Scan a list of names searching for a particular name.
2951 */
2952int
2953findname(char *string, char *level, char **bufp, struct list *namelist)
2954{
2955	char *name;
2956	int i;
2957
2958	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
2959		warnx("%s: incomplete specification", string);
2960		return (-1);
2961	}
2962	for (i = 0; i < namelist->size; i++)
2963		if (namelist->list[i].ctl_name != NULL &&
2964		    strcmp(name, namelist->list[i].ctl_name) == 0)
2965			break;
2966	if (i == namelist->size) {
2967		warnx("%s level name %s in %s is invalid", level, name, string);
2968		return (-1);
2969	}
2970	return (i);
2971}
2972
2973void
2974usage(void)
2975{
2976
2977	(void)fprintf(stderr,
2978	    "usage: sysctl [-Aanq] [name[=value]]\n");
2979	exit(1);
2980}
2981