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