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