xref: /openbsd-src/sbin/sysctl/sysctl.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: sysctl.c,v 1.100 2003/10/17 21:04:57 mcbride 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 #ifndef lint
34 static const char copyright[] =
35 "@(#) Copyright (c) 1993\n\
36 	The Regents of the University of California.  All rights reserved.\n";
37 #endif /* not lint */
38 
39 #ifndef lint
40 #if 0
41 static const char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
42 #else
43 static char *rcsid = "$OpenBSD: sysctl.c,v 1.100 2003/10/17 21:04:57 mcbride Exp $";
44 #endif
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #include <sys/gmon.h>
49 #include <sys/mount.h>
50 #include <sys/stat.h>
51 #include <sys/sem.h>
52 #include <sys/shm.h>
53 #include <sys/sysctl.h>
54 #include <sys/socket.h>
55 #include <sys/malloc.h>
56 #include <sys/dkstat.h>
57 #include <sys/uio.h>
58 #include <sys/tty.h>
59 #include <sys/namei.h>
60 #include <sys/sensors.h>
61 #include <machine/cpu.h>
62 #include <net/route.h>
63 
64 #include <netinet/in.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/ip.h>
67 #include <netinet/in_pcb.h>
68 #include <netinet/ip_icmp.h>
69 #include <netinet/ip_ipip.h>
70 #include <netinet/ip_ether.h>
71 #include <netinet/ip_ah.h>
72 #include <netinet/ip_esp.h>
73 #include <netinet/icmp_var.h>
74 #include <netinet/ip_var.h>
75 #include <netinet/udp.h>
76 #include <netinet/udp_var.h>
77 #include <netinet/tcp.h>
78 #include <netinet/tcp_timer.h>
79 #include <netinet/tcp_var.h>
80 #include <netinet/ip_gre.h>
81 #include <netinet/ip_ipcomp.h>
82 #include <netinet/ip_carp.h>
83 
84 #ifdef INET6
85 #include <netinet/ip6.h>
86 #include <netinet/icmp6.h>
87 #include <netinet6/ip6_var.h>
88 #include <netinet6/pim6_var.h>
89 #endif
90 
91 #include <uvm/uvm_swap_encrypt.h>
92 
93 #include <ufs/ufs/quota.h>
94 #include <ufs/ufs/inode.h>
95 #include <ufs/ffs/fs.h>
96 #include <ufs/ffs/ffs_extern.h>
97 
98 #include <nfs/rpcv2.h>
99 #include <nfs/nfsproto.h>
100 #include <nfs/nfs.h>
101 
102 #include <netipx/ipx.h>
103 #include <netipx/ipx_var.h>
104 #include <netipx/spx_var.h>
105 #include <ddb/db_var.h>
106 #include <dev/rndvar.h>
107 
108 #include <err.h>
109 #include <errno.h>
110 #include <stdio.h>
111 #include <stdlib.h>
112 #include <string.h>
113 #include <ctype.h>
114 
115 #ifdef CPU_BIOS
116 #include <machine/biosvar.h>
117 #endif
118 
119 struct ctlname topname[] = CTL_NAMES;
120 struct ctlname kernname[] = CTL_KERN_NAMES;
121 struct ctlname vmname[] = CTL_VM_NAMES;
122 struct ctlname fsname[] = CTL_FS_NAMES;
123 struct ctlname netname[] = CTL_NET_NAMES;
124 struct ctlname hwname[] = CTL_HW_NAMES;
125 struct ctlname username[] = CTL_USER_NAMES;
126 struct ctlname debugname[CTL_DEBUG_MAXID];
127 struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
128 struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
129 struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
130 struct ctlname ttyname[] = CTL_KERN_TTY_NAMES;
131 struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES;
132 struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES;
133 struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES;
134 struct ctlname *vfsname;
135 #ifdef CTL_MACHDEP_NAMES
136 struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
137 #endif
138 struct ctlname ddbname[] = CTL_DDB_NAMES;
139 char names[BUFSIZ];
140 int lastused;
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 	{ username, USER_MAXID },	/* CTL_USER_NAMES */
161 	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
162 	{ 0, 0 },			/* CTL_VFS */
163 };
164 
165 int	Aflag, aflag, nflag, qflag, wflag;
166 
167 /*
168  * Variables requiring special processing.
169  */
170 #define	CLOCK		0x00000001
171 #define	BOOTTIME	0x00000002
172 #define	CHRDEV		0x00000004
173 #define	BLKDEV		0x00000008
174 #define	RNDSTATS	0x00000010
175 #define	BADDYNAMIC	0x00000020
176 #define	BIOSGEO		0x00000040
177 #define	BIOSDEV		0x00000080
178 #define	MAJ2DEV		0x00000100
179 #define	UNSIGNED	0x00000200
180 #define	KMEMBUCKETS	0x00000400
181 #define	LONGARRAY	0x00000800
182 #define	KMEMSTATS	0x00001000
183 #define	SENSORS		0x00002000
184 
185 /* prototypes */
186 void debuginit(void);
187 void listall(char *, struct list *);
188 void parse(char *, int);
189 void parse_baddynamic(int *, size_t, char *, void **, size_t *, int, int);
190 void usage(void);
191 int findname(char *, char *, char **, struct list *);
192 int sysctl_inet(char *, char **, int *, int, int *);
193 #ifdef INET6
194 int sysctl_inet6(char *, char **, int *, int, int *);
195 #endif
196 int sysctl_ipx(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_sensors(char *, char **, int *, int, int *);
210 int sysctl_emul(char *, char *, int);
211 #ifdef CPU_CHIPSET
212 int sysctl_chipset(char *, char **, int *, int, int *);
213 #endif
214 void vfsinit(void);
215 
216 int
217 main(int argc, char *argv[])
218 {
219 	int ch, lvl1;
220 
221 	while ((ch = getopt(argc, argv, "Aanqw")) != -1) {
222 		switch (ch) {
223 
224 		case 'A':
225 			Aflag = 1;
226 			break;
227 
228 		case 'a':
229 			aflag = 1;
230 			break;
231 
232 		case 'n':
233 			nflag = 1;
234 			break;
235 
236 		case 'q':
237 			qflag = 1;
238 			break;
239 
240 		case 'w':
241 			wflag = 1;
242 			break;
243 
244 		default:
245 			usage();
246 		}
247 	}
248 	argc -= optind;
249 	argv += optind;
250 
251 	if (argc == 0 && (Aflag || aflag)) {
252 		debuginit();
253 		vfsinit();
254 		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
255 			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
256 		return (0);
257 	}
258 	if (argc == 0)
259 		usage();
260 	for (; *argv != NULL; ++argv)
261 		parse(*argv, 1);
262 	return (0);
263 }
264 
265 /*
266  * List all variables known to the system.
267  */
268 void
269 listall(char *prefix, struct list *lp)
270 {
271 	char *cp, name[BUFSIZ];
272 	int lvl2, len;
273 
274 	if (lp->list == NULL)
275 		return;
276 	if ((len = strlcpy(name, prefix, sizeof(name))) >= sizeof(name))
277 		warn("%s: name too long", prefix);
278 	cp = name + len++;
279 	*cp++ = '.';
280 	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
281 		if (lp->list[lvl2].ctl_name == NULL)
282 			continue;
283 		if (strlcpy(cp, lp->list[lvl2].ctl_name,
284 		    sizeof(name) - len) >= sizeof(name) - len)
285 			warn("%s: name too long", lp->list[lvl2].ctl_name);
286 		parse(name, Aflag);
287 	}
288 }
289 
290 /*
291  * Parse a name into a MIB entry.
292  * Lookup and print out the MIB entry if it exists.
293  * Set a new value if requested.
294  */
295 void
296 parse(char *string, int flags)
297 {
298 	int indx, type, state, intval, len;
299 	size_t size, newsize = 0;
300 	int lal = 0, special = 0;
301 	void *newval = 0;
302 	int64_t quadval;
303 	struct list *lp;
304 	int mib[CTL_MAXNAME];
305 	char *cp, *bufp, buf[BUFSIZ];
306 
307 	(void)strlcpy(buf, string, sizeof(buf));
308 	bufp = buf;
309 	if ((cp = strchr(string, '=')) != NULL) {
310 		if (!wflag)
311 			errx(2, "must specify -w to set variables");
312 		*strchr(buf, '=') = '\0';
313 		*cp++ = '\0';
314 		while (isspace(*cp))
315 			cp++;
316 		newval = cp;
317 		newsize = strlen(cp);
318 	}
319 	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
320 		return;
321 	mib[0] = indx;
322 	if (indx == CTL_VFS)
323 		vfsinit();
324 	if (indx == CTL_DEBUG)
325 		debuginit();
326 	lp = &secondlevel[indx];
327 	if (lp->list == 0) {
328 		warnx("%s: class is not implemented", topname[indx].ctl_name);
329 		return;
330 	}
331 	if (bufp == NULL) {
332 		listall(topname[indx].ctl_name, lp);
333 		return;
334 	}
335 	if ((indx = findname(string, "second", &bufp, lp)) == -1)
336 		return;
337 	mib[1] = indx;
338 	type = lp->list[indx].ctl_type;
339 	len = 2;
340 	switch (mib[0]) {
341 
342 	case CTL_KERN:
343 		switch (mib[1]) {
344 		case KERN_PROF:
345 			mib[2] = GPROF_STATE;
346 			size = sizeof(state);
347 			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
348 				if (flags == 0)
349 					return;
350 				if (!nflag)
351 					(void)printf("%s: ", string);
352 				(void)puts("kernel is not compiled for profiling");
353 				return;
354 			}
355 			if (!nflag)
356 				(void)printf("%s = %s\n", string,
357 				    state == GMON_PROF_OFF ? "off" : "running");
358 			return;
359 		case KERN_FORKSTAT:
360 			sysctl_forkstat(string, &bufp, mib, flags, &type);
361 			return;
362 		case KERN_TTY:
363 			len = sysctl_tty(string, &bufp, mib, flags, &type);
364 			if (len < 0)
365 				return;
366 			newsize = 0;
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_VNODE:
392 		case KERN_FILE:
393 			if (flags == 0)
394 				return;
395 			warnx("use pstat to view %s information", string);
396 			return;
397 		case KERN_PROC:
398 			if (flags == 0)
399 				return;
400 			warnx("use ps to view %s information", string);
401 			return;
402 		case KERN_CLOCKRATE:
403 			special |= CLOCK;
404 			break;
405 		case KERN_BOOTTIME:
406 			special |= BOOTTIME;
407 			break;
408 		case KERN_RND:
409 			special |= RNDSTATS;
410 			break;
411 		case KERN_HOSTID:
412 		case KERN_ARND:
413 			special |= UNSIGNED;
414 			break;
415 		case KERN_CPTIME:
416 			special |= LONGARRAY;
417 			lal = CPUSTATES;
418 			break;
419 		case KERN_SEMINFO:
420 			len = sysctl_seminfo(string, &bufp, mib, flags, &type);
421 			if (len < 0)
422 				return;
423 			break;
424 		case KERN_SHMINFO:
425 			len = sysctl_shminfo(string, &bufp, mib, flags, &type);
426 			if (len < 0)
427 				return;
428 			break;
429 		case KERN_WATCHDOG:
430 			len = sysctl_watchdog(string, &bufp, mib, flags,
431 			    &type);
432 			if (len < 0)
433 				return;
434 			break;
435 		case KERN_EMUL:
436 			sysctl_emul(string, newval, flags);
437 			return;
438 		}
439 		break;
440 
441 	case CTL_HW:
442 		switch (mib[1]) {
443 		case HW_DISKSTATS:
444 			/*
445 			 * Only complain if someone asks explicitly for this,
446 			 * otherwise "fail" silently.
447 			 */
448 			if (flags)
449 				warnx("use vmstat to view %s information",
450 				    string);
451 			return;
452 		case HW_SENSORS:
453 			special |= SENSORS;
454 			len = sysctl_sensors(string, &bufp, mib, flags, &type);
455 			if (len < 0)
456 				return;
457 			break;
458 		}
459 		break;
460 
461 	case CTL_VM:
462 		if (mib[1] == VM_LOADAVG) {
463 			double loads[3];
464 
465 			getloadavg(loads, 3);
466 			if (!nflag)
467 				(void)printf("%s = ", string);
468 			(void)printf("%.2f %.2f %.2f\n", loads[0],
469 			    loads[1], loads[2]);
470 			return;
471 		} else if (mib[1] == VM_PSSTRINGS) {
472 			struct _ps_strings _ps;
473 
474 			size = sizeof(_ps);
475 			if (sysctl(mib, 2, &_ps, &size, NULL, 0) == -1) {
476 				if (flags == 0)
477 					return;
478 				if (!nflag)
479 					(void)printf("%s: ", string);
480 				(void)puts("can't find ps strings");
481 				return;
482 			}
483 			if (!nflag)
484 				(void)printf("%s = ", string);
485 			(void)printf("%p\n", _ps.val);
486 			return;
487 		} else if (mib[1] == VM_SWAPENCRYPT) {
488 			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
489 			if (len < 0)
490 				return;
491 
492 			break;
493 		} else if (mib[1] == VM_NKMEMPAGES ||
494 		    mib[1] == VM_ANONMIN ||
495 		    mib[1] == VM_VTEXTMIN ||
496 		    mib[1] == VM_VNODEMIN) {
497 			break;
498 		}
499 		if (flags == 0)
500 			return;
501 		warnx("use vmstat or systat to view %s information", string);
502 		return;
503 
504 		break;
505 
506 	case CTL_NET:
507 		if (mib[1] == PF_INET) {
508 			len = sysctl_inet(string, &bufp, mib, flags, &type);
509 			if (len < 0)
510 				return;
511 
512 			if ((mib[2] == IPPROTO_TCP &&
513 			     mib[3] == TCPCTL_BADDYNAMIC) ||
514 			    (mib[2] == IPPROTO_UDP &&
515 			     mib[3] == UDPCTL_BADDYNAMIC)) {
516 
517 				special |= BADDYNAMIC;
518 
519 				if (newval != NULL)
520 					parse_baddynamic(mib, len, string,
521 					    &newval, &newsize, flags, nflag);
522 			}
523 			break;
524 		}
525 #ifdef INET6
526 		if (mib[1] == PF_INET6) {
527 			len = sysctl_inet6(string, &bufp, mib, flags, &type);
528 			if (len < 0)
529 				return;
530 
531 			break;
532 		}
533 #endif
534 		if (mib[1] == PF_IPX) {
535 			len = sysctl_ipx(string, &bufp, mib, flags, &type);
536 			if (len >= 0)
537 				break;
538 			return;
539 		}
540 		if (flags == 0)
541 			return;
542 		warnx("use netstat to view %s information", string);
543 		return;
544 
545 	case CTL_DEBUG:
546 		mib[2] = CTL_DEBUG_VALUE;
547 		len = 3;
548 		break;
549 
550 	case CTL_MACHDEP:
551 #ifdef CPU_CONSDEV
552 		if (mib[1] == CPU_CONSDEV)
553 			special |= CHRDEV;
554 #endif
555 #ifdef CPU_BLK2CHR
556 		if (mib[1] == CPU_BLK2CHR) {
557 			if (bufp == NULL)
558 				return;
559 			mib[2] = makedev(atoi(bufp),0);
560 			bufp = NULL;
561 			len = 3;
562 			special |= CHRDEV;
563 			break;
564 		}
565 #endif
566 #ifdef CPU_CHR2BLK
567 		if (mib[1] == CPU_CHR2BLK) {
568 			if (bufp == NULL)
569 				return;
570 			mib[2] = makedev(atoi(bufp),0);
571 			bufp = NULL;
572 			len = 3;
573 			special |= BLKDEV;
574 			break;
575 		}
576 #endif
577 #ifdef CPU_BIOS
578 		if (mib[1] == CPU_BIOS) {
579 			len = sysctl_bios(string, &bufp, mib, flags, &type);
580 			if (len < 0)
581 				return;
582 			if (mib[2] == BIOS_DEV)
583 				special |= BIOSDEV;
584 			if (mib[2] == BIOS_DISKINFO)
585 				special |= BIOSGEO;
586 			break;
587 		}
588 #endif
589 #ifdef CPU_CHIPSET
590 		if (mib[1] == CPU_CHIPSET) {
591 			len = sysctl_chipset(string, &bufp, mib, flags, &type);
592 			if (len < 0)
593 				return;
594 			break;
595 		}
596 #endif
597 #ifdef CPU_LONGRUN
598 		if (mib[1] == CPU_LONGRUN)
599 			return;
600 #endif
601 
602 		break;
603 
604 	case CTL_FS:
605 		len = sysctl_fs(string, &bufp, mib, flags, &type);
606 		if (len >= 0)
607 			break;
608 		return;
609 
610 	case CTL_VFS:
611 		if (mib[1])
612 			len = sysctl_vfs(string, &bufp, mib, flags, &type);
613 		else
614 			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
615 		if (len >= 0) {
616 			if (type == CTLTYPE_STRUCT) {
617 				if (flags)
618 					warnx("use nfsstat to view %s information",
619 					    MOUNT_NFS);
620 				return;
621 			} else
622 				break;
623 		}
624 		return;
625 
626 	case CTL_USER:
627 	case CTL_DDB:
628 		break;
629 
630 	default:
631 		warnx("illegal top level value: %d", mib[0]);
632 		return;
633 
634 	}
635 	if (bufp) {
636 		warnx("name %s in %s is unknown", bufp, string);
637 		return;
638 	}
639 	if (newsize > 0) {
640 		switch (type) {
641 		case CTLTYPE_INT:
642 			errno = 0;
643 			if (special & UNSIGNED)
644 				intval = strtoul(newval, &cp, 10);
645 			else
646 				intval = strtol(newval, &cp, 10);
647 			if (*cp != '\0') {
648 				warnx("%s: illegal value: %s", string,
649 				    (char *)newval);
650 				return;
651 			}
652 			if (errno == ERANGE) {
653 				warnx("%s: value %s out of range", string,
654 				    (char *)newval);
655 				return;
656 			}
657 			newval = &intval;
658 			newsize = sizeof(intval);
659 			break;
660 
661 		case CTLTYPE_QUAD:
662 			/* XXX - assumes sizeof(long long) == sizeof(quad_t) */
663 			(void)sscanf(newval, "%lld", (long long *)&quadval);
664 			newval = &quadval;
665 			newsize = sizeof(quadval);
666 			break;
667 		}
668 	}
669 	size = BUFSIZ;
670 	if (sysctl(mib, len, buf, &size, newval, newsize) == -1) {
671 		if (flags == 0)
672 			return;
673 		switch (errno) {
674 		case EOPNOTSUPP:
675 			warnx("%s: value is not available", string);
676 			return;
677 		case ENOTDIR:
678 			warnx("%s: specification is incomplete", string);
679 			return;
680 		case ENOMEM:
681 			warnx("%s: type is unknown to this program", string);
682 			return;
683 		case ENXIO:
684 			if (special & BIOSGEO)
685 				return;
686 		default:
687 			warn("%s", string);
688 			return;
689 		}
690 	}
691 	if (special & KMEMBUCKETS) {
692 		struct kmembuckets *kb = (struct kmembuckets *)buf;
693 		if (!nflag)
694 			(void)printf("%s = ", string);
695 		printf("(");
696 		printf("calls = %llu ", (long long)kb->kb_calls);
697 		printf("total_allocated = %llu ", (long long)kb->kb_total);
698 		printf("total_free = %lld ", (long long)kb->kb_totalfree);
699 		printf("elements = %lld ", (long long)kb->kb_elmpercl);
700 		printf("high watermark = %lld ", (long long)kb->kb_highwat);
701 		printf("could_free = %lld", (long long)kb->kb_couldfree);
702 		printf(")\n");
703 		return;
704 	}
705 	if (special & KMEMSTATS) {
706 		struct kmemstats *km = (struct kmemstats *)buf;
707 		int j, first = 1;
708 
709 		if (!nflag)
710 			(void)printf("%s = ", string);
711 		(void)printf("(inuse = %ld, calls = %ld, memuse = %ldK, "
712 		    "limblocks = %d, mapblocks = %d, maxused = %ldK, "
713 		    "limit = %ldK, spare = %ld, sizes = (",
714 		    km->ks_inuse, km->ks_calls,
715 		    (km->ks_memuse + 1023) / 1024, km->ks_limblocks,
716 		    km->ks_mapblocks, (km->ks_maxused + 1023) / 1024,
717 		    (km->ks_limit + 1023) / 1024, km->ks_spare);
718 		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
719 			if ((km->ks_size & j ) == 0)
720 				continue;
721 			if (first)
722 				(void)printf("%d", j);
723 			else
724 				(void)printf(",%d", j);
725 			first = 0;
726 		}
727 		if (first)
728 			(void)printf("none");
729 		(void)printf("))\n");
730 		return;
731 	}
732 	if (special & CLOCK) {
733 		struct clockinfo *clkp = (struct clockinfo *)buf;
734 
735 		if (!nflag)
736 			(void)printf("%s = ", string);
737 		(void)printf(
738 		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
739 		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
740 		return;
741 	}
742 	if (special & BOOTTIME) {
743 		struct timeval *btp = (struct timeval *)buf;
744 		time_t boottime;
745 
746 		if (!nflag) {
747 			boottime = btp->tv_sec;
748 			(void)printf("%s = %s", string, ctime(&boottime));
749 		} else
750 			(void)printf("%ld\n", btp->tv_sec);
751 		return;
752 	}
753 	if (special & BLKDEV) {
754 		dev_t dev = *(dev_t *)buf;
755 
756 		if (!nflag)
757 			(void)printf("%s = %s\n", string,
758 			    devname(dev, S_IFBLK));
759 		else
760 			(void)printf("0x%x\n", dev);
761 		return;
762 	}
763 	if (special & CHRDEV) {
764 		dev_t dev = *(dev_t *)buf;
765 
766 		if (!nflag)
767 			(void)printf("%s = %s\n", string,
768 			    devname(dev, S_IFCHR));
769 		else
770 			(void)printf("0x%x\n", dev);
771 		return;
772 	}
773 #ifdef CPU_BIOS
774 	if (special & BIOSGEO) {
775 		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
776 
777 		if (!nflag)
778 			(void)printf("%s = ", string);
779 		(void)printf("bootdev = 0x%x, "
780 			     "cylinders = %u, heads = %u, sectors = %u\n",
781 			     pdi->bsd_dev, pdi->bios_cylinders,
782 			     pdi->bios_heads, pdi->bios_sectors);
783 		return;
784 	}
785 	if (special & BIOSDEV) {
786 		int dev = *(int*)buf;
787 
788 		if (!nflag)
789 			(void)printf("%s = ", string);
790 		(void) printf("0x%02x\n", dev);
791 		return;
792 	}
793 #endif
794 	if (special & UNSIGNED) {
795 		if (newsize == 0) {
796 			if (!nflag)
797 				(void)printf("%s = ", string);
798 			(void)printf("%u\n", *(u_int *)buf);
799 		} else {
800 			if (!qflag) {
801 				if (!nflag)
802 					(void)printf("%s: %u -> ", string,
803 					    *(u_int *)buf);
804 				(void)printf("%u\n", *(u_int *)newval);
805 			}
806 		}
807 		return;
808 	}
809 	if (special & RNDSTATS) {
810 		struct rndstats *rndstats = (struct rndstats *)buf;
811 		int i;
812 
813 		if (!nflag)
814 			(void)printf("%s = ", string);
815 		(void)printf(
816 		"%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
817 		    (unsigned long long)rndstats->rnd_total,
818 		    (unsigned long long)rndstats->rnd_used,
819 		    (unsigned long long)rndstats->rnd_reads,
820 		    (unsigned long long)rndstats->arc4_reads,
821 		    (unsigned long long)rndstats->arc4_nstirs,
822 		    (unsigned long long)rndstats->arc4_stirs,
823 		    (unsigned long long)rndstats->rnd_pad[0],
824 		    (unsigned long long)rndstats->rnd_pad[1],
825 		    (unsigned long long)rndstats->rnd_pad[2],
826 		    (unsigned long long)rndstats->rnd_pad[3],
827 		    (unsigned long long)rndstats->rnd_pad[4],
828 		    (unsigned long long)rndstats->rnd_waits,
829 		    (unsigned long long)rndstats->rnd_enqs,
830 		    (unsigned long long)rndstats->rnd_deqs,
831 		    (unsigned long long)rndstats->rnd_drops,
832 		    (unsigned long long)rndstats->rnd_drople);
833 		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]);
834 		    i++)
835 			(void)printf(" %llu", (unsigned long long)rndstats->rnd_ed[i]);
836 		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]);
837 		    i++)
838 			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sc[i]);
839 		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]);
840 		    i++)
841 			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sb[i]);
842 		printf("\n");
843 		return;
844 	}
845 	if (special & BADDYNAMIC) {
846 		in_port_t port, lastport;
847 		u_int32_t *baddynamic = (u_int32_t *)buf;
848 
849 		if (!qflag) {
850 			if (!nflag)
851 				(void)printf("%s%s", string,
852 				    newsize ? ": " : " = ");
853 			lastport = 0;
854 			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
855 			    port++)
856 				if (DP_ISSET(baddynamic, port)) {
857 					(void)printf("%s%hd",
858 					    lastport ? "," : "", port);
859 					lastport = port;
860 				}
861 			if (newsize != 0) {
862 				if (!nflag)
863 					fputs(" -> ", stdout);
864 				baddynamic = (u_int32_t *)newval;
865 				lastport = 0;
866 				for (port = IPPORT_RESERVED/2;
867 				    port < IPPORT_RESERVED; port++)
868 					if (DP_ISSET(baddynamic, port)) {
869 						(void)printf("%s%hd",
870 						    lastport ? "," : "", port);
871 						lastport = port;
872 					}
873 			}
874 			(void)putchar('\n');
875 		}
876 		return;
877 	}
878 	if (special & LONGARRAY) {
879 		long *la = (long *)buf;
880 		if (!nflag)
881 			printf("%s = ", string);
882 		while (lal--)
883 			printf("%ld%s", *la++, lal? ",":"");
884 		putchar('\n');
885 		return;
886 	}
887 	if (special & SENSORS) {
888 		struct sensor *s = (struct sensor *)buf;
889 
890 		if (size > 0) {
891 			if (!nflag)
892 				printf("%s = ", string);
893 			printf("%s, %s, ", s->device, s->desc);
894 			switch (s->type) {
895 			case SENSOR_TEMP:
896 				printf("temp, %.2f degC / %.2f degF",
897 				    (s->value / 1000000.0) - 273.16,
898 				    ((s->value / 1000000.0) - 273.16) * 9 / 5 +
899 				    32);
900 				break;
901 			case SENSOR_FANRPM:
902 				printf("fanrpm, %lld RPM", s->value);
903 				break;
904 			case SENSOR_VOLTS_DC:
905 				printf("volts_dc, %.2f V",
906 				    s->value / 1000000.0);
907 				break;
908 			default:
909 				printf("unknown");
910 			}
911 			printf("\n");
912 		}
913 		return;
914 	}
915 
916 	switch (type) {
917 	case CTLTYPE_INT:
918 		if (newsize == 0) {
919 			if (!nflag)
920 				(void)printf("%s = ", string);
921 			(void)printf("%d\n", *(int *)buf);
922 		} else {
923 			if (!qflag) {
924 				if (!nflag)
925 					(void)printf("%s: %d -> ", string,
926 					    *(int *)buf);
927 				(void)printf("%d\n", *(int *)newval);
928 			}
929 		}
930 		return;
931 
932 	case CTLTYPE_STRING:
933 		if (newval == NULL) {
934 			if (!nflag)
935 				(void)printf("%s = ", string);
936 			(void)puts(buf);
937 		} else {
938 			if (!qflag) {
939 				if (!nflag)
940 					(void)printf("%s: %s -> ", string, buf);
941 				(void)puts((char *)newval);
942 			}
943 		}
944 		return;
945 
946 	case CTLTYPE_QUAD:
947 		if (newsize == 0) {
948 			long long tmp = *(quad_t *)buf;
949 
950 			if (!nflag)
951 				(void)printf("%s = ", string);
952 			(void)printf("%lld\n", tmp);
953 		} else {
954 			long long tmp = *(quad_t *)buf;
955 
956 			if (!qflag) {
957 				if (!nflag)
958 					(void)printf("%s: %lld -> ",
959 					    string, tmp);
960 				tmp = *(quad_t *)newval;
961 				(void)printf("%qd\n", tmp);
962 			}
963 		}
964 		return;
965 
966 	case CTLTYPE_STRUCT:
967 		warnx("%s: unknown structure returned", string);
968 		return;
969 
970 	default:
971 	case CTLTYPE_NODE:
972 		warnx("%s: unknown type returned", string);
973 		return;
974 	}
975 }
976 
977 void
978 parse_baddynamic(int mib[], size_t len, char *string, void **newvalp,
979     size_t *newsizep, int flags, int nflag)
980 {
981 	static u_int32_t newbaddynamic[DP_MAPSIZE];
982 	in_port_t port;
983 	size_t size;
984 	char action, *cp;
985 
986 	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
987 		size = sizeof(newbaddynamic);
988 		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
989 			if (flags == 0)
990 				return;
991 			if (!nflag)
992 				(void)printf("%s: ", string);
993 			(void)puts("kernel does contain bad dynamic port tables");
994 			return;
995 		}
996 
997 		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
998 			if (*cp != '+' && *cp != '-')
999 				errx(1, "cannot mix +/- with full list");
1000 			action = *cp++;
1001 			port = atoi(cp);
1002 			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
1003 				errx(1, "invalid port, range is %d to %d",
1004 				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
1005 			if (action == '+')
1006 				DP_SET(newbaddynamic, port);
1007 			else
1008 				DP_CLR(newbaddynamic, port);
1009 		}
1010 	} else {
1011 		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
1012 		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1013 			port = atoi(cp);
1014 			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
1015 				errx(1, "invalid port, range is %d to %d",
1016 				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
1017 			DP_SET(newbaddynamic, port);
1018 		}
1019 	}
1020 
1021 	*newvalp = (void *)newbaddynamic;
1022 	*newsizep = sizeof(newbaddynamic);
1023 }
1024 
1025 /*
1026  * Initialize the set of debugging names
1027  */
1028 void
1029 debuginit(void)
1030 {
1031 	int mib[3], loc, i;
1032 	size_t size;
1033 
1034 	if (secondlevel[CTL_DEBUG].list != 0)
1035 		return;
1036 	secondlevel[CTL_DEBUG].list = debugname;
1037 	mib[0] = CTL_DEBUG;
1038 	mib[2] = CTL_DEBUG_NAME;
1039 	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
1040 		mib[1] = i;
1041 		size = BUFSIZ - loc;
1042 		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
1043 			continue;
1044 		debugname[i].ctl_name = &names[loc];
1045 		debugname[i].ctl_type = CTLTYPE_INT;
1046 		loc += size;
1047 	}
1048 	lastused = loc;
1049 }
1050 
1051 struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
1052 struct ctlname ffsname[] = FFS_NAMES;
1053 struct ctlname nfsname[] = FS_NFS_NAMES;
1054 struct list *vfsvars;
1055 int *vfs_typenums;
1056 
1057 /*
1058  * Initialize the set of filesystem names
1059  */
1060 void
1061 vfsinit(void)
1062 {
1063 	int mib[4], maxtypenum, cnt, loc, size;
1064 	struct vfsconf vfc;
1065 	size_t buflen;
1066 
1067 	if (secondlevel[CTL_VFS].list != 0)
1068 		return;
1069 	mib[0] = CTL_VFS;
1070 	mib[1] = VFS_GENERIC;
1071 	mib[2] = VFS_MAXTYPENUM;
1072 	buflen = 4;
1073 	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
1074 		return;
1075 	maxtypenum++;	/* + generic */
1076 	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
1077 		return;
1078 	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
1079 	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
1080 		free(vfs_typenums);
1081 		return;
1082 	}
1083 	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
1084 	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
1085 		free(vfs_typenums);
1086 		free(vfsvars);
1087 		return;
1088 	}
1089 	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
1090 	mib[2] = VFS_CONF;
1091 	buflen = sizeof vfc;
1092 	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
1093 		mib[3] = cnt - 1;
1094 		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
1095 			if (errno == EOPNOTSUPP)
1096 				continue;
1097 			warn("vfsinit");
1098 			free(vfsname);
1099 			return;
1100 		}
1101 		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1102 			vfsvars[cnt].list = ffsname;
1103 			vfsvars[cnt].size = FFS_MAXID;
1104 		}
1105 		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1106 			vfsvars[cnt].list = nfsname;
1107 			vfsvars[cnt].size = NFS_MAXID;
1108 		}
1109 		vfs_typenums[cnt] = vfc.vfc_typenum;
1110 		strlcat(&names[loc], vfc.vfc_name, sizeof names - loc);
1111 		vfsname[cnt].ctl_name = &names[loc];
1112 		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1113 		size = strlen(vfc.vfc_name) + 1;
1114 		loc += size;
1115 	}
1116 	lastused = loc;
1117 
1118 	vfsname[0].ctl_name = "mounts";
1119 	vfsname[0].ctl_type = CTLTYPE_NODE;
1120 	vfsvars[0].list = vfsname + 1;
1121 	vfsvars[0].size = maxtypenum - 1;
1122 
1123 	secondlevel[CTL_VFS].list = vfsname;
1124 	secondlevel[CTL_VFS].size = maxtypenum;
1125 	return;
1126 }
1127 
1128 int
1129 sysctl_vfsgen(char *string, char **bufpp, int mib[], int flags, int *typep)
1130 {
1131 	int indx;
1132 	size_t size;
1133 	struct vfsconf vfc;
1134 
1135 	if (*bufpp == NULL) {
1136 		listall(string, vfsvars);
1137 		return (-1);
1138 	}
1139 
1140 	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1141 		return (-1);
1142 
1143 	mib[1] = VFS_GENERIC;
1144 	mib[2] = VFS_CONF;
1145 	mib[3] = indx;
1146 	size = sizeof vfc;
1147 	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
1148 		if (errno != EOPNOTSUPP)
1149 			warn("vfs print");
1150 		return -1;
1151 	}
1152 	if (flags == 0 && vfc.vfc_refcount == 0)
1153 		return -1;
1154 	if (!nflag)
1155 		fprintf(stdout, "%s has %d mounted instance%s\n",
1156 		    string, vfc.vfc_refcount,
1157 		    vfc.vfc_refcount != 1 ? "s" : "");
1158 	else
1159 		fprintf(stdout, "%d\n", vfc.vfc_refcount);
1160 
1161 	return -1;
1162 }
1163 
1164 int
1165 sysctl_vfs(char *string, char **bufpp, int mib[], int flags, int *typep)
1166 {
1167 	struct list *lp = &vfsvars[mib[1]];
1168 	int indx;
1169 
1170 	if (lp->list == NULL) {
1171 		if (flags)
1172 			warnx("No variables defined for file system %s", string);
1173 		return (-1);
1174 	}
1175 	if (*bufpp == NULL) {
1176 		listall(string, lp);
1177 		return (-1);
1178 	}
1179 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1180 		return (-1);
1181 
1182 	mib[1] = vfs_typenums[mib[1]];
1183 	mib[2] = indx;
1184 	*typep = lp->list[indx].ctl_type;
1185 	return (3);
1186 }
1187 
1188 struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1189 struct list fslist = { posixname, FS_POSIX_MAXID };
1190 
1191 /*
1192  * handle file system requests
1193  */
1194 int
1195 sysctl_fs(char *string, char **bufpp, int mib[], int flags, int *typep)
1196 {
1197 	int indx;
1198 
1199 	if (*bufpp == NULL) {
1200 		listall(string, &fslist);
1201 		return (-1);
1202 	}
1203 	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1204 		return (-1);
1205 	mib[2] = indx;
1206 	*typep = fslist.list[indx].ctl_type;
1207 	return (3);
1208 }
1209 
1210 #ifdef CPU_BIOS
1211 struct ctlname biosname[] = CTL_BIOS_NAMES;
1212 struct list bioslist = { biosname, BIOS_MAXID };
1213 
1214 /*
1215  * handle BIOS requests
1216  */
1217 int
1218 sysctl_bios(char *string, char **bufpp, int mib[], int flags, int *typep)
1219 {
1220 	char *name;
1221 	int indx;
1222 
1223 	if (*bufpp == NULL) {
1224 		listall(string, &bioslist);
1225 		return (-1);
1226 	}
1227 	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1228 		return (-1);
1229 	mib[2] = indx;
1230 	if (indx == BIOS_DISKINFO) {
1231 		if (*bufpp == NULL) {
1232 			char name[BUFSIZ];
1233 
1234 			/* scan all the bios devices */
1235 			for (indx = 0; indx < 256; indx++) {
1236 				snprintf(name, sizeof(name), "%s.%u",
1237 					 string, indx);
1238 				parse(name, 1);
1239 			}
1240 			return (-1);
1241 		}
1242 		if ((name = strsep(bufpp, ".")) == NULL) {
1243 			warnx("%s: incomplete specification", string);
1244 			return (-1);
1245 		}
1246 		mib[3] = atoi(name);
1247 		*typep = CTLTYPE_STRUCT;
1248 		return (4);
1249 	} else {
1250 		*typep = bioslist.list[indx].ctl_type;
1251 		return (3);
1252 	}
1253 }
1254 #endif
1255 
1256 struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1257 struct list swpenclist = { swpencname, SWPENC_MAXID };
1258 
1259 /*
1260  * handle swap encrypt requests
1261  */
1262 int
1263 sysctl_swpenc(char *string, char **bufpp, int mib[], int flags, int *typep)
1264 {
1265 	int indx;
1266 
1267 	if (*bufpp == NULL) {
1268 		listall(string, &swpenclist);
1269 		return (-1);
1270 	}
1271 	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1272 		return (-1);
1273 	mib[2] = indx;
1274 	*typep = swpenclist.list[indx].ctl_type;
1275 	return (3);
1276 }
1277 
1278 struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1279 struct ctlname ipname[] = IPCTL_NAMES;
1280 struct ctlname icmpname[] = ICMPCTL_NAMES;
1281 struct ctlname ipipname[] = IPIPCTL_NAMES;
1282 struct ctlname tcpname[] = TCPCTL_NAMES;
1283 struct ctlname udpname[] = UDPCTL_NAMES;
1284 struct ctlname espname[] = ESPCTL_NAMES;
1285 struct ctlname ahname[] = AHCTL_NAMES;
1286 struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1287 struct ctlname grename[] = GRECTL_NAMES;
1288 struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1289 struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1290 struct ctlname carpname[] = CARPCTL_NAMES;
1291 struct list inetlist = { inetname, IPPROTO_MAXID };
1292 struct list inetvars[] = {
1293 	{ ipname, IPCTL_MAXID },	/* ip */
1294 	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1295 	{ 0, 0 },			/* igmp */
1296 	{ 0, 0 },			/* ggmp */
1297 	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1298 	{ 0, 0 },
1299 	{ tcpname, TCPCTL_MAXID },	/* tcp */
1300 	{ 0, 0 },
1301 	{ 0, 0 },			/* egp */
1302 	{ 0, 0 },
1303 	{ 0, 0 },
1304 	{ 0, 0 },
1305 	{ 0, 0 },			/* pup */
1306 	{ 0, 0 },
1307 	{ 0, 0 },
1308 	{ 0, 0 },
1309 	{ 0, 0 },
1310 	{ udpname, UDPCTL_MAXID },	/* udp */
1311 	{ 0, 0 },
1312 	{ 0, 0 },
1313 	{ 0, 0 },
1314 	{ 0, 0 },
1315 	{ 0, 0 },
1316 	{ 0, 0 },
1317 	{ 0, 0 },
1318 	{ 0, 0 },
1319 	{ 0, 0 },
1320 	{ 0, 0 },
1321 	{ 0, 0 },
1322 	{ 0, 0 },
1323 	{ 0, 0 },
1324 	{ 0, 0 },
1325 	{ 0, 0 },
1326 	{ 0, 0 },
1327 	{ 0, 0 },
1328 	{ 0, 0 },
1329 	{ 0, 0 },
1330 	{ 0, 0 },
1331 	{ 0, 0 },
1332 	{ 0, 0 },
1333 	{ 0, 0 },
1334 	{ 0, 0 },
1335 	{ 0, 0 },
1336 	{ 0, 0 },
1337 	{ 0, 0 },
1338 	{ 0, 0 },
1339 	{ 0, 0 },
1340 	{ grename, GRECTL_MAXID }, /* GRE */
1341 	{ 0, 0 },
1342 	{ 0, 0 },
1343 	{ espname, ESPCTL_MAXID },	/* esp */
1344 	{ ahname, AHCTL_MAXID },	/* ah */
1345 	{ 0, 0 },
1346 	{ 0, 0 },
1347 	{ 0, 0 },
1348 	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1349 	{ 0, 0 },
1350 	{ 0, 0 },
1351 	{ 0, 0 },
1352 	{ 0, 0 },
1353 	{ 0, 0 },
1354 	{ 0, 0 },
1355 	{ 0, 0 },
1356 	{ 0, 0 },
1357 	{ 0, 0 },
1358 	{ 0, 0 },
1359 	{ 0, 0 },
1360 	{ 0, 0 },
1361 	{ 0, 0 },
1362 	{ 0, 0 },
1363 	{ 0, 0 },
1364 	{ 0, 0 },
1365 	{ 0, 0 },
1366 	{ 0, 0 },
1367 	{ 0, 0 },
1368 	{ 0, 0 },
1369 	{ 0, 0 },
1370 	{ 0, 0 },
1371 	{ 0, 0 },
1372 	{ 0, 0 },
1373 	{ 0, 0 },
1374 	{ 0, 0 },
1375 	{ 0, 0 },
1376 	{ 0, 0 },
1377 	{ 0, 0 },
1378 	{ 0, 0 },
1379 	{ 0, 0 },
1380 	{ 0, 0 },
1381 	{ 0, 0 },
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 	{ etheripname, ETHERIPCTL_MAXID },
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 	{ ipcompname, IPCOMPCTL_MAXID },
1402 	{ 0, 0 },
1403 	{ 0, 0 },
1404 	{ 0, 0 },
1405 	{ carpname, CARPCTL_MAXID },
1406 };
1407 
1408 struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1409 struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1410 struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1411 struct list ttylist = { ttyname, KERN_TTY_MAXID };
1412 struct list semlist = { semname, KERN_SEMINFO_MAXID };
1413 struct list shmlist = { shmname, KERN_SHMINFO_MAXID };
1414 struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
1415 
1416 /*
1417  * handle vfs namei cache statistics
1418  */
1419 int
1420 sysctl_nchstats(char *string, char **bufpp, int mib[], int flags, int *typep)
1421 {
1422 	static struct nchstats nch;
1423 	int indx;
1424 	size_t size;
1425 	static int keepvalue = 0;
1426 
1427 	if (*bufpp == NULL) {
1428 		bzero(&nch, sizeof(struct nchstats));
1429 		listall(string, &nchstatslist);
1430 		return (-1);
1431 	}
1432 	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1433 		return (-1);
1434 	mib[2] = indx;
1435 	if (*bufpp != NULL) {
1436 		warnx("fourth level name in %s is invalid", string);
1437 		return (-1);
1438 	}
1439 	if (keepvalue == 0) {
1440 		size = sizeof(struct nchstats);
1441 		if (sysctl(mib, 2, &nch, &size, NULL, 0) < 0)
1442 			return (-1);
1443 		keepvalue = 1;
1444 	}
1445 	if (!nflag)
1446 		(void)printf("%s = ", string);
1447 	switch (indx) {
1448 	case KERN_NCHSTATS_GOODHITS:
1449 		(void)printf("%ld\n", nch.ncs_goodhits);
1450 		break;
1451 	case KERN_NCHSTATS_NEGHITS:
1452 		(void)printf("%ld\n", nch.ncs_neghits);
1453 		break;
1454 	case KERN_NCHSTATS_BADHITS:
1455 		(void)printf("%ld\n", nch.ncs_badhits);
1456 		break;
1457 	case KERN_NCHSTATS_FALSEHITS:
1458 		(void)printf("%ld\n", nch.ncs_falsehits);
1459 		break;
1460 	case KERN_NCHSTATS_MISS:
1461 		(void)printf("%ld\n", nch.ncs_miss);
1462 		break;
1463 	case KERN_NCHSTATS_LONG:
1464 		(void)printf("%ld\n", nch.ncs_long);
1465 		break;
1466 	case KERN_NCHSTATS_PASS2:
1467 		(void)printf("%ld\n", nch.ncs_pass2);
1468 		break;
1469 	case KERN_NCHSTATS_2PASSES:
1470 		(void)printf("%ld\n", nch.ncs_2passes);
1471 		break;
1472 	}
1473 	return (-1);
1474 }
1475 
1476 /*
1477  * handle tty statistics
1478  */
1479 int
1480 sysctl_tty(char *string, char **bufpp, int mib[], int flags, int *typep)
1481 {
1482 	int indx;
1483 
1484 	if (*bufpp == NULL) {
1485 		listall(string, &ttylist);
1486 		return (-1);
1487 	}
1488 	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1489 		return (-1);
1490 	mib[2] = indx;
1491 	*typep = CTLTYPE_QUAD;
1492 	return (3);
1493 }
1494 
1495 /*
1496  * handle fork statistics
1497  */
1498 int
1499 sysctl_forkstat(char *string, char **bufpp, int mib[], int flags, int *typep)
1500 {
1501 	static struct forkstat fks;
1502 	static int keepvalue = 0;
1503 	int indx;
1504 	size_t size;
1505 
1506 	if (*bufpp == NULL) {
1507 		bzero(&fks, sizeof(struct forkstat));
1508 		listall(string, &forkstatlist);
1509 		return (-1);
1510 	}
1511 	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1512 		return (-1);
1513 	if (*bufpp != NULL) {
1514 		warnx("fourth level name in %s is invalid", string);
1515 		return (-1);
1516 	}
1517 	if (keepvalue == 0) {
1518 		size = sizeof(struct forkstat);
1519 		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0)
1520 			return (-1);
1521 		keepvalue = 1;
1522 	}
1523 	if (!nflag)
1524 		(void)printf("%s = ", string);
1525 	switch (indx)	{
1526 	case KERN_FORKSTAT_FORK:
1527 		(void)printf("%d\n", fks.cntfork);
1528 		break;
1529 	case KERN_FORKSTAT_VFORK:
1530 		(void)printf("%d\n", fks.cntvfork);
1531 		break;
1532 	case KERN_FORKSTAT_RFORK:
1533 		(void)printf("%d\n", fks.cntrfork);
1534 		break;
1535 	case KERN_FORKSTAT_KTHREAD:
1536 		(void)printf("%d\n", fks.cntkthread);
1537 		break;
1538 	case KERN_FORKSTAT_SIZFORK:
1539 		(void)printf("%d\n", fks.sizfork);
1540 		break;
1541 	case KERN_FORKSTAT_SIZVFORK:
1542 		(void)printf("%d\n", fks.sizvfork);
1543 		break;
1544 	case KERN_FORKSTAT_SIZRFORK:
1545 		(void)printf("%d\n", fks.sizrfork);
1546 		break;
1547 	case KERN_FORKSTAT_SIZKTHREAD:
1548 		(void)printf("%d\n", fks.sizkthread);
1549 		break;
1550 	}
1551 	return (-1);
1552 }
1553 
1554 /*
1555  * handle malloc statistics
1556  */
1557 int
1558 sysctl_malloc(char *string, char **bufpp, int mib[], int flags, int *typep)
1559 {
1560 	int indx, stor, i;
1561 	char *name, bufp[BUFSIZ], *buf, *ptr;
1562 	struct list lp;
1563 	size_t size;
1564 
1565 	if (*bufpp == NULL) {
1566 		listall(string, &kernmalloclist);
1567 		return (-1);
1568 	}
1569 	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1570 		return (-1);
1571 	mib[2] = indx;
1572 	if (mib[2] == KERN_MALLOC_BUCKET) {
1573 		if ((name = strsep(bufpp, ".")) == NULL) {
1574 			size = BUFSIZ;
1575 			stor = mib[2];
1576 			mib[2] = KERN_MALLOC_BUCKETS;
1577 			buf = bufp;
1578 			if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1579 				return (-1);
1580 			mib[2] = stor;
1581 			for (stor = 0, i = 0; i < size; i++)
1582 				if (buf[i] == ',')
1583 					stor++;
1584 			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1585 			if (lp.list == NULL)
1586 				return (-1);
1587 			lp.size = stor + 2;
1588 			for (i = 1;
1589 			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL;
1590 			    i++) {
1591 				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1592 			}
1593 			lp.list[i].ctl_name = buf;
1594 			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1595 			listall(string, &lp);
1596 			free(lp.list);
1597 			return (-1);
1598 		}
1599 		mib[3] = atoi(name);
1600 		return (4);
1601 	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
1602 		*typep = CTLTYPE_STRING;
1603 		return (3);
1604 	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
1605 		size = BUFSIZ;
1606 		stor = mib[2];
1607 		mib[2] = KERN_MALLOC_KMEMNAMES;
1608 		buf = bufp;
1609 		if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1610 			return (-1);
1611 		mib[2] = stor;
1612 		if ((name = strsep(bufpp, ".")) == NULL) {
1613 			for (stor = 0, i = 0; i < size; i++)
1614 				if (buf[i] == ',')
1615 					stor++;
1616 			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1617 			if (lp.list == NULL)
1618 				return (-1);
1619 			lp.size = stor + 2;
1620 			for (i = 1;
1621 			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL; i++) {
1622 				if (lp.list[i].ctl_name[0] == '\0') {
1623 					i--;
1624 					continue;
1625 				}
1626 				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1627 			}
1628 			lp.list[i].ctl_name = buf;
1629 			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1630 			listall(string, &lp);
1631 			free(lp.list);
1632 			return (-1);
1633 		}
1634 		ptr = strstr(buf, name);
1635  tryagain:
1636 		if (ptr == NULL) {
1637 		       warnx("fourth level name %s in %s is invalid", name,
1638 			     string);
1639 		       return (-1);
1640 		}
1641 		if ((*(ptr + strlen(name)) != ',') &&
1642 		    (*(ptr + strlen(name)) != '\0')) {
1643 			ptr = strstr(ptr + 1, name); /* retry */
1644 			goto tryagain;
1645 		}
1646 		if ((ptr != buf) && (*(ptr - 1) != ',')) {
1647 			ptr = strstr(ptr + 1, name); /* retry */
1648 			goto tryagain;
1649 		}
1650 		for (i = 0, stor = 0; buf + i < ptr; i++)
1651 			if (buf[i] == ',')
1652 				stor++;
1653 		mib[3] = stor;
1654 		return (4);
1655 	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
1656 		*typep = CTLTYPE_STRING;
1657 		return (3);
1658 	}
1659 	return (-1);
1660 }
1661 
1662 #ifdef CPU_CHIPSET
1663 /*
1664  * handle machdep.chipset requests
1665  */
1666 struct ctlname chipsetname[] = CTL_CHIPSET_NAMES;
1667 struct list chipsetlist = { chipsetname, CPU_CHIPSET_MAXID };
1668 
1669 int
1670 sysctl_chipset(char *string, char **bufpp, int mib[], int flags, int *typep)
1671 {
1672 	int indx, bwx;
1673 	static void *q;
1674 	size_t len;
1675 	char *p;
1676 
1677 	if (*bufpp == NULL) {
1678 		listall(string, &chipsetlist);
1679 		return (-1);
1680 	}
1681 	if ((indx = findname(string, "third", bufpp, &chipsetlist)) == -1)
1682 		return (-1);
1683 	mib[2] = indx;
1684 	if (!nflag)
1685 		printf("%s = ", string);
1686 	switch(mib[2]) {
1687 	case CPU_CHIPSET_MEM:
1688 	case CPU_CHIPSET_DENSE:
1689 	case CPU_CHIPSET_PORTS:
1690 	case CPU_CHIPSET_HAE_MASK:
1691 		len = sizeof(void *);
1692 		if (sysctl(mib, 3, &q, &len, NULL, 0) < 0)
1693 			return (-1);
1694 		printf("%p\n", q);
1695 		break;
1696 	case CPU_CHIPSET_BWX:
1697 		len = sizeof(int);
1698 		if (sysctl(mib, 3, &bwx, &len, NULL, 0) < 0)
1699 			return (-1);
1700 		printf("%d\n", bwx);
1701 		break;
1702 	case CPU_CHIPSET_TYPE:
1703 		if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0)
1704 			return (-1);
1705 		p = malloc(len + 1);
1706 		if (p == NULL)
1707 			return (-1);
1708 		if (sysctl(mib, 3, p, &len, NULL, 0) < 0)
1709 			return (-1);
1710 		p[len] = '\0';
1711 		printf("%s\n", p);
1712 		break;
1713 	}
1714 	return (-1);
1715 }
1716 #endif
1717 /*
1718  * handle internet requests
1719  */
1720 int
1721 sysctl_inet(char *string, char **bufpp, int mib[], int flags, int *typep)
1722 {
1723 	struct list *lp;
1724 	int indx;
1725 
1726 	if (*bufpp == NULL) {
1727 		listall(string, &inetlist);
1728 		return (-1);
1729 	}
1730 	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1731 		return (-1);
1732 	mib[2] = indx;
1733 	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1734 		lp = &inetvars[indx];
1735 	else if (!flags)
1736 		return (-1);
1737 	else {
1738 		warnx("%s: no variables defined for this protocol", string);
1739 		return (-1);
1740 	}
1741 	if (*bufpp == NULL) {
1742 		listall(string, lp);
1743 		return (-1);
1744 	}
1745 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1746 		return (-1);
1747 	mib[3] = indx;
1748 	*typep = lp->list[indx].ctl_type;
1749 	return (4);
1750 }
1751 
1752 #ifdef INET6
1753 struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1754 struct ctlname ip6name[] = IPV6CTL_NAMES;
1755 struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1756 struct ctlname pim6name[] = PIM6CTL_NAMES;
1757 struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1758 struct list inet6vars[] = {
1759 /*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1760 	{ 0, 0 },
1761 	{ 0, 0 },
1762 	{ 0, 0 },
1763 	{ 0, 0 },
1764 	{ 0, 0 },
1765 /*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1766 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1767 /*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1768 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1769 /*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1770 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1771 /*40*/	{ 0, 0 },
1772 	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1773 	{ 0, 0 },
1774 	{ 0, 0 },
1775 	{ 0, 0 },
1776 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1777 /*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1778 	{ 0, 0 },
1779 	{ 0, 0 },
1780 	{ 0, 0 },
1781 	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1782 	{ 0, 0 },
1783 /*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1784 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1785 /*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1786 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1787 /*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1788 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1789 /*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1790 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1791 /*100*/	{ 0, 0 },
1792 	{ 0, 0 },
1793 	{ 0, 0 },
1794 	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
1795 };
1796 
1797 /*
1798  * handle internet6 requests
1799  */
1800 int
1801 sysctl_inet6(char *string, char **bufpp, int mib[], int flags, int *typep)
1802 {
1803 	struct list *lp;
1804 	int indx;
1805 
1806 	if (*bufpp == NULL) {
1807 		listall(string, &inet6list);
1808 		return (-1);
1809 	}
1810 	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
1811 		return (-1);
1812 	mib[2] = indx;
1813 	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
1814 		lp = &inet6vars[indx];
1815 	else if (!flags)
1816 		return (-1);
1817 	else {
1818 		warnx("%s: no variables defined for this protocol", string);
1819 		return (-1);
1820 	}
1821 	if (*bufpp == NULL) {
1822 		listall(string, lp);
1823 		return (-1);
1824 	}
1825 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1826 		return (-1);
1827 	mib[3] = indx;
1828 	*typep = lp->list[indx].ctl_type;
1829 	return (4);
1830 }
1831 #endif
1832 
1833 struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
1834 struct ctlname ipxpname[] = IPXCTL_NAMES;
1835 struct ctlname spxpname[] = SPXCTL_NAMES;
1836 struct list ipxlist = { ipxname, IPXCTL_MAXID };
1837 struct list ipxvars[] = {
1838 	{ ipxpname, IPXCTL_MAXID },	/* ipx */
1839 	{ 0, 0 },
1840 	{ 0, 0 },
1841 	{ 0, 0 },
1842 	{ 0, 0 },
1843 	{ spxpname, SPXCTL_MAXID },
1844 };
1845 
1846 /*
1847  * Handle internet requests
1848  */
1849 int
1850 sysctl_ipx(char *string, char **bufpp, int mib[], int flags, int *typep)
1851 {
1852 	struct list *lp;
1853 	int indx;
1854 
1855 	if (*bufpp == NULL) {
1856 		listall(string, &ipxlist);
1857 		return (-1);
1858 	}
1859 	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1860 		return (-1);
1861 	mib[2] = indx;
1862 	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1863 		lp = &ipxvars[indx];
1864 	else if (!flags)
1865 		return (-1);
1866 	else {
1867 		warnx("%s: no variables defined for this protocol", string);
1868 		return (-1);
1869 	}
1870 	if (*bufpp == NULL) {
1871 		listall(string, lp);
1872 		return (-1);
1873 	}
1874 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1875 		return (-1);
1876 	mib[3] = indx;
1877 	*typep = lp->list[indx].ctl_type;
1878 	return (4);
1879 }
1880 
1881 /*
1882  * Handle SysV semaphore info requests
1883  */
1884 int
1885 sysctl_seminfo(string, bufpp, mib, flags, typep)
1886 	char *string;
1887 	char **bufpp;
1888 	int mib[];
1889 	int flags;
1890 	int *typep;
1891 {
1892 	int indx;
1893 
1894 	if (*bufpp == NULL) {
1895 		listall(string, &semlist);
1896 		return (-1);
1897 	}
1898 	if ((indx = findname(string, "third", bufpp, &semlist)) == -1)
1899 		return (-1);
1900 	mib[2] = indx;
1901 	*typep = CTLTYPE_INT;
1902 	return (3);
1903 }
1904 
1905 /*
1906  * Handle SysV shared memory info requests
1907  */
1908 int
1909 sysctl_shminfo(string, bufpp, mib, flags, typep)
1910 	char *string;
1911 	char **bufpp;
1912 	int mib[];
1913 	int flags;
1914 	int *typep;
1915 {
1916 	int indx;
1917 
1918 	if (*bufpp == NULL) {
1919 		listall(string, &shmlist);
1920 		return (-1);
1921 	}
1922 	if ((indx = findname(string, "third", bufpp, &shmlist)) == -1)
1923 		return (-1);
1924 	mib[2] = indx;
1925 	*typep = CTLTYPE_INT;
1926 	return (3);
1927 }
1928 
1929 /*
1930  * Handle watchdog support
1931  */
1932 int
1933 sysctl_watchdog(char *string, char **bufpp, int mib[], int flags,
1934     int *typep)
1935 {
1936 	int indx;
1937 
1938 	if (*bufpp == NULL) {
1939 		listall(string, &watchdoglist);
1940 		return (-1);
1941 	}
1942 	if ((indx = findname(string, "third", bufpp, &watchdoglist)) == -1)
1943 		return (-1);
1944 	mib[2] = indx;
1945 	*typep = watchdoglist.list[indx].ctl_type;
1946 	return (3);
1947 }
1948 
1949 /*
1950  * Handle hardware monitoring sensors support
1951  */
1952 int
1953 sysctl_sensors(char *string, char **bufpp, int mib[], int flags, int *typep)
1954 {
1955 	char *name;
1956 	int indx;
1957 
1958 	if (*bufpp == NULL) {
1959 		char name[BUFSIZ];
1960 
1961 		/* scan all sensors */
1962 		for (indx = 0; indx < 256; indx++) {
1963 			snprintf(name, sizeof(name), "%s.%u", string, indx);
1964 			parse(name, 0);
1965 		}
1966 		return (-1);
1967 	}
1968 	if ((name = strsep(bufpp, ".")) == NULL) {
1969 		warnx("%s: incomplete specification", string);
1970 		return (-1);
1971 	}
1972 	mib[2] = atoi(name);
1973 	*typep = CTLTYPE_STRUCT;
1974 	return (3);
1975 }
1976 
1977 char	**emul_names;
1978 int	emul_num, nemuls;
1979 int	emul_init(void);
1980 
1981 int
1982 sysctl_emul(char *string, char *newval, int flags)
1983 {
1984 	int mib[4], enabled, i, old, print, found = 0;
1985 	char *head, *target;
1986 	size_t len;
1987 
1988 	if (emul_init() == -1) {
1989 		warnx("emul_init: out of memory");
1990 		return (1);
1991 	}
1992 
1993 	mib[0] = CTL_KERN;
1994 	mib[1] = KERN_EMUL;
1995 	mib[3] = KERN_EMUL_ENABLED;
1996 	head = "kern.emul.";
1997 
1998 	if (aflag || strcmp(string, "kern.emul") == 0) {
1999 		if (strcmp(string, "kern.emul") == 0 && wflag) {
2000 			warnx("%s: specification is incomplete", string);
2001 			return (1);
2002 		}
2003 		if (nflag)
2004 			printf("%d\n", nemuls);
2005 		else
2006 			printf("%snemuls = %d\n", head, nemuls);
2007 		for (i = 0; i < emul_num; i++) {
2008 			if (emul_names[i] == NULL)
2009 				continue;
2010 			mib[2] = i + 1;
2011 			len = sizeof(int);
2012 			if (sysctl(mib, 4, &enabled, &len, NULL, 0) == -1) {
2013 				warn("%s", string);
2014 				continue;
2015 			}
2016 			if (nflag)
2017 				printf("%d\n", enabled);
2018 			else
2019 				printf("%s%s = %d\n", head, emul_names[i],
2020 				    enabled);
2021 		}
2022 		return (0);
2023 	}
2024 	/* User specified a third level name */
2025 	target = strrchr(string, '.');
2026 	target++;
2027 	if (strcmp(string, "nemuls") == 0) {
2028 		if (newval) {
2029 			warnx("Operation not permitted");
2030 			return (1);
2031 		}
2032 		if (nflag)
2033 			printf("%d\n", nemuls);
2034 		else
2035 			printf("%snemuls = %d\n", head, nemuls);
2036 		return (0);
2037 	}
2038 	for (i = 0; i < emul_num; i++) {
2039 		print = 1;
2040 		if (!emul_names[i]) {
2041 			print = 0;
2042 			if (strcmp(target, emul_names[i-1]))
2043 				continue;
2044 		} else if (strcmp(target, emul_names[i]))
2045 			continue;
2046 		found = 1;
2047 		mib[2] = i + 1;
2048 		len = sizeof(int);
2049 		if (newval) {
2050 			enabled = atoi(newval);
2051 			if (sysctl(mib, 4, &old, &len, &enabled, len) == -1) {
2052 				warn("%s", string);
2053 				continue;
2054 			}
2055 			if (print) {
2056 				if (nflag)
2057 					printf("%d\n", enabled);
2058 				else
2059 					printf("%s%s: %d -> %d\n", head,
2060 					    target, old, enabled);
2061 			}
2062 		} else {
2063 			if (sysctl(mib, 4, &enabled, &len, NULL, 0) == -1) {
2064 				warn("%s", string);
2065 				continue;
2066 			}
2067 			if (print) {
2068 				if (nflag)
2069 					printf("%d\n", enabled);
2070 				else
2071 					printf("%s%s = %d\n", head, target,
2072 					    enabled);
2073 			}
2074 		}
2075 	}
2076 	if (!found)
2077 		warnx("third level name %s in kern.emul is invalid",
2078 		    string);
2079 	return (0);
2080 
2081 
2082 }
2083 
2084 int
2085 emul_init(void)
2086 {
2087 	static int done;
2088 	char string[16];
2089 	int mib[4], i;
2090 	size_t len;
2091 
2092 	if (done)
2093 		return;
2094 	done = 1;
2095 
2096 	mib[0] = CTL_KERN;
2097 	mib[1] = KERN_EMUL;
2098 	mib[2] = KERN_EMUL_NUM;
2099 	len = sizeof(int);
2100 	if (sysctl(mib, 3, &emul_num, &len, NULL, 0) == -1)
2101 		return (-1);
2102 
2103 	emul_names = calloc(emul_num, sizeof(char *));
2104 	if (emul_names == NULL)
2105 		return (-1);
2106 
2107 	nemuls = emul_num;
2108 	for (i = 0; i < emul_num; i++) {
2109 		mib[2] = i + 1;
2110 		mib[3] = KERN_EMUL_NAME;
2111 		len = sizeof(string);
2112 		if (sysctl(mib, 4, string, &len, NULL, 0) == -1)
2113 			break;
2114 		if (i > 0 && emul_names[i - 1] &&
2115 		    strcmp(string, emul_names[i - 1]) == 0) {
2116 			nemuls--;
2117 			continue;
2118 		}
2119 		emul_names[i] = strdup(string);
2120 		if (emul_names[i] == NULL) {
2121 			free(emul_names);
2122 			return (-1);
2123 		}
2124 	}
2125 	return (0);
2126 }
2127 
2128 /*
2129  * Scan a list of names searching for a particular name.
2130  */
2131 int
2132 findname(char *string, char *level, char **bufp, struct list *namelist)
2133 {
2134 	char *name;
2135 	int i;
2136 
2137 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
2138 		warnx("%s: incomplete specification", string);
2139 		return (-1);
2140 	}
2141 	for (i = 0; i < namelist->size; i++)
2142 		if (namelist->list[i].ctl_name != NULL &&
2143 		    strcmp(name, namelist->list[i].ctl_name) == 0)
2144 			break;
2145 	if (i == namelist->size) {
2146 		warnx("%s level name %s in %s is invalid", level, name, string);
2147 		return (-1);
2148 	}
2149 	return (i);
2150 }
2151 
2152 void
2153 usage(void)
2154 {
2155 
2156 	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n",
2157 	    "sysctl [-n] variable ...", "sysctl [-nq] -w variable=value ...",
2158 	    "sysctl -aA [-n]");
2159 	exit(1);
2160 }
2161