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