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