xref: /openbsd-src/sbin/sysctl/sysctl.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: sysctl.c,v 1.78 2001/12/04 14:57:27 art 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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1993\n\
40 	The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
46 #else
47 static char *rcsid = "$OpenBSD: sysctl.c,v 1.78 2001/12/04 14:57:27 art Exp $";
48 #endif
49 #endif /* not lint */
50 
51 #include <sys/param.h>
52 #include <sys/gmon.h>
53 #include <sys/mount.h>
54 #include <sys/stat.h>
55 #include <sys/sysctl.h>
56 #include <sys/socket.h>
57 #include <sys/malloc.h>
58 #include <sys/dkstat.h>
59 #include <sys/uio.h>
60 #include <sys/tty.h>
61 #include <sys/namei.h>
62 #include <machine/cpu.h>
63 #include <net/route.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 
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 *vfsname;
132 #ifdef CTL_MACHDEP_NAMES
133 struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
134 #endif
135 struct ctlname ddbname[] = CTL_DDB_NAMES;
136 char names[BUFSIZ];
137 int lastused;
138 
139 struct list {
140 	struct	ctlname *list;
141 	int	size;
142 };
143 struct list toplist = { topname, CTL_MAXID };
144 struct list secondlevel[] = {
145 	{ 0, 0 },			/* CTL_UNSPEC */
146 	{ kernname, KERN_MAXID },	/* CTL_KERN */
147 	{ vmname, VM_MAXID },		/* CTL_VM */
148 	{ fsname, FS_MAXID },		/* CTL_FS */
149 	{ netname, NET_MAXID },		/* CTL_NET */
150 	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
151 	{ hwname, HW_MAXID },		/* CTL_HW */
152 #ifdef CTL_MACHDEP_NAMES
153 	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
154 #else
155 	{ 0, 0 },			/* CTL_MACHDEP */
156 #endif
157 	{ username, USER_MAXID },	/* CTL_USER_NAMES */
158 	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
159 	{ 0, 0 },			/* CTL_VFS */
160 };
161 
162 int	Aflag, aflag, nflag, wflag;
163 
164 /*
165  * Variables requiring special processing.
166  */
167 #define	CLOCK		0x00000001
168 #define	BOOTTIME	0x00000002
169 #define	CHRDEV		0x00000004
170 #define	BLKDEV		0x00000008
171 #define	RNDSTATS	0x00000010
172 #define	BADDYNAMIC	0x00000020
173 #define	BIOSGEO		0x00000040
174 #define	BIOSDEV		0x00000080
175 #define	MAJ2DEV		0x00000100
176 #define	UNSIGNED	0x00000200
177 #define	KMEMBUCKETS	0x00000400
178 #define	LONGARRAY	0x00000800
179 #define KMEMSTATS	0x00001000
180 
181 /* prototypes */
182 void debuginit __P((void));
183 void listall __P((char *, struct list *));
184 void parse __P((char *, int));
185 void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
186 void usage __P((void));
187 int findname __P((char *, char *, char **, struct list *));
188 int sysctl_inet __P((char *, char **, int *, int, int *));
189 #ifdef INET6
190 int sysctl_inet6 __P((char *, char **, int *, int, int *));
191 #endif
192 int sysctl_ipx __P((char *, char **, int *, int, int *));
193 int sysctl_fs __P((char *, char **, int *, int, int *));
194 static int sysctl_vfs __P((char *, char **, int[], int, int *));
195 static int sysctl_vfsgen __P((char *, char **, int[], int, int *));
196 int sysctl_bios __P((char *, char **, int *, int, int *));
197 int sysctl_swpenc __P((char *, char **, int *, int, int *));
198 int sysctl_forkstat __P((char *, char **, int *, int, int *));
199 int sysctl_tty __P((char *, char **, int *, int, int *));
200 int sysctl_nchstats __P((char *, char **, int *, int, int *));
201 int sysctl_malloc __P((char *, char **, int *, int, int *));
202 void vfsinit __P((void));
203 
204 int
205 main(argc, argv)
206 	int argc;
207 	char *argv[];
208 {
209 	int ch, lvl1;
210 
211 	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
212 		switch (ch) {
213 
214 		case 'A':
215 			Aflag = 1;
216 			break;
217 
218 		case 'a':
219 			aflag = 1;
220 			break;
221 
222 		case 'n':
223 			nflag = 1;
224 			break;
225 
226 		case 'w':
227 			wflag = 1;
228 			break;
229 
230 		default:
231 			usage();
232 		}
233 	}
234 	argc -= optind;
235 	argv += optind;
236 
237 	if (argc == 0 && (Aflag || aflag)) {
238 		debuginit();
239 		vfsinit();
240 		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
241 			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
242 		return (0);
243 	}
244 	if (argc == 0)
245 		usage();
246 	for (; *argv != NULL; ++argv)
247 		parse(*argv, 1);
248 	return (0);
249 }
250 
251 /*
252  * List all variables known to the system.
253  */
254 void
255 listall(prefix, lp)
256 	char *prefix;
257 	struct list *lp;
258 {
259 	char *cp, name[BUFSIZ];
260 	int lvl2, len;
261 
262 	if (lp->list == NULL)
263 		return;
264 	if ((len = strlcpy(name, prefix, sizeof(name))) >= sizeof(name))
265 		warn("%s: name too long", prefix);
266 	cp = name + len++;
267 	*cp++ = '.';
268 	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
269 		if (lp->list[lvl2].ctl_name == NULL)
270 			continue;
271 		if (strlcpy(cp, lp->list[lvl2].ctl_name,
272 		    sizeof(name) - len) >= sizeof(name) - len)
273 			warn("%s: name too long", lp->list[lvl2].ctl_name);
274 		parse(name, Aflag);
275 	}
276 }
277 
278 /*
279  * Parse a name into a MIB entry.
280  * Lookup and print out the MIB entry if it exists.
281  * Set a new value if requested.
282  */
283 void
284 parse(string, flags)
285 	char *string;
286 	int flags;
287 {
288 	int indx, type, state, intval, len;
289 	size_t size, newsize = 0;
290 	int lal = 0, special = 0;
291 	void *newval = 0;
292 	int64_t quadval;
293 	struct list *lp;
294 	int mib[CTL_MAXNAME];
295 	char *cp, *bufp, buf[BUFSIZ];
296 
297 	(void)strlcpy(buf, string, sizeof(buf));
298 	bufp = buf;
299 	if ((cp = strchr(string, '=')) != NULL) {
300 		if (!wflag)
301 			errx(2, "must specify -w to set variables");
302 		*strchr(buf, '=') = '\0';
303 		*cp++ = '\0';
304 		while (isspace(*cp))
305 			cp++;
306 		newval = cp;
307 		newsize = strlen(cp);
308 	}
309 	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
310 		return;
311 	mib[0] = indx;
312 	if (indx == CTL_VFS)
313 		vfsinit();
314 	if (indx == CTL_DEBUG)
315 		debuginit();
316 	lp = &secondlevel[indx];
317 	if (lp->list == 0) {
318 		warnx("%s: class is not implemented", topname[indx].ctl_name);
319 		return;
320 	}
321 	if (bufp == NULL) {
322 		listall(topname[indx].ctl_name, lp);
323 		return;
324 	}
325 	if ((indx = findname(string, "second", &bufp, lp)) == -1)
326 		return;
327 	mib[1] = indx;
328 	type = lp->list[indx].ctl_type;
329 	len = 2;
330 	switch (mib[0]) {
331 
332 	case CTL_KERN:
333 		switch (mib[1]) {
334 		case KERN_PROF:
335 			mib[2] = GPROF_STATE;
336 			size = sizeof(state);
337 			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
338 				if (flags == 0)
339 					return;
340 				if (!nflag)
341 					(void)printf("%s: ", string);
342 				(void)puts("kernel is not compiled for profiling");
343 				return;
344 			}
345 			if (!nflag)
346 				(void)printf("%s = %s\n", string,
347 				    state == GMON_PROF_OFF ? "off" : "running");
348 			return;
349 		case KERN_FORKSTAT:
350 			sysctl_forkstat(string, &bufp, mib, flags, &type);
351 			return;
352 		case KERN_TTY:
353 			len = sysctl_tty(string, &bufp, mib, flags, &type);
354 			if (len < 0)
355 				return;
356 			newsize = 0;
357 			break;
358 		case KERN_NCHSTATS:
359 			sysctl_nchstats(string, &bufp, mib, flags, &type);
360 			return;
361 		case KERN_MALLOCSTATS:
362 			len = sysctl_malloc(string, &bufp, mib, flags, &type);
363 			if (len < 0)
364 				return;
365 			if (mib[2] == KERN_MALLOC_BUCKET)
366 				special |= KMEMBUCKETS;
367 			if (mib[2] == KERN_MALLOC_KMEMSTATS)
368 				special |= KMEMSTATS;
369 			newsize = 0;
370 			break;
371 		case KERN_MSGBUF:
372 			if (flags == 0)
373 				return;
374 			warnx("use dmesg to view %s", string);
375 			return;
376 		case KERN_VNODE:
377 		case KERN_FILE:
378 			if (flags == 0)
379 				return;
380 			warnx("use pstat to view %s information", string);
381 			return;
382 		case KERN_PROC:
383 			if (flags == 0)
384 				return;
385 			warnx("use ps to view %s information", string);
386 			return;
387 		case KERN_NTPTIME:
388 			if (flags == 0)
389 				return;
390 			warnx("use xntpdc to view %s information", string);
391 			return;
392 		case KERN_CLOCKRATE:
393 			special |= CLOCK;
394 			break;
395 		case KERN_BOOTTIME:
396 			special |= BOOTTIME;
397 			break;
398 		case KERN_RND:
399 			special |= RNDSTATS;
400 			break;
401 		case KERN_HOSTID:
402 		case KERN_ARND:
403 			special |= UNSIGNED;
404 			break;
405 		case KERN_CPTIME:
406 			special |= LONGARRAY;
407 			lal = CPUSTATES;
408 			break;
409 		}
410 		break;
411 
412 	case CTL_HW:
413 		switch (mib[1]) {
414 		case HW_DISKSTATS:
415 			/*
416 			 * Only complain if someone asks explicitly for this,
417 			 * otherwise "fail" silently.
418 			 */
419 			if (flags)
420 				warnx("use vmstat to view %s information",
421 				    string);
422 			return;
423 		}
424 		break;
425 
426 	case CTL_VM:
427 		if (mib[1] == VM_LOADAVG) {
428 			double loads[3];
429 
430 			getloadavg(loads, 3);
431 			if (!nflag)
432 				(void)printf("%s = ", string);
433 			(void)printf("%.2f %.2f %.2f\n", loads[0],
434 			    loads[1], loads[2]);
435 			return;
436 		} else if (mib[1] == VM_PSSTRINGS) {
437 			struct _ps_strings _ps;
438 
439 			size = sizeof(_ps);
440 			if (sysctl(mib, 2, &_ps, &size, NULL, 0) == -1) {
441 				if (flags == 0)
442 					return;
443 				if (!nflag)
444 					(void)printf("%s: ", string);
445 				(void)puts("can't find ps strings");
446 				return;
447 			}
448 			if (!nflag)
449 				(void)printf("%s = ", string);
450 			(void)printf("%p\n", _ps.val);
451 			return;
452 		} else if (mib[1] == VM_SWAPENCRYPT) {
453 			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
454 			if (len < 0)
455 				return;
456 
457 			break;
458 		} else if (mib[1] == VM_NKMEMPAGES ||
459 		    mib[1] == VM_ANONMIN ||
460 		    mib[1] == VM_VTEXTMIN ||
461 		    mib[1] == VM_VNODEMIN) {
462 			break;
463 		}
464 		if (flags == 0)
465 			return;
466 		warnx("use vmstat or systat to view %s information", string);
467 		return;
468 
469 		break;
470 
471 	case CTL_NET:
472 		if (mib[1] == PF_INET) {
473 			len = sysctl_inet(string, &bufp, mib, flags, &type);
474 			if (len < 0)
475 				return;
476 
477 			if ((mib[2] == IPPROTO_TCP &&
478 			     mib[3] == TCPCTL_BADDYNAMIC) ||
479 			    (mib[2] == IPPROTO_UDP &&
480 			     mib[3] == UDPCTL_BADDYNAMIC)) {
481 
482 				special |= BADDYNAMIC;
483 
484 				if (newval != NULL)
485 					parse_baddynamic(mib, len, string,
486 					    &newval, &newsize, flags, nflag);
487 			}
488 			break;
489 		}
490 #ifdef INET6
491 		if (mib[1] == PF_INET6) {
492 			len = sysctl_inet6(string, &bufp, mib, flags, &type);
493 			if (len < 0)
494 				return;
495 
496 			break;
497 		}
498 #endif
499 		if (mib[1] == PF_IPX) {
500 			len = sysctl_ipx(string, &bufp, mib, flags, &type);
501 			if (len >= 0)
502 				break;
503 			return;
504 		}
505 		if (flags == 0)
506 			return;
507 		warnx("use netstat to view %s information", string);
508 		return;
509 
510 	case CTL_DEBUG:
511 		mib[2] = CTL_DEBUG_VALUE;
512 		len = 3;
513 		break;
514 
515 	case CTL_MACHDEP:
516 #ifdef CPU_CONSDEV
517 		if (mib[1] == CPU_CONSDEV)
518 			special |= CHRDEV;
519 #endif
520 #ifdef CPU_BLK2CHR
521 		if (mib[1] == CPU_BLK2CHR) {
522 			if (bufp == NULL)
523 				return;
524 			mib[2] = makedev(atoi(bufp),0);
525 			bufp = NULL;
526 			len = 3;
527 			special |= CHRDEV;
528 			break;
529 		}
530 #endif
531 #ifdef CPU_CHR2BLK
532 		if (mib[1] == CPU_CHR2BLK) {
533 			if (bufp == NULL)
534 				return;
535 			mib[2] = makedev(atoi(bufp),0);
536 			bufp = NULL;
537 			len = 3;
538 			special |= BLKDEV;
539 			break;
540 		}
541 #endif
542 #ifdef CPU_BIOS
543 		if (mib[1] == CPU_BIOS) {
544 			len = sysctl_bios(string, &bufp, mib, flags, &type);
545 			if (len < 0)
546 				return;
547 			if (mib[2] == BIOS_DEV)
548 				special |= BIOSDEV;
549 			if (mib[2] == BIOS_DISKINFO)
550 				special |= BIOSGEO;
551 			break;
552 		}
553 #endif
554 		break;
555 
556 	case CTL_FS:
557 		len = sysctl_fs(string, &bufp, mib, flags, &type);
558 		if (len >= 0)
559 			break;
560 		return;
561 
562 	case CTL_VFS:
563 		if (mib[1])
564 			len = sysctl_vfs(string, &bufp, mib, flags, &type);
565 		else
566 			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
567 		if (len >= 0) {
568 			if (type == CTLTYPE_STRUCT) {
569 				if (flags)
570 					warnx("use nfsstat to view %s information",
571 					    MOUNT_NFS);
572 				return;
573 			} else
574 				break;
575 		}
576 		return;
577 
578 	case CTL_USER:
579 	case CTL_DDB:
580 		break;
581 
582 	default:
583 		warnx("illegal top level value: %d", mib[0]);
584 		return;
585 
586 	}
587 	if (bufp) {
588 		warnx("name %s in %s is unknown", bufp, string);
589 		return;
590 	}
591 	if (newsize > 0) {
592 		switch (type) {
593 		case CTLTYPE_INT:
594 			errno = 0;
595 			if (special & UNSIGNED)
596 				intval = strtoul(newval, &cp, 10);
597 			else
598 				intval = strtol(newval, &cp, 10);
599 			if (*cp != '\0') {
600 				warnx("%s: illegal value: %s", string,
601 				    (char *)newval);
602 				return;
603 			}
604 			if (errno == ERANGE) {
605 				warnx("%s: value %s out of range", string,
606 				    (char *)newval);
607 				return;
608 			}
609 			newval = &intval;
610 			newsize = sizeof(intval);
611 			break;
612 
613 		case CTLTYPE_QUAD:
614 			/* XXX - assumes sizeof(long long) == sizeof(quad_t) */
615 			(void)sscanf(newval, "%lld", (long long *)&quadval);
616 			newval = &quadval;
617 			newsize = sizeof(quadval);
618 			break;
619 		}
620 	}
621 	size = BUFSIZ;
622 	if (sysctl(mib, len, buf, &size, newval, newsize) == -1) {
623 		if (flags == 0)
624 			return;
625 		switch (errno) {
626 		case EOPNOTSUPP:
627 			warnx("%s: value is not available", string);
628 			return;
629 		case ENOTDIR:
630 			warnx("%s: specification is incomplete", string);
631 			return;
632 		case ENOMEM:
633 			warnx("%s: type is unknown to this program", string);
634 			return;
635 		case ENXIO:
636 			if (special & BIOSGEO)
637 				return;
638 		default:
639 			warn("%s", string);
640 			return;
641 		}
642 	}
643 	if (special & KMEMBUCKETS) {
644 		struct kmembuckets *kb = (struct kmembuckets *)buf;
645 		if (!nflag)
646 			(void)printf("%s = ", string);
647 		printf("(");
648 		printf("calls = %llu ", (long long)kb->kb_calls);
649 		printf("total_allocated = %llu ", (long long)kb->kb_total);
650 		printf("total_free = %lld ", (long long)kb->kb_totalfree);
651 		printf("elements = %lld ", (long long)kb->kb_elmpercl);
652 		printf("high watermark = %lld ", (long long)kb->kb_highwat);
653 		printf("could_free = %lld", (long long)kb->kb_couldfree);
654 		printf(")\n");
655 		return;
656 	}
657 	if (special & KMEMSTATS) {
658 		struct kmemstats *km = (struct kmemstats *)buf;
659 		int j, first = 1;
660 
661 		if (!nflag)
662 			(void)printf("%s = ", string);
663 		(void)printf("(inuse = %ld, calls = %ld, memuse = %ldK, limblocks = %d, mapblocks = %d, maxused = %ldK, limit = %ldK, spare = %ld, sizes = (", km->ks_inuse, km->ks_calls, (km->ks_memuse + 1023) / 1024, km->ks_limblocks, km->ks_mapblocks, (km->ks_maxused + 1023) / 1024, (km->ks_limit + 1023) / 1024, km->ks_spare);
664 		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
665 		 	if ((km->ks_size & j ) == 0)
666 				continue;
667 			if (first)
668 				(void)printf("%d", j);
669 			else
670 				(void)printf(",%d", j);
671 			first = 0;
672 		}
673 		if (first)
674 			(void)printf("none");
675 		(void)printf("))\n");
676 		return;
677 	}
678 	if (special & CLOCK) {
679 		struct clockinfo *clkp = (struct clockinfo *)buf;
680 
681 		if (!nflag)
682 			(void)printf("%s = ", string);
683 		(void)printf(
684 		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
685 		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
686 		return;
687 	}
688 	if (special & BOOTTIME) {
689 		struct timeval *btp = (struct timeval *)buf;
690 		time_t boottime;
691 
692 		if (!nflag) {
693 			boottime = btp->tv_sec;
694 			(void)printf("%s = %s", string, ctime(&boottime));
695 		} else
696 			(void)printf("%ld\n", btp->tv_sec);
697 		return;
698 	}
699 	if (special & BLKDEV) {
700 		dev_t dev = *(dev_t *)buf;
701 
702 		if (!nflag)
703 			(void)printf("%s = %s\n", string,
704 			    devname(dev, S_IFBLK));
705 		else
706 			(void)printf("0x%x\n", dev);
707 		return;
708 	}
709 	if (special & CHRDEV) {
710 		dev_t dev = *(dev_t *)buf;
711 
712 		if (!nflag)
713 			(void)printf("%s = %s\n", string,
714 			    devname(dev, S_IFCHR));
715 		else
716 			(void)printf("0x%x\n", dev);
717 		return;
718 	}
719 #ifdef CPU_BIOS
720 	if (special & BIOSGEO) {
721 		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
722 
723 		if (!nflag)
724 			(void)printf("%s = ", string);
725 		(void)printf("bootdev = 0x%x, "
726 			     "cylinders = %u, heads = %u, sectors = %u\n",
727 			     pdi->bsd_dev, pdi->bios_cylinders,
728 			     pdi->bios_heads, pdi->bios_sectors);
729 		return;
730 	}
731 	if (special & BIOSDEV) {
732 		int dev = *(int*)buf;
733 
734 		if (!nflag)
735 			(void)printf("%s = ", string);
736 		(void) printf("0x%02x\n", dev);
737 		return;
738 	}
739 #endif
740 	if (special & UNSIGNED) {
741 		if (newsize == 0) {
742 			if (!nflag)
743 				(void)printf("%s = ", string);
744 			(void)printf("%u\n", *(u_int *)buf);
745 		} else {
746 			if (!nflag)
747 				(void)printf("%s: %u -> ", string,
748 				    *(u_int *)buf);
749 			(void)printf("%u\n", *(u_int *)newval);
750 		}
751 		return;
752 	}
753 	if (special & RNDSTATS) {
754 		struct rndstats *rndstats = (struct rndstats *)buf;
755 		int i;
756 
757 		if (!nflag)
758 			(void)printf("%s = ", string);
759 		(void)printf(
760 		"%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
761 		    (unsigned long long)rndstats->rnd_total,
762 		    (unsigned long long)rndstats->rnd_used,
763 		    (unsigned long long)rndstats->rnd_reads,
764 		    (unsigned long long)rndstats->arc4_reads,
765 		    (unsigned long long)rndstats->arc4_nstirs,
766 		    (unsigned long long)rndstats->arc4_stirs,
767 		    (unsigned long long)rndstats->rnd_pad[0],
768 		    (unsigned long long)rndstats->rnd_pad[1],
769 		    (unsigned long long)rndstats->rnd_pad[2],
770 		    (unsigned long long)rndstats->rnd_pad[3],
771 		    (unsigned long long)rndstats->rnd_pad[4],
772 		    (unsigned long long)rndstats->rnd_waits,
773 		    (unsigned long long)rndstats->rnd_enqs,
774 		    (unsigned long long)rndstats->rnd_deqs,
775 		    (unsigned long long)rndstats->rnd_drops,
776 		    (unsigned long long)rndstats->rnd_drople);
777 		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]); i++)
778 			(void)printf(" %llu", (unsigned long long)rndstats->rnd_ed[i]);
779 		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]); i++)
780 			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sc[i]);
781 		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]); i++)
782 			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sb[i]);
783 		printf("\n");
784 		return;
785 	}
786 	if (special & BADDYNAMIC) {
787 		in_port_t port, lastport;
788 		u_int32_t *baddynamic = (u_int32_t *)buf;
789 
790 		if (!nflag)
791 			(void)printf("%s%s", string, newsize ? ": " : " = ");
792 		lastport = 0;
793 		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
794 			if (DP_ISSET(baddynamic, port)) {
795 				(void)printf("%s%hd", lastport ? "," : "",
796 				    port);
797 				lastport = port;
798 			}
799 		if (newsize != 0) {
800 			if (!nflag)
801 				fputs(" -> ", stdout);
802 			baddynamic = (u_int32_t *)newval;
803 			lastport = 0;
804 			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
805 			    port++)
806 				if (DP_ISSET(baddynamic, port)) {
807 					(void)printf("%s%hd",
808 					    lastport ? "," : "", port);
809 					lastport = port;
810 				}
811 		}
812 		(void)putchar('\n');
813 		return;
814 	}
815 	if (special & LONGARRAY) {
816 		long *la = (long *)buf;
817 		if (!nflag)
818 			printf("%s = ", string);
819 		while (lal--)
820 			printf("%ld%s", *la++, lal? ",":"");
821 		putchar('\n');
822 		return;
823 	}
824 	switch (type) {
825 	case CTLTYPE_INT:
826 		if (newsize == 0) {
827 			if (!nflag)
828 				(void)printf("%s = ", string);
829 			(void)printf("%d\n", *(int *)buf);
830 		} else {
831 			if (!nflag)
832 				(void)printf("%s: %d -> ", string,
833 				    *(int *)buf);
834 			(void)printf("%d\n", *(int *)newval);
835 		}
836 		return;
837 
838 	case CTLTYPE_STRING:
839 		if (newval == NULL) {
840 			if (!nflag)
841 				(void)printf("%s = ", string);
842 			(void)puts(buf);
843 		} else {
844 			if (!nflag)
845 				(void)printf("%s: %s -> ", string, buf);
846 			(void)puts((char *)newval);
847 		}
848 		return;
849 
850 	case CTLTYPE_QUAD:
851 		if (newsize == 0) {
852 			long long tmp = *(quad_t *)buf;
853 
854 			if (!nflag)
855 				(void)printf("%s = ", string);
856 			(void)printf("%lld\n", tmp);
857 		} else {
858 			long long tmp = *(quad_t *)buf;
859 
860 			if (!nflag)
861 				(void)printf("%s: %lld -> ", string, tmp);
862 			tmp = *(quad_t *)newval;
863 			(void)printf("%qd\n", tmp);
864 		}
865 		return;
866 
867 	case CTLTYPE_STRUCT:
868 		warnx("%s: unknown structure returned", string);
869 		return;
870 
871 	default:
872 	case CTLTYPE_NODE:
873 		warnx("%s: unknown type returned", string);
874 		return;
875 	}
876 }
877 
878 void
879 parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
880 	int mib[];
881 	size_t len;
882 	char *string;
883 	void **newvalp;
884 	size_t *newsizep;
885 	int flags;
886 	int nflag;
887 {
888 	static u_int32_t newbaddynamic[DP_MAPSIZE];
889 	in_port_t port;
890 	size_t size;
891 	char action, *cp;
892 
893 	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
894 		size = sizeof(newbaddynamic);
895 		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
896 			if (flags == 0)
897 				return;
898 			if (!nflag)
899 				(void)printf("%s: ", string);
900 			(void)puts("kernel does contain bad dynamic port tables");
901 			return;
902 		}
903 
904 		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
905 			if (*cp != '+' && *cp != '-')
906 				errx(1, "cannot mix +/- with full list");
907 			action = *cp++;
908 			port = atoi(cp);
909 			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
910 				errx(1, "invalid port, range is %d to %d",
911 				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
912 			if (action == '+')
913 				DP_SET(newbaddynamic, port);
914 			else
915 				DP_CLR(newbaddynamic, port);
916 		}
917 	} else {
918 		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
919 		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
920 			port = atoi(cp);
921 			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
922 				errx(1, "invalid port, range is %d to %d",
923 				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
924 			DP_SET(newbaddynamic, port);
925 		}
926 	}
927 
928 	*newvalp = (void *)newbaddynamic;
929 	*newsizep = sizeof(newbaddynamic);
930 }
931 
932 /*
933  * Initialize the set of debugging names
934  */
935 void
936 debuginit()
937 {
938 	int mib[3], loc, i;
939 	size_t size;
940 
941 	if (secondlevel[CTL_DEBUG].list != 0)
942 		return;
943 	secondlevel[CTL_DEBUG].list = debugname;
944 	mib[0] = CTL_DEBUG;
945 	mib[2] = CTL_DEBUG_NAME;
946 	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
947 		mib[1] = i;
948 		size = BUFSIZ - loc;
949 		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
950 			continue;
951 		debugname[i].ctl_name = &names[loc];
952 		debugname[i].ctl_type = CTLTYPE_INT;
953 		loc += size;
954 	}
955 	lastused = loc;
956 }
957 
958 struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
959 struct ctlname ffsname[] = FFS_NAMES;
960 struct ctlname nfsname[] = FS_NFS_NAMES;
961 struct list *vfsvars;
962 int *vfs_typenums;
963 
964 /*
965  * Initialize the set of filesystem names
966  */
967 void
968 vfsinit()
969 {
970 	int mib[4], maxtypenum, cnt, loc, size;
971 	struct vfsconf vfc;
972 	size_t buflen;
973 
974 	if (secondlevel[CTL_VFS].list != 0)
975 		return;
976 	mib[0] = CTL_VFS;
977 	mib[1] = VFS_GENERIC;
978 	mib[2] = VFS_MAXTYPENUM;
979 	buflen = 4;
980 	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
981 		return;
982 	maxtypenum++;	/* + generic */
983 	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
984 		return;
985 	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
986 	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
987 		free(vfs_typenums);
988 		return;
989 	}
990 	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
991 	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
992 		free(vfs_typenums);
993 		free(vfsvars);
994 		return;
995 	}
996 	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
997 	mib[2] = VFS_CONF;
998 	buflen = sizeof vfc;
999 	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
1000 		mib[3] = cnt - 1;
1001 		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
1002 			if (errno == EOPNOTSUPP)
1003 				continue;
1004 			warn("vfsinit");
1005 			free(vfsname);
1006 			return;
1007 		}
1008 		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1009 			vfsvars[cnt].list = ffsname;
1010 			vfsvars[cnt].size = FFS_MAXID;
1011 		}
1012 		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1013 			vfsvars[cnt].list = nfsname;
1014 			vfsvars[cnt].size = NFS_MAXID;
1015 		}
1016 		vfs_typenums[cnt] = vfc.vfc_typenum;
1017 		strcat(&names[loc], vfc.vfc_name);
1018 		vfsname[cnt].ctl_name = &names[loc];
1019 		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1020 		size = strlen(vfc.vfc_name) + 1;
1021 		loc += size;
1022 	}
1023 	lastused = loc;
1024 
1025 	vfsname[0].ctl_name = "mounts";
1026 	vfsname[0].ctl_type = CTLTYPE_NODE;
1027 	vfsvars[0].list = vfsname + 1;
1028 	vfsvars[0].size = maxtypenum - 1;
1029 
1030 	secondlevel[CTL_VFS].list = vfsname;
1031 	secondlevel[CTL_VFS].size = maxtypenum;
1032 	return;
1033 }
1034 
1035 int
1036 sysctl_vfsgen(string, bufpp, mib, flags, typep)
1037 	char *string;
1038 	char **bufpp;
1039 	int mib[];
1040 	int flags;
1041 	int *typep;
1042 {
1043 	int indx;
1044 	size_t size;
1045 	struct vfsconf vfc;
1046 
1047 	if (*bufpp == NULL) {
1048 		listall(string, vfsvars);
1049 		return (-1);
1050 	}
1051 
1052 	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1053 		return (-1);
1054 
1055 	mib[1] = VFS_GENERIC;
1056 	mib[2] = VFS_CONF;
1057 	mib[3] = indx;
1058 	size = sizeof vfc;
1059 	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
1060 		if (errno != EOPNOTSUPP)
1061 			warn("vfs print");
1062 		return -1;
1063 	}
1064 	if (flags == 0 && vfc.vfc_refcount == 0)
1065 		return -1;
1066 	if (!nflag)
1067 		fprintf(stdout, "%s has %d mounted instance%s\n",
1068 		    string, vfc.vfc_refcount,
1069 		    vfc.vfc_refcount != 1 ? "s" : "");
1070 	else
1071 		fprintf(stdout, "%d\n", vfc.vfc_refcount);
1072 
1073 	return -1;
1074 }
1075 
1076 int
1077 sysctl_vfs(string, bufpp, mib, flags, typep)
1078 	char *string;
1079 	char **bufpp;
1080 	int mib[];
1081 	int flags;
1082 	int *typep;
1083 {
1084 	struct list *lp = &vfsvars[mib[1]];
1085 	int indx;
1086 
1087 	if (lp->list == NULL) {
1088 		if (flags)
1089 			warnx("No variables defined for file system %s", string);
1090 		return(-1);
1091 	}
1092 	if (*bufpp == NULL) {
1093 		listall(string, lp);
1094 		return (-1);
1095 	}
1096 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1097 		return (-1);
1098 
1099 	mib[1] = vfs_typenums[mib[1]];
1100 	mib[2] = indx;
1101 	*typep = lp->list[indx].ctl_type;
1102 	return (3);
1103 }
1104 
1105 struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1106 struct list fslist = { posixname, FS_POSIX_MAXID };
1107 
1108 /*
1109  * handle file system requests
1110  */
1111 int
1112 sysctl_fs(string, bufpp, mib, flags, typep)
1113 	char *string;
1114 	char **bufpp;
1115 	int mib[];
1116 	int flags;
1117 	int *typep;
1118 {
1119 	int indx;
1120 
1121 	if (*bufpp == NULL) {
1122 		listall(string, &fslist);
1123 		return(-1);
1124 	}
1125 	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1126 		return(-1);
1127 	mib[2] = indx;
1128 	*typep = fslist.list[indx].ctl_type;
1129 	return(3);
1130 }
1131 
1132 #ifdef CPU_BIOS
1133 struct ctlname biosname[] = CTL_BIOS_NAMES;
1134 struct list bioslist = { biosname, BIOS_MAXID };
1135 
1136 /*
1137  * handle BIOS requests
1138  */
1139 int
1140 sysctl_bios(string, bufpp, mib, flags, typep)
1141 	char *string;
1142 	char **bufpp;
1143 	int mib[];
1144 	int flags;
1145 	int *typep;
1146 {
1147 	char *name;
1148 	int indx;
1149 
1150 	if (*bufpp == NULL) {
1151 		listall(string, &bioslist);
1152 		return(-1);
1153 	}
1154 	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1155 		return(-1);
1156 	mib[2] = indx;
1157 	if (indx == BIOS_DISKINFO) {
1158 		if (*bufpp == NULL) {
1159 			char name[BUFSIZ];
1160 
1161 			/* scan all the bios devices */
1162 			for (indx = 0; indx < 256; indx++) {
1163 				snprintf(name, sizeof(name), "%s.%u",
1164 					 string, indx);
1165 				parse(name, 1);
1166 			}
1167 			return(-1);
1168 		}
1169 		if ((name = strsep(bufpp, ".")) == NULL) {
1170 			warnx("%s: incomplete specification", string);
1171 			return(-1);
1172 		}
1173 		mib[3] = atoi(name);
1174 		*typep = CTLTYPE_STRUCT;
1175 		return(4);
1176 	} else {
1177 		*typep = bioslist.list[indx].ctl_type;
1178 		return(3);
1179 	}
1180 }
1181 #endif
1182 
1183 struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1184 struct list swpenclist = { swpencname, SWPENC_MAXID };
1185 
1186 /*
1187  * handle swap encrypt requests
1188  */
1189 int
1190 sysctl_swpenc(string, bufpp, mib, flags, typep)
1191 	char *string;
1192 	char **bufpp;
1193 	int mib[];
1194 	int flags;
1195 	int *typep;
1196 {
1197 	int indx;
1198 
1199 	if (*bufpp == NULL) {
1200 		listall(string, &swpenclist);
1201 		return(-1);
1202 	}
1203 	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1204 		return(-1);
1205 	mib[2] = indx;
1206 	*typep = swpenclist.list[indx].ctl_type;
1207 	return(3);
1208 }
1209 
1210 struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1211 struct ctlname ipname[] = IPCTL_NAMES;
1212 struct ctlname icmpname[] = ICMPCTL_NAMES;
1213 struct ctlname ipipname[] = IPIPCTL_NAMES;
1214 struct ctlname tcpname[] = TCPCTL_NAMES;
1215 struct ctlname udpname[] = UDPCTL_NAMES;
1216 struct ctlname espname[] = ESPCTL_NAMES;
1217 struct ctlname ahname[] = AHCTL_NAMES;
1218 struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1219 struct ctlname grename[] = GRECTL_NAMES;
1220 struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1221 struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1222 struct list inetlist = { inetname, IPPROTO_MAXID };
1223 struct list inetvars[] = {
1224 	{ ipname, IPCTL_MAXID },	/* ip */
1225 	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1226 	{ 0, 0 },			/* igmp */
1227 	{ 0, 0 },			/* ggmp */
1228 	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1229 	{ 0, 0 },
1230 	{ tcpname, TCPCTL_MAXID },	/* tcp */
1231 	{ 0, 0 },
1232 	{ 0, 0 },			/* egp */
1233 	{ 0, 0 },
1234 	{ 0, 0 },
1235 	{ 0, 0 },
1236 	{ 0, 0 },			/* pup */
1237 	{ 0, 0 },
1238 	{ 0, 0 },
1239 	{ 0, 0 },
1240 	{ 0, 0 },
1241 	{ udpname, UDPCTL_MAXID },	/* udp */
1242 	{ 0, 0 },
1243 	{ 0, 0 },
1244 	{ 0, 0 },
1245 	{ 0, 0 },
1246 	{ 0, 0 },
1247 	{ 0, 0 },
1248 	{ 0, 0 },
1249 	{ 0, 0 },
1250 	{ 0, 0 },
1251 	{ 0, 0 },
1252 	{ 0, 0 },
1253 	{ 0, 0 },
1254 	{ 0, 0 },
1255 	{ 0, 0 },
1256 	{ 0, 0 },
1257 	{ 0, 0 },
1258 	{ 0, 0 },
1259 	{ 0, 0 },
1260 	{ 0, 0 },
1261 	{ 0, 0 },
1262 	{ 0, 0 },
1263 	{ 0, 0 },
1264 	{ 0, 0 },
1265 	{ 0, 0 },
1266 	{ 0, 0 },
1267 	{ 0, 0 },
1268 	{ 0, 0 },
1269 	{ 0, 0 },
1270 	{ 0, 0 },
1271 	{ grename, GRECTL_MAXID }, /* GRE */
1272 	{ 0, 0 },
1273 	{ 0, 0 },
1274 	{ espname, ESPCTL_MAXID },	/* esp */
1275 	{ ahname, AHCTL_MAXID },	/* ah */
1276 	{ 0, 0 },
1277 	{ 0, 0 },
1278 	{ 0, 0 },
1279 	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1280 	{ 0, 0 },
1281 	{ 0, 0 },
1282 	{ 0, 0 },
1283 	{ 0, 0 },
1284 	{ 0, 0 },
1285 	{ 0, 0 },
1286 	{ 0, 0 },
1287 	{ 0, 0 },
1288 	{ 0, 0 },
1289 	{ 0, 0 },
1290 	{ 0, 0 },
1291 	{ 0, 0 },
1292 	{ 0, 0 },
1293 	{ 0, 0 },
1294 	{ 0, 0 },
1295 	{ 0, 0 },
1296 	{ 0, 0 },
1297 	{ 0, 0 },
1298 	{ 0, 0 },
1299 	{ 0, 0 },
1300 	{ 0, 0 },
1301 	{ 0, 0 },
1302 	{ 0, 0 },
1303 	{ 0, 0 },
1304 	{ 0, 0 },
1305 	{ 0, 0 },
1306 	{ 0, 0 },
1307 	{ 0, 0 },
1308 	{ 0, 0 },
1309 	{ 0, 0 },
1310 	{ 0, 0 },
1311 	{ 0, 0 },
1312 	{ 0, 0 },
1313 	{ 0, 0 },
1314 	{ 0, 0 },
1315 	{ 0, 0 },
1316 	{ 0, 0 },
1317 	{ 0, 0 },
1318 	{ 0, 0 },
1319 	{ 0, 0 },
1320 	{ 0, 0 },
1321 	{ etheripname, ETHERIPCTL_MAXID },
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 	{ ipcompname, IPCOMPCTL_MAXID },
1333 };
1334 
1335 struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1336 struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1337 struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1338 struct list ttylist = { ttyname, KERN_TTY_MAXID };
1339 
1340 /*
1341  * handle vfs namei cache statistics
1342  */
1343 int
1344 sysctl_nchstats(string, bufpp, mib, flags, typep)
1345 	char *string;
1346 	char **bufpp;
1347 	int mib[];
1348 	int flags;
1349 	int *typep;
1350 {
1351 	static struct nchstats nch;
1352 	int indx;
1353 	size_t size;
1354 	static int keepvalue = 0;
1355 
1356 	if (*bufpp == NULL) {
1357 		bzero(&nch, sizeof(struct nchstats));
1358 		listall(string, &nchstatslist);
1359 		return(-1);
1360 	}
1361 	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1362 		return(-1);
1363 	mib[2] = indx;
1364 	if (*bufpp != NULL) {
1365 		warnx("fourth level name in %s is invalid", string);
1366 		return(-1);
1367 	}
1368 	if (keepvalue == 0) {
1369 		size = sizeof(struct nchstats);
1370 		if (sysctl(mib, 2, &nch, &size, NULL, 0) < 0)
1371 			return(-1);
1372 		keepvalue = 1;
1373 	}
1374 	if (!nflag)
1375 		(void)printf("%s = ", string);
1376 	switch (indx) {
1377 	case KERN_NCHSTATS_GOODHITS:
1378 		(void)printf("%ld\n", nch.ncs_goodhits);
1379 		break;
1380 	case KERN_NCHSTATS_NEGHITS:
1381 		(void)printf("%ld\n", nch.ncs_neghits);
1382 		break;
1383 	case KERN_NCHSTATS_BADHITS:
1384 		(void)printf("%ld\n", nch.ncs_badhits);
1385 		break;
1386 	case KERN_NCHSTATS_FALSEHITS:
1387 		(void)printf("%ld\n", nch.ncs_falsehits);
1388 		break;
1389 	case KERN_NCHSTATS_MISS:
1390 		(void)printf("%ld\n", nch.ncs_miss);
1391 		break;
1392 	case KERN_NCHSTATS_LONG:
1393 		(void)printf("%ld\n", nch.ncs_long);
1394 		break;
1395 	case KERN_NCHSTATS_PASS2:
1396 		(void)printf("%ld\n", nch.ncs_pass2);
1397 		break;
1398 	case KERN_NCHSTATS_2PASSES:
1399 		(void)printf("%ld\n", nch.ncs_2passes);
1400 		break;
1401 	}
1402 	return(-1);
1403 }
1404 
1405 /*
1406  * handle tty statistics
1407  */
1408 int
1409 sysctl_tty(string, bufpp, mib, flags, typep)
1410 	char *string;
1411 	char **bufpp;
1412 	int mib[];
1413 	int flags;
1414 	int *typep;
1415 {
1416 	int indx;
1417 
1418 	if (*bufpp == NULL) {
1419 		listall(string, &ttylist);
1420 		return(-1);
1421 	}
1422 	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1423 		return(-1);
1424 	mib[2] = indx;
1425 	*typep = CTLTYPE_QUAD;
1426 	return(3);
1427 }
1428 
1429 /*
1430  * handle fork statistics
1431  */
1432 int
1433 sysctl_forkstat(string, bufpp, mib, flags, typep)
1434 	char *string;
1435 	char **bufpp;
1436 	int mib[];
1437 	int flags;
1438 	int *typep;
1439 {
1440 	static struct forkstat fks;
1441 	static int keepvalue = 0;
1442 	int indx;
1443 	size_t size;
1444 
1445 	if (*bufpp == NULL) {
1446 		bzero(&fks, sizeof(struct forkstat));
1447 		listall(string, &forkstatlist);
1448 		return(-1);
1449 	}
1450 	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1451 		return(-1);
1452 	if (*bufpp != NULL) {
1453 		warnx("fourth level name in %s is invalid", string);
1454 		return(-1);
1455 	}
1456 	if (keepvalue == 0) {
1457 		size = sizeof(struct forkstat);
1458 		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0)
1459 			return(-1);
1460 		keepvalue = 1;
1461 	}
1462 	if (!nflag)
1463 		(void)printf("%s = ", string);
1464 	switch (indx)	{
1465 	case KERN_FORKSTAT_FORK:
1466 		(void)printf("%d\n", fks.cntfork);
1467 		break;
1468 	case KERN_FORKSTAT_VFORK:
1469 		(void)printf("%d\n", fks.cntvfork);
1470 		break;
1471 	case KERN_FORKSTAT_RFORK:
1472 		(void)printf("%d\n", fks.cntrfork);
1473 		break;
1474 	case KERN_FORKSTAT_KTHREAD:
1475 		(void)printf("%d\n", fks.cntkthread);
1476 		break;
1477 	case KERN_FORKSTAT_SIZFORK:
1478 		(void)printf("%d\n", fks.sizfork);
1479 		break;
1480 	case KERN_FORKSTAT_SIZVFORK:
1481 		(void)printf("%d\n", fks.sizvfork);
1482 		break;
1483 	case KERN_FORKSTAT_SIZRFORK:
1484 		(void)printf("%d\n", fks.sizrfork);
1485 		break;
1486 	case KERN_FORKSTAT_SIZKTHREAD:
1487 		(void)printf("%d\n", fks.sizkthread);
1488 		break;
1489 	}
1490 	return(-1);
1491 }
1492 
1493 /*
1494  * handle malloc statistics
1495  */
1496 int
1497 sysctl_malloc(string, bufpp, mib, flags, typep)
1498 	char *string;
1499 	char **bufpp;
1500 	int mib[];
1501 	int flags;
1502 	int *typep;
1503 {
1504 	int indx, stor, i;
1505 	char *name, bufp[BUFSIZ], *buf, *ptr;
1506 	struct list lp;
1507 	size_t size;
1508 
1509 	if (*bufpp == NULL) {
1510 		listall(string, &kernmalloclist);
1511 		return(-1);
1512 	}
1513 	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1514 		return(-1);
1515 	mib[2] = indx;
1516 	if (mib[2] == KERN_MALLOC_BUCKET) {
1517 		if ((name = strsep(bufpp, ".")) == NULL) {
1518 			size = BUFSIZ;
1519 			stor = mib[2];
1520 			mib[2] = KERN_MALLOC_BUCKETS;
1521 			buf = bufp;
1522 			if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1523 				return(-1);
1524 			mib[2] = stor;
1525 			for (stor = 0, i = 0; i < size; i++)
1526 				if (buf[i] == ',')
1527 					stor++;
1528 			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1529 			if (lp.list == NULL)
1530 				return(-1);
1531 			lp.size = stor + 2;
1532 			for (i = 1;
1533 			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL;
1534 			    i++) {
1535 				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1536 			}
1537 			lp.list[i].ctl_name = buf;
1538 			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1539 			listall(string, &lp);
1540 			free(lp.list);
1541 			return(-1);
1542 		}
1543 		mib[3] = atoi(name);
1544 		return(4);
1545 	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
1546 		*typep = CTLTYPE_STRING;
1547 		return(3);
1548 	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
1549 		size = BUFSIZ;
1550 		stor = mib[2];
1551 		mib[2] = KERN_MALLOC_KMEMNAMES;
1552 		buf = bufp;
1553 		if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1554 			return(-1);
1555 		mib[2] = stor;
1556 		if ((name = strsep(bufpp, ".")) == NULL) {
1557 			for (stor = 0, i = 0; i < size; i++)
1558 				if (buf[i] == ',')
1559 					stor++;
1560 			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1561 			if (lp.list == NULL)
1562 				return(-1);
1563 			lp.size = stor + 2;
1564 			for (i = 1; (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL; i++) {
1565 				if (lp.list[i].ctl_name[0] == '\0') {
1566 					i--;
1567 					continue;
1568 				}
1569 				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1570 			}
1571 			lp.list[i].ctl_name = buf;
1572 			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1573 			listall(string, &lp);
1574 			free(lp.list);
1575 			return(-1);
1576 		}
1577 		ptr = strstr(buf, name);
1578  tryagain:
1579 		if (ptr == NULL) {
1580 		       warnx("fourth level name %s in %s is invalid", name,
1581 			     string);
1582 		       return(-1);
1583 		}
1584 		if ((*(ptr + strlen(name)) != ',') &&
1585 		    (*(ptr + strlen(name)) != '\0')) {
1586 			ptr = strstr(ptr + 1, name); /* retry */
1587 			goto tryagain;
1588 		}
1589 		if ((ptr != buf) && (*(ptr - 1) != ',')) {
1590 			ptr = strstr(ptr + 1, name); /* retry */
1591 			goto tryagain;
1592 		}
1593 		for (i = 0, stor = 0; buf + i < ptr; i++)
1594 			if (buf[i] == ',')
1595 				stor++;
1596 		mib[3] = stor;
1597 		return(4);
1598 	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
1599 		*typep = CTLTYPE_STRING;
1600 		return(3);
1601 	}
1602 	return(-1);
1603 }
1604 
1605 /*
1606  * handle internet requests
1607  */
1608 int
1609 sysctl_inet(string, bufpp, mib, flags, typep)
1610 	char *string;
1611 	char **bufpp;
1612 	int mib[];
1613 	int flags;
1614 	int *typep;
1615 {
1616 	struct list *lp;
1617 	int indx;
1618 
1619 	if (*bufpp == NULL) {
1620 		listall(string, &inetlist);
1621 		return(-1);
1622 	}
1623 	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1624 		return(-1);
1625 	mib[2] = indx;
1626 	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1627 		lp = &inetvars[indx];
1628 	else if (!flags)
1629 		return(-1);
1630 	else {
1631 		warnx("%s: no variables defined for this protocol", string);
1632 		return(-1);
1633 	}
1634 	if (*bufpp == NULL) {
1635 		listall(string, lp);
1636 		return(-1);
1637 	}
1638 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1639 		return(-1);
1640 	mib[3] = indx;
1641 	*typep = lp->list[indx].ctl_type;
1642 	return(4);
1643 }
1644 
1645 #ifdef INET6
1646 struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1647 struct ctlname ip6name[] = IPV6CTL_NAMES;
1648 struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1649 struct ctlname pim6name[] = PIM6CTL_NAMES;
1650 struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1651 struct list inet6vars[] = {
1652 /*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1653 	{ 0, 0 },
1654 	{ 0, 0 },
1655 	{ 0, 0 },
1656 	{ 0, 0 },
1657 	{ 0, 0 },
1658 /*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1659 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1660 /*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1661 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1662 /*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1663 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1664 /*40*/	{ 0, 0 },
1665 	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1666 	{ 0, 0 },
1667 	{ 0, 0 },
1668 	{ 0, 0 },
1669 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1670 /*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1671 	{ 0, 0 },
1672 	{ 0, 0 },
1673 	{ 0, 0 },
1674 	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1675 	{ 0, 0 },
1676 /*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1677 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1678 /*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1679 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1680 /*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1681 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1682 /*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1683 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1684 /*100*/	{ 0, 0 },
1685 	{ 0, 0 },
1686 	{ 0, 0 },
1687 	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
1688 };
1689 
1690 /*
1691  * handle internet6 requests
1692  */
1693 int
1694 sysctl_inet6(string, bufpp, mib, flags, typep)
1695 	char *string;
1696 	char **bufpp;
1697 	int mib[];
1698 	int flags;
1699 	int *typep;
1700 {
1701 	struct list *lp;
1702 	int indx;
1703 
1704 	if (*bufpp == NULL) {
1705 		listall(string, &inet6list);
1706 		return(-1);
1707 	}
1708 	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
1709 		return(-1);
1710 	mib[2] = indx;
1711 	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
1712 		lp = &inet6vars[indx];
1713 	else if (!flags)
1714 		return(-1);
1715 	else {
1716 		warnx("%s: no variables defined for this protocol", string);
1717 		return(-1);
1718 	}
1719 	if (*bufpp == NULL) {
1720 		listall(string, lp);
1721 		return(-1);
1722 	}
1723 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1724 		return(-1);
1725 	mib[3] = indx;
1726 	*typep = lp->list[indx].ctl_type;
1727 	return(4);
1728 }
1729 #endif
1730 
1731 struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
1732 struct ctlname ipxpname[] = IPXCTL_NAMES;
1733 struct ctlname spxpname[] = SPXCTL_NAMES;
1734 struct list ipxlist = { ipxname, IPXCTL_MAXID };
1735 struct list ipxvars[] = {
1736 	{ ipxpname, IPXCTL_MAXID },	/* ipx */
1737 	{ 0, 0 },
1738 	{ 0, 0 },
1739 	{ 0, 0 },
1740 	{ 0, 0 },
1741 	{ spxpname, SPXCTL_MAXID },
1742 };
1743 
1744 /*
1745  * Handle internet requests
1746  */
1747 int
1748 sysctl_ipx(string, bufpp, mib, flags, typep)
1749 	char *string;
1750 	char **bufpp;
1751 	int mib[];
1752 	int flags;
1753 	int *typep;
1754 {
1755 	struct list *lp;
1756 	int indx;
1757 
1758 	if (*bufpp == NULL) {
1759 		listall(string, &ipxlist);
1760 		return(-1);
1761 	}
1762 	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1763 		return(-1);
1764 	mib[2] = indx;
1765 	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1766 		lp = &ipxvars[indx];
1767 	else if (!flags)
1768 		return(-1);
1769 	else {
1770 		warnx("%s: no variables defined for this protocol", string);
1771 		return(-1);
1772 	}
1773 	if (*bufpp == NULL) {
1774 		listall(string, lp);
1775 		return(-1);
1776 	}
1777 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1778 		return(-1);
1779 	mib[3] = indx;
1780 	*typep = lp->list[indx].ctl_type;
1781 	return(4);
1782 }
1783 
1784 /*
1785  * Scan a list of names searching for a particular name.
1786  */
1787 int
1788 findname(string, level, bufp, namelist)
1789 	char *string;
1790 	char *level;
1791 	char **bufp;
1792 	struct list *namelist;
1793 {
1794 	char *name;
1795 	int i;
1796 
1797 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1798 		warnx("%s: incomplete specification", string);
1799 		return(-1);
1800 	}
1801 	for (i = 0; i < namelist->size; i++)
1802 		if (namelist->list[i].ctl_name != NULL &&
1803 		    strcmp(name, namelist->list[i].ctl_name) == 0)
1804 			break;
1805 	if (i == namelist->size) {
1806 		warnx("%s level name %s in %s is invalid", level, name, string);
1807 		return(-1);
1808 	}
1809 	return(i);
1810 }
1811 
1812 void
1813 usage()
1814 {
1815 
1816 	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
1817 	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
1818 	    "sysctl [-n] -a", "sysctl [-n] -A");
1819 	exit(1);
1820 }
1821