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