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