sysctl.c revision 1.75
1/*	$OpenBSD: sysctl.c,v 1.75 2001/07/13 23:51:35 mickey 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
38static 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
45static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
46#else
47static char *rcsid = "$OpenBSD: sysctl.c,v 1.75 2001/07/13 23:51:35 mickey 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
120struct ctlname topname[] = CTL_NAMES;
121struct ctlname kernname[] = CTL_KERN_NAMES;
122struct ctlname vmname[] = CTL_VM_NAMES;
123struct ctlname fsname[] = CTL_FS_NAMES;
124struct ctlname netname[] = CTL_NET_NAMES;
125struct ctlname hwname[] = CTL_HW_NAMES;
126struct ctlname username[] = CTL_USER_NAMES;
127struct ctlname debugname[CTL_DEBUG_MAXID];
128struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
129struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
130struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
131struct ctlname ttyname[] = CTL_KERN_TTY_NAMES;
132struct ctlname *vfsname;
133#ifdef CTL_MACHDEP_NAMES
134struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
135#endif
136struct ctlname ddbname[] = CTL_DDB_NAMES;
137char names[BUFSIZ];
138int lastused;
139
140struct list {
141	struct	ctlname *list;
142	int	size;
143};
144struct list toplist = { topname, CTL_MAXID };
145struct 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
163int	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 */
183void debuginit __P((void));
184void listall __P((char *, struct list *));
185void parse __P((char *, int));
186void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
187void usage __P((void));
188int findname __P((char *, char *, char **, struct list *));
189int sysctl_inet __P((char *, char **, int *, int, int *));
190#ifdef INET6
191int sysctl_inet6 __P((char *, char **, int *, int, int *));
192#endif
193int sysctl_ipx __P((char *, char **, int *, int, int *));
194int sysctl_fs __P((char *, char **, int *, int, int *));
195static int sysctl_vfs __P((char *, char **, int[], int, int *));
196static int sysctl_vfsgen __P((char *, char **, int[], int, int *));
197int sysctl_bios __P((char *, char **, int *, int, int *));
198int sysctl_swpenc __P((char *, char **, int *, int, int *));
199int sysctl_forkstat __P((char *, char **, int *, int, int *));
200int sysctl_tty __P((char *, char **, int *, int, int *));
201int sysctl_nchstats __P((char *, char **, int *, int, int *));
202int sysctl_malloc __P((char *, char **, int *, int, int *));
203void vfsinit __P((void));
204
205int
206main(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 */
255void
256listall(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 */
284void
285parse(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		}
454		else if (mib[1] == VM_SWAPENCRYPT) {
455			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
456			if (len < 0)
457				return;
458
459			break;
460		}
461		if (flags == 0)
462			return;
463		warnx("use vmstat or systat to view %s information", string);
464		return;
465
466		break;
467
468	case CTL_NET:
469		if (mib[1] == PF_INET) {
470			len = sysctl_inet(string, &bufp, mib, flags, &type);
471			if (len < 0)
472				return;
473
474			if ((mib[2] == IPPROTO_TCP &&
475			     mib[3] == TCPCTL_BADDYNAMIC) ||
476			    (mib[2] == IPPROTO_UDP &&
477			     mib[3] == UDPCTL_BADDYNAMIC)) {
478
479				special |= BADDYNAMIC;
480
481				if (newval != NULL)
482					parse_baddynamic(mib, len, string,
483					    &newval, &newsize, flags, nflag);
484			}
485			break;
486		}
487#ifdef INET6
488		if (mib[1] == PF_INET6) {
489			len = sysctl_inet6(string, &bufp, mib, flags, &type);
490			if (len < 0)
491				return;
492
493			break;
494		}
495#endif
496		if (mib[1] == PF_IPX) {
497			len = sysctl_ipx(string, &bufp, mib, flags, &type);
498			if (len >= 0)
499				break;
500			return;
501		}
502		if (flags == 0)
503			return;
504		warnx("use netstat to view %s information", string);
505		return;
506
507	case CTL_DEBUG:
508		mib[2] = CTL_DEBUG_VALUE;
509		len = 3;
510		break;
511
512	case CTL_MACHDEP:
513#ifdef CPU_CONSDEV
514		if (mib[1] == CPU_CONSDEV)
515			special |= CHRDEV;
516#endif
517#ifdef CPU_BLK2CHR
518		if (mib[1] == CPU_BLK2CHR) {
519			if (bufp == NULL)
520				return;
521			mib[2] = makedev(atoi(bufp),0);
522			bufp = NULL;
523			len = 3;
524			special |= CHRDEV;
525			break;
526		}
527#endif
528#ifdef CPU_CHR2BLK
529		if (mib[1] == CPU_CHR2BLK) {
530			if (bufp == NULL)
531				return;
532			mib[2] = makedev(atoi(bufp),0);
533			bufp = NULL;
534			len = 3;
535			special |= BLKDEV;
536			break;
537		}
538#endif
539#ifdef CPU_BIOS
540		if (mib[1] == CPU_BIOS) {
541			len = sysctl_bios(string, &bufp, mib, flags, &type);
542			if (len < 0)
543				return;
544			if (mib[2] == BIOS_DEV)
545				special |= BIOSDEV;
546			if (mib[2] == BIOS_DISKINFO)
547				special |= BIOSGEO;
548			break;
549		}
550#endif
551		break;
552
553	case CTL_FS:
554		len = sysctl_fs(string, &bufp, mib, flags, &type);
555		if (len >= 0)
556			break;
557		return;
558
559	case CTL_VFS:
560		if (mib[1])
561			len = sysctl_vfs(string, &bufp, mib, flags, &type);
562		else
563			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
564		if (len >= 0) {
565			if (type == CTLTYPE_STRUCT) {
566				if (flags)
567					warnx("use nfsstat to view %s information",
568					    MOUNT_NFS);
569				return;
570			} else
571				break;
572		}
573		return;
574
575	case CTL_USER:
576	case CTL_DDB:
577		break;
578
579	default:
580		warnx("illegal top level value: %d", mib[0]);
581		return;
582
583	}
584	if (bufp) {
585		warnx("name %s in %s is unknown", bufp, string);
586		return;
587	}
588	if (newsize > 0) {
589		switch (type) {
590		case CTLTYPE_INT:
591			errno = 0;
592			if (special & UNSIGNED)
593				intval = strtoul(newval, &cp, 10);
594			else
595				intval = strtol(newval, &cp, 10);
596			if (*cp != '\0') {
597				warnx("%s: illegal value: %s", string,
598				    (char *)newval);
599				return;
600			}
601			if (errno == ERANGE) {
602				warnx("%s: value %s out of range", string,
603				    (char *)newval);
604				return;
605			}
606			newval = &intval;
607			newsize = sizeof(intval);
608			break;
609
610		case CTLTYPE_QUAD:
611			/* XXX - assumes sizeof(long long) == sizeof(quad_t) */
612			(void)sscanf(newval, "%lld", (long long *)&quadval);
613			newval = &quadval;
614			newsize = sizeof(quadval);
615			break;
616		}
617	}
618	size = BUFSIZ;
619	if (sysctl(mib, len, buf, &size, newval, newsize) == -1) {
620		if (flags == 0)
621			return;
622		switch (errno) {
623		case EOPNOTSUPP:
624			warnx("%s: value is not available", string);
625			return;
626		case ENOTDIR:
627			warnx("%s: specification is incomplete", string);
628			return;
629		case ENOMEM:
630			warnx("%s: type is unknown to this program", string);
631			return;
632		case ENXIO:
633			if (special & BIOSGEO)
634				return;
635		default:
636			warn("%s", string);
637			return;
638		}
639	}
640	if (special & KMEMBUCKETS) {
641		struct kmembuckets *kb = (struct kmembuckets *)buf;
642		if (!nflag)
643			(void)printf("%s = ", string);
644		printf("(");
645		printf("calls = %llu ", (long long)kb->kb_calls);
646		printf("total_allocated = %llu ", (long long)kb->kb_total);
647		printf("total_free = %lld ", (long long)kb->kb_totalfree);
648		printf("elements = %lld ", (long long)kb->kb_elmpercl);
649		printf("high watermark = %lld ", (long long)kb->kb_highwat);
650		printf("could_free = %lld", (long long)kb->kb_couldfree);
651		printf(")\n");
652		return;
653	}
654	if (special & KMEMSTATS) {
655		struct kmemstats *km = (struct kmemstats *)buf;
656		int j, first = 1;
657
658		if (!nflag)
659			(void)printf("%s = ", string);
660		(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);
661		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
662		 	if ((km->ks_size & j ) == 0)
663				continue;
664			if (first)
665				(void)printf("%d", j);
666			else
667				(void)printf(",%d", j);
668			first = 0;
669		}
670		if (first)
671			(void)printf("none");
672		(void)printf("))\n");
673		return;
674	}
675	if (special & CLOCK) {
676		struct clockinfo *clkp = (struct clockinfo *)buf;
677
678		if (!nflag)
679			(void)printf("%s = ", string);
680		(void)printf(
681		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
682		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
683		return;
684	}
685	if (special & BOOTTIME) {
686		struct timeval *btp = (struct timeval *)buf;
687		time_t boottime;
688
689		if (!nflag) {
690			boottime = btp->tv_sec;
691			(void)printf("%s = %s", string, ctime(&boottime));
692		} else
693			(void)printf("%ld\n", btp->tv_sec);
694		return;
695	}
696	if (special & BLKDEV) {
697		dev_t dev = *(dev_t *)buf;
698
699		if (!nflag)
700			(void)printf("%s = %s\n", string,
701			    devname(dev, S_IFBLK));
702		else
703			(void)printf("0x%x\n", dev);
704		return;
705	}
706	if (special & CHRDEV) {
707		dev_t dev = *(dev_t *)buf;
708
709		if (!nflag)
710			(void)printf("%s = %s\n", string,
711			    devname(dev, S_IFCHR));
712		else
713			(void)printf("0x%x\n", dev);
714		return;
715	}
716#ifdef CPU_BIOS
717	if (special & BIOSGEO) {
718		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
719
720		if (!nflag)
721			(void)printf("%s = ", string);
722		(void)printf("bootdev = 0x%x, "
723			     "cylinders = %u, heads = %u, sectors = %u\n",
724			     pdi->bsd_dev, pdi->bios_cylinders,
725			     pdi->bios_heads, pdi->bios_sectors);
726		return;
727	}
728	if (special & BIOSDEV) {
729		int dev = *(int*)buf;
730
731		if (!nflag)
732			(void)printf("%s = ", string);
733		(void) printf("0x%02x\n", dev);
734		return;
735	}
736#endif
737	if (special & UNSIGNED) {
738		if (newsize == 0) {
739			if (!nflag)
740				(void)printf("%s = ", string);
741			(void)printf("%u\n", *(u_int *)buf);
742		} else {
743			if (!nflag)
744				(void)printf("%s: %u -> ", string,
745				    *(u_int *)buf);
746			(void)printf("%u\n", *(u_int *)newval);
747		}
748		return;
749	}
750	if (special & RNDSTATS) {
751		struct rndstats *rndstats = (struct rndstats *)buf;
752		int i;
753
754		if (!nflag)
755			(void)printf("%s = ", string);
756		(void)printf(
757		"%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
758		    (unsigned long long)rndstats->rnd_total,
759		    (unsigned long long)rndstats->rnd_used,
760		    (unsigned long long)rndstats->rnd_reads,
761		    (unsigned long long)rndstats->arc4_reads,
762		    (unsigned long long)rndstats->arc4_nstirs,
763		    (unsigned long long)rndstats->arc4_stirs,
764		    (unsigned long long)rndstats->rnd_pad[0],
765		    (unsigned long long)rndstats->rnd_pad[1],
766		    (unsigned long long)rndstats->rnd_pad[2],
767		    (unsigned long long)rndstats->rnd_pad[3],
768		    (unsigned long long)rndstats->rnd_pad[4],
769		    (unsigned long long)rndstats->rnd_waits,
770		    (unsigned long long)rndstats->rnd_enqs,
771		    (unsigned long long)rndstats->rnd_deqs,
772		    (unsigned long long)rndstats->rnd_drops,
773		    (unsigned long long)rndstats->rnd_drople);
774		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]); i++)
775			(void)printf(" %llu", (unsigned long long)rndstats->rnd_ed[i]);
776		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]); i++)
777			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sc[i]);
778		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]); i++)
779			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sb[i]);
780		printf("\n");
781		return;
782	}
783	if (special & BADDYNAMIC) {
784		in_port_t port, lastport;
785		u_int32_t *baddynamic = (u_int32_t *)buf;
786
787		if (!nflag)
788			(void)printf("%s%s", string, newsize ? ": " : " = ");
789		lastport = 0;
790		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
791			if (DP_ISSET(baddynamic, port)) {
792				(void)printf("%s%hd", lastport ? "," : "",
793				    port);
794				lastport = port;
795			}
796		if (newsize != 0) {
797			if (!nflag)
798				fputs(" -> ", stdout);
799			baddynamic = (u_int32_t *)newval;
800			lastport = 0;
801			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
802			    port++)
803				if (DP_ISSET(baddynamic, port)) {
804					(void)printf("%s%hd",
805					    lastport ? "," : "", port);
806					lastport = port;
807				}
808		}
809		(void)putchar('\n');
810		return;
811	}
812	if (special & LONGARRAY) {
813		long *la = (long *)buf;
814		if (!nflag)
815			printf("%s = ", string);
816		while (lal--)
817			printf("%ld%s", *la++, lal? ",":"");
818		putchar('\n');
819		return;
820	}
821	switch (type) {
822	case CTLTYPE_INT:
823		if (newsize == 0) {
824			if (!nflag)
825				(void)printf("%s = ", string);
826			(void)printf("%d\n", *(int *)buf);
827		} else {
828			if (!nflag)
829				(void)printf("%s: %d -> ", string,
830				    *(int *)buf);
831			(void)printf("%d\n", *(int *)newval);
832		}
833		return;
834
835	case CTLTYPE_STRING:
836		if (newval == NULL) {
837			if (!nflag)
838				(void)printf("%s = ", string);
839			(void)puts(buf);
840		} else {
841			if (!nflag)
842				(void)printf("%s: %s -> ", string, buf);
843			(void)puts((char *)newval);
844		}
845		return;
846
847	case CTLTYPE_QUAD:
848		if (newsize == 0) {
849			long long tmp = *(quad_t *)buf;
850
851			if (!nflag)
852				(void)printf("%s = ", string);
853			(void)printf("%lld\n", tmp);
854		} else {
855			long long tmp = *(quad_t *)buf;
856
857			if (!nflag)
858				(void)printf("%s: %lld -> ", string, tmp);
859			tmp = *(quad_t *)newval;
860			(void)printf("%qd\n", tmp);
861		}
862		return;
863
864	case CTLTYPE_STRUCT:
865		warnx("%s: unknown structure returned", string);
866		return;
867
868	default:
869	case CTLTYPE_NODE:
870		warnx("%s: unknown type returned", string);
871		return;
872	}
873}
874
875void
876parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
877	int mib[];
878	size_t len;
879	char *string;
880	void **newvalp;
881	size_t *newsizep;
882	int flags;
883	int nflag;
884{
885	static u_int32_t newbaddynamic[DP_MAPSIZE];
886	in_port_t port;
887	size_t size;
888	char action, *cp;
889
890	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
891		size = sizeof(newbaddynamic);
892		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
893			if (flags == 0)
894				return;
895			if (!nflag)
896				(void)printf("%s: ", string);
897			(void)puts("kernel does contain bad dynamic port tables");
898			return;
899		}
900
901		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
902			if (*cp != '+' && *cp != '-')
903				errx(1, "cannot mix +/- with full list");
904			action = *cp++;
905			port = atoi(cp);
906			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
907				errx(1, "invalid port, range is %d to %d",
908				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
909			if (action == '+')
910				DP_SET(newbaddynamic, port);
911			else
912				DP_CLR(newbaddynamic, port);
913		}
914	} else {
915		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
916		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
917			port = atoi(cp);
918			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
919				errx(1, "invalid port, range is %d to %d",
920				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
921			DP_SET(newbaddynamic, port);
922		}
923	}
924
925	*newvalp = (void *)newbaddynamic;
926	*newsizep = sizeof(newbaddynamic);
927}
928
929/*
930 * Initialize the set of debugging names
931 */
932void
933debuginit()
934{
935	int mib[3], loc, i;
936	size_t size;
937
938	if (secondlevel[CTL_DEBUG].list != 0)
939		return;
940	secondlevel[CTL_DEBUG].list = debugname;
941	mib[0] = CTL_DEBUG;
942	mib[2] = CTL_DEBUG_NAME;
943	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
944		mib[1] = i;
945		size = BUFSIZ - loc;
946		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
947			continue;
948		debugname[i].ctl_name = &names[loc];
949		debugname[i].ctl_type = CTLTYPE_INT;
950		loc += size;
951	}
952	lastused = loc;
953}
954
955struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
956struct ctlname ffsname[] = FFS_NAMES;
957struct ctlname nfsname[] = FS_NFS_NAMES;
958struct list *vfsvars;
959int *vfs_typenums;
960
961/*
962 * Initialize the set of filesystem names
963 */
964void
965vfsinit()
966{
967	int mib[4], maxtypenum, cnt, loc, size;
968	struct vfsconf vfc;
969	size_t buflen;
970
971	if (secondlevel[CTL_VFS].list != 0)
972		return;
973	mib[0] = CTL_VFS;
974	mib[1] = VFS_GENERIC;
975	mib[2] = VFS_MAXTYPENUM;
976	buflen = 4;
977	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
978		return;
979	maxtypenum++;	/* + generic */
980	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
981		return;
982	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
983	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
984		free(vfs_typenums);
985		return;
986	}
987	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
988	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
989		free(vfs_typenums);
990		free(vfsvars);
991		return;
992	}
993	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
994	mib[2] = VFS_CONF;
995	buflen = sizeof vfc;
996	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
997		mib[3] = cnt - 1;
998		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
999			if (errno == EOPNOTSUPP)
1000				continue;
1001			warn("vfsinit");
1002			free(vfsname);
1003			return;
1004		}
1005		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1006			vfsvars[cnt].list = ffsname;
1007			vfsvars[cnt].size = FFS_MAXID;
1008		}
1009		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1010			vfsvars[cnt].list = nfsname;
1011			vfsvars[cnt].size = NFS_MAXID;
1012		}
1013		vfs_typenums[cnt] = vfc.vfc_typenum;
1014		strcat(&names[loc], vfc.vfc_name);
1015		vfsname[cnt].ctl_name = &names[loc];
1016		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1017		size = strlen(vfc.vfc_name) + 1;
1018		loc += size;
1019	}
1020	lastused = loc;
1021
1022	vfsname[0].ctl_name = "mounts";
1023	vfsname[0].ctl_type = CTLTYPE_NODE;
1024	vfsvars[0].list = vfsname + 1;
1025	vfsvars[0].size = maxtypenum - 1;
1026
1027	secondlevel[CTL_VFS].list = vfsname;
1028	secondlevel[CTL_VFS].size = maxtypenum;
1029	return;
1030}
1031
1032int
1033sysctl_vfsgen(string, bufpp, mib, flags, typep)
1034	char *string;
1035	char **bufpp;
1036	int mib[];
1037	int flags;
1038	int *typep;
1039{
1040	int indx;
1041	size_t size;
1042	struct vfsconf vfc;
1043
1044	if (*bufpp == NULL) {
1045		listall(string, vfsvars);
1046		return (-1);
1047	}
1048
1049	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1050		return (-1);
1051
1052	mib[1] = VFS_GENERIC;
1053	mib[2] = VFS_CONF;
1054	mib[3] = indx;
1055	size = sizeof vfc;
1056	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
1057		if (errno != EOPNOTSUPP)
1058			warn("vfs print");
1059		return -1;
1060	}
1061	if (flags == 0 && vfc.vfc_refcount == 0)
1062		return -1;
1063	if (!nflag)
1064		fprintf(stdout, "%s has %d mounted instance%s\n",
1065		    string, vfc.vfc_refcount,
1066		    vfc.vfc_refcount != 1 ? "s" : "");
1067	else
1068		fprintf(stdout, "%d\n", vfc.vfc_refcount);
1069
1070	return -1;
1071}
1072
1073int
1074sysctl_vfs(string, bufpp, mib, flags, typep)
1075	char *string;
1076	char **bufpp;
1077	int mib[];
1078	int flags;
1079	int *typep;
1080{
1081	struct list *lp = &vfsvars[mib[1]];
1082	int indx;
1083
1084	if (lp->list == NULL) {
1085		if (flags)
1086			warnx("No variables defined for file system %s", string);
1087		return(-1);
1088	}
1089	if (*bufpp == NULL) {
1090		listall(string, lp);
1091		return (-1);
1092	}
1093	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1094		return (-1);
1095
1096	mib[1] = vfs_typenums[mib[1]];
1097	mib[2] = indx;
1098	*typep = lp->list[indx].ctl_type;
1099	return (3);
1100}
1101
1102struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1103struct list fslist = { posixname, FS_POSIX_MAXID };
1104
1105/*
1106 * handle file system requests
1107 */
1108int
1109sysctl_fs(string, bufpp, mib, flags, typep)
1110	char *string;
1111	char **bufpp;
1112	int mib[];
1113	int flags;
1114	int *typep;
1115{
1116	int indx;
1117
1118	if (*bufpp == NULL) {
1119		listall(string, &fslist);
1120		return(-1);
1121	}
1122	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1123		return(-1);
1124	mib[2] = indx;
1125	*typep = fslist.list[indx].ctl_type;
1126	return(3);
1127}
1128
1129#ifdef CPU_BIOS
1130struct ctlname biosname[] = CTL_BIOS_NAMES;
1131struct list bioslist = { biosname, BIOS_MAXID };
1132
1133/*
1134 * handle BIOS requests
1135 */
1136int
1137sysctl_bios(string, bufpp, mib, flags, typep)
1138	char *string;
1139	char **bufpp;
1140	int mib[];
1141	int flags;
1142	int *typep;
1143{
1144	char *name;
1145	int indx;
1146
1147	if (*bufpp == NULL) {
1148		listall(string, &bioslist);
1149		return(-1);
1150	}
1151	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1152		return(-1);
1153	mib[2] = indx;
1154	if (indx == BIOS_DISKINFO) {
1155		if (*bufpp == NULL) {
1156			char name[BUFSIZ];
1157
1158			/* scan all the bios devices */
1159			for (indx = 0; indx < 256; indx++) {
1160				snprintf(name, sizeof(name), "%s.%u",
1161					 string, indx);
1162				parse(name, 1);
1163			}
1164			return(-1);
1165		}
1166		if ((name = strsep(bufpp, ".")) == NULL) {
1167			warnx("%s: incomplete specification", string);
1168			return(-1);
1169		}
1170		mib[3] = atoi(name);
1171		*typep = CTLTYPE_STRUCT;
1172		return(4);
1173	} else {
1174		*typep = bioslist.list[indx].ctl_type;
1175		return(3);
1176	}
1177}
1178#endif
1179
1180struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1181struct list swpenclist = { swpencname, SWPENC_MAXID };
1182
1183/*
1184 * handle swap encrypt requests
1185 */
1186int
1187sysctl_swpenc(string, bufpp, mib, flags, typep)
1188	char *string;
1189	char **bufpp;
1190	int mib[];
1191	int flags;
1192	int *typep;
1193{
1194	int indx;
1195
1196	if (*bufpp == NULL) {
1197		listall(string, &swpenclist);
1198		return(-1);
1199	}
1200	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1201		return(-1);
1202	mib[2] = indx;
1203	*typep = swpenclist.list[indx].ctl_type;
1204	return(3);
1205}
1206
1207struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1208struct ctlname ipname[] = IPCTL_NAMES;
1209struct ctlname icmpname[] = ICMPCTL_NAMES;
1210struct ctlname ipipname[] = IPIPCTL_NAMES;
1211struct ctlname tcpname[] = TCPCTL_NAMES;
1212struct ctlname udpname[] = UDPCTL_NAMES;
1213struct ctlname espname[] = ESPCTL_NAMES;
1214struct ctlname ahname[] = AHCTL_NAMES;
1215struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1216struct ctlname grename[] = GRECTL_NAMES;
1217struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1218struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1219struct list inetlist = { inetname, IPPROTO_MAXID };
1220struct list inetvars[] = {
1221	{ ipname, IPCTL_MAXID },	/* ip */
1222	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1223	{ 0, 0 },			/* igmp */
1224	{ 0, 0 },			/* ggmp */
1225	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1226	{ 0, 0 },
1227	{ tcpname, TCPCTL_MAXID },	/* tcp */
1228	{ 0, 0 },
1229	{ 0, 0 },			/* egp */
1230	{ 0, 0 },
1231	{ 0, 0 },
1232	{ 0, 0 },
1233	{ 0, 0 },			/* pup */
1234	{ 0, 0 },
1235	{ 0, 0 },
1236	{ 0, 0 },
1237	{ 0, 0 },
1238	{ udpname, UDPCTL_MAXID },	/* udp */
1239	{ 0, 0 },
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	{ grename, GRECTL_MAXID }, /* GRE */
1269	{ 0, 0 },
1270	{ 0, 0 },
1271	{ espname, ESPCTL_MAXID },	/* esp */
1272	{ ahname, AHCTL_MAXID },	/* ah */
1273	{ 0, 0 },
1274	{ 0, 0 },
1275	{ 0, 0 },
1276	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1277	{ 0, 0 },
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	{ etheripname, ETHERIPCTL_MAXID },
1319	{ 0, 0 },
1320	{ 0, 0 },
1321	{ 0, 0 },
1322	{ 0, 0 },
1323	{ 0, 0 },
1324	{ 0, 0 },
1325	{ 0, 0 },
1326	{ 0, 0 },
1327	{ 0, 0 },
1328	{ 0, 0 },
1329	{ ipcompname, IPCOMPCTL_MAXID },
1330};
1331
1332struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1333struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1334struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1335struct list ttylist = { ttyname, KERN_TTY_MAXID };
1336
1337/*
1338 * handle vfs namei cache statistics
1339 */
1340int
1341sysctl_nchstats(string, bufpp, mib, flags, typep)
1342	char *string;
1343	char **bufpp;
1344	int mib[];
1345	int flags;
1346	int *typep;
1347{
1348	static struct nchstats nch;
1349	int indx;
1350	size_t size;
1351	static int keepvalue = 0;
1352
1353	if (*bufpp == NULL) {
1354		bzero(&nch, sizeof(struct nchstats));
1355		listall(string, &nchstatslist);
1356		return(-1);
1357	}
1358	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1359		return(-1);
1360	mib[2] = indx;
1361	if (*bufpp != NULL) {
1362		warnx("fourth level name in %s is invalid", string);
1363		return(-1);
1364	}
1365	if (keepvalue == 0) {
1366		size = sizeof(struct nchstats);
1367		if (sysctl(mib, 2, &nch, &size, NULL, 0) < 0)
1368			return(-1);
1369		keepvalue = 1;
1370	}
1371	if (!nflag)
1372		(void)printf("%s = ", string);
1373	switch (indx) {
1374	case KERN_NCHSTATS_GOODHITS:
1375		(void)printf("%ld\n", nch.ncs_goodhits);
1376		break;
1377	case KERN_NCHSTATS_NEGHITS:
1378		(void)printf("%ld\n", nch.ncs_neghits);
1379		break;
1380	case KERN_NCHSTATS_BADHITS:
1381		(void)printf("%ld\n", nch.ncs_badhits);
1382		break;
1383	case KERN_NCHSTATS_FALSEHITS:
1384		(void)printf("%ld\n", nch.ncs_falsehits);
1385		break;
1386	case KERN_NCHSTATS_MISS:
1387		(void)printf("%ld\n", nch.ncs_miss);
1388		break;
1389	case KERN_NCHSTATS_LONG:
1390		(void)printf("%ld\n", nch.ncs_long);
1391		break;
1392	case KERN_NCHSTATS_PASS2:
1393		(void)printf("%ld\n", nch.ncs_pass2);
1394		break;
1395	case KERN_NCHSTATS_2PASSES:
1396		(void)printf("%ld\n", nch.ncs_2passes);
1397		break;
1398	}
1399	return(-1);
1400}
1401
1402/*
1403 * handle tty statistics
1404 */
1405int
1406sysctl_tty(string, bufpp, mib, flags, typep)
1407	char *string;
1408	char **bufpp;
1409	int mib[];
1410	int flags;
1411	int *typep;
1412{
1413	int indx;
1414
1415	if (*bufpp == NULL) {
1416		listall(string, &ttylist);
1417		return(-1);
1418	}
1419	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1420		return(-1);
1421	mib[2] = indx;
1422	*typep = CTLTYPE_QUAD;
1423	return(3);
1424}
1425
1426/*
1427 * handle fork statistics
1428 */
1429int
1430sysctl_forkstat(string, bufpp, mib, flags, typep)
1431	char *string;
1432	char **bufpp;
1433	int mib[];
1434	int flags;
1435	int *typep;
1436{
1437	static struct forkstat fks;
1438	static int keepvalue = 0;
1439	int indx;
1440	size_t size;
1441
1442	if (*bufpp == NULL) {
1443		bzero(&fks, sizeof(struct forkstat));
1444		listall(string, &forkstatlist);
1445		return(-1);
1446	}
1447	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1448		return(-1);
1449	if (*bufpp != NULL) {
1450		warnx("fourth level name in %s is invalid", string);
1451		return(-1);
1452	}
1453	if (keepvalue == 0) {
1454		size = sizeof(struct forkstat);
1455		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0)
1456			return(-1);
1457		keepvalue = 1;
1458	}
1459	if (!nflag)
1460		(void)printf("%s = ", string);
1461	switch (indx)	{
1462	case KERN_FORKSTAT_FORK:
1463		(void)printf("%d\n", fks.cntfork);
1464		break;
1465	case KERN_FORKSTAT_VFORK:
1466		(void)printf("%d\n", fks.cntvfork);
1467		break;
1468	case KERN_FORKSTAT_RFORK:
1469		(void)printf("%d\n", fks.cntrfork);
1470		break;
1471	case KERN_FORKSTAT_KTHREAD:
1472		(void)printf("%d\n", fks.cntkthread);
1473		break;
1474	case KERN_FORKSTAT_SIZFORK:
1475		(void)printf("%d\n", fks.sizfork);
1476		break;
1477	case KERN_FORKSTAT_SIZVFORK:
1478		(void)printf("%d\n", fks.sizvfork);
1479		break;
1480	case KERN_FORKSTAT_SIZRFORK:
1481		(void)printf("%d\n", fks.sizrfork);
1482		break;
1483	case KERN_FORKSTAT_SIZKTHREAD:
1484		(void)printf("%d\n", fks.sizkthread);
1485		break;
1486	}
1487	return(-1);
1488}
1489
1490/*
1491 * handle malloc statistics
1492 */
1493int
1494sysctl_malloc(string, bufpp, mib, flags, typep)
1495	char *string;
1496	char **bufpp;
1497	int mib[];
1498	int flags;
1499	int *typep;
1500{
1501	int indx, stor, i;
1502	char *name, bufp[BUFSIZ], *buf, *ptr;
1503	struct list lp;
1504	size_t size;
1505
1506	if (*bufpp == NULL) {
1507		listall(string, &kernmalloclist);
1508		return(-1);
1509	}
1510	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1511		return(-1);
1512	mib[2] = indx;
1513	if (mib[2] == KERN_MALLOC_BUCKET) {
1514		if ((name = strsep(bufpp, ".")) == NULL) {
1515			size = BUFSIZ;
1516			stor = mib[2];
1517			mib[2] = KERN_MALLOC_BUCKETS;
1518			buf = bufp;
1519			if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1520				return(-1);
1521			mib[2] = stor;
1522			for (stor = 0, i = 0; i < size; i++)
1523				if (buf[i] == ',')
1524					stor++;
1525			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1526			if (lp.list == NULL)
1527				return(-1);
1528			lp.size = stor + 2;
1529			for (i = 1;
1530			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL;
1531			    i++) {
1532				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1533			}
1534			lp.list[i].ctl_name = buf;
1535			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1536			listall(string, &lp);
1537			free(lp.list);
1538			return(-1);
1539		}
1540		mib[3] = atoi(name);
1541		return(4);
1542	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
1543		*typep = CTLTYPE_STRING;
1544		return(3);
1545	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
1546		size = BUFSIZ;
1547		stor = mib[2];
1548		mib[2] = KERN_MALLOC_KMEMNAMES;
1549		buf = bufp;
1550		if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1551			return(-1);
1552		mib[2] = stor;
1553		if ((name = strsep(bufpp, ".")) == NULL) {
1554			for (stor = 0, i = 0; i < size; i++)
1555				if (buf[i] == ',')
1556					stor++;
1557			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1558			if (lp.list == NULL)
1559				return(-1);
1560			lp.size = stor + 2;
1561			for (i = 1; (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL; i++) {
1562				if (lp.list[i].ctl_name[0] == '\0') {
1563					i--;
1564					continue;
1565				}
1566				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1567			}
1568			lp.list[i].ctl_name = buf;
1569			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1570			listall(string, &lp);
1571			free(lp.list);
1572			return(-1);
1573		}
1574		ptr = strstr(buf, name);
1575 tryagain:
1576		if (ptr == NULL) {
1577		       warnx("fourth level name %s in %s is invalid", name,
1578			     string);
1579		       return(-1);
1580		}
1581		if ((*(ptr + strlen(name)) != ',') &&
1582		    (*(ptr + strlen(name)) != '\0')) {
1583			ptr = strstr(ptr + 1, name); /* retry */
1584			goto tryagain;
1585		}
1586		if ((ptr != buf) && (*(ptr - 1) != ',')) {
1587			ptr = strstr(ptr + 1, name); /* retry */
1588			goto tryagain;
1589		}
1590		for (i = 0, stor = 0; buf + i < ptr; i++)
1591			if (buf[i] == ',')
1592				stor++;
1593		mib[3] = stor;
1594		return(4);
1595	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
1596		*typep = CTLTYPE_STRING;
1597		return(3);
1598	}
1599	return(-1);
1600}
1601
1602/*
1603 * handle internet requests
1604 */
1605int
1606sysctl_inet(string, bufpp, mib, flags, typep)
1607	char *string;
1608	char **bufpp;
1609	int mib[];
1610	int flags;
1611	int *typep;
1612{
1613	struct list *lp;
1614	int indx;
1615
1616	if (*bufpp == NULL) {
1617		listall(string, &inetlist);
1618		return(-1);
1619	}
1620	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1621		return(-1);
1622	mib[2] = indx;
1623	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1624		lp = &inetvars[indx];
1625	else if (!flags)
1626		return(-1);
1627	else {
1628		warnx("%s: no variables defined for this protocol", string);
1629		return(-1);
1630	}
1631	if (*bufpp == NULL) {
1632		listall(string, lp);
1633		return(-1);
1634	}
1635	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1636		return(-1);
1637	mib[3] = indx;
1638	*typep = lp->list[indx].ctl_type;
1639	return(4);
1640}
1641
1642#ifdef INET6
1643struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1644struct ctlname ip6name[] = IPV6CTL_NAMES;
1645struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1646struct ctlname pim6name[] = PIM6CTL_NAMES;
1647struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1648struct list inet6vars[] = {
1649/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1650	{ 0, 0 },
1651	{ 0, 0 },
1652	{ 0, 0 },
1653	{ 0, 0 },
1654	{ 0, 0 },
1655/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1656	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1657/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1658	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1659/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1660	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1661/*40*/	{ 0, 0 },
1662	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1663	{ 0, 0 },
1664	{ 0, 0 },
1665	{ 0, 0 },
1666	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1667/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1668	{ 0, 0 },
1669	{ 0, 0 },
1670	{ 0, 0 },
1671	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1672	{ 0, 0 },
1673/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1674	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1675/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1676	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1677/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1678	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1679/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1680	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1681/*100*/	{ 0, 0 },
1682	{ 0, 0 },
1683	{ 0, 0 },
1684	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
1685};
1686
1687/*
1688 * handle internet6 requests
1689 */
1690int
1691sysctl_inet6(string, bufpp, mib, flags, typep)
1692	char *string;
1693	char **bufpp;
1694	int mib[];
1695	int flags;
1696	int *typep;
1697{
1698	struct list *lp;
1699	int indx;
1700
1701	if (*bufpp == NULL) {
1702		listall(string, &inet6list);
1703		return(-1);
1704	}
1705	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
1706		return(-1);
1707	mib[2] = indx;
1708	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
1709		lp = &inet6vars[indx];
1710	else if (!flags)
1711		return(-1);
1712	else {
1713		warnx("%s: no variables defined for this protocol", string);
1714		return(-1);
1715	}
1716	if (*bufpp == NULL) {
1717		listall(string, lp);
1718		return(-1);
1719	}
1720	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1721		return(-1);
1722	mib[3] = indx;
1723	*typep = lp->list[indx].ctl_type;
1724	return(4);
1725}
1726#endif
1727
1728struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
1729struct ctlname ipxpname[] = IPXCTL_NAMES;
1730struct ctlname spxpname[] = SPXCTL_NAMES;
1731struct list ipxlist = { ipxname, IPXCTL_MAXID };
1732struct list ipxvars[] = {
1733	{ ipxpname, IPXCTL_MAXID },	/* ipx */
1734	{ 0, 0 },
1735	{ 0, 0 },
1736	{ 0, 0 },
1737	{ 0, 0 },
1738	{ spxpname, SPXCTL_MAXID },
1739};
1740
1741/*
1742 * Handle internet requests
1743 */
1744int
1745sysctl_ipx(string, bufpp, mib, flags, typep)
1746	char *string;
1747	char **bufpp;
1748	int mib[];
1749	int flags;
1750	int *typep;
1751{
1752	struct list *lp;
1753	int indx;
1754
1755	if (*bufpp == NULL) {
1756		listall(string, &ipxlist);
1757		return(-1);
1758	}
1759	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1760		return(-1);
1761	mib[2] = indx;
1762	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1763		lp = &ipxvars[indx];
1764	else if (!flags)
1765		return(-1);
1766	else {
1767		warnx("%s: no variables defined for this protocol", string);
1768		return(-1);
1769	}
1770	if (*bufpp == NULL) {
1771		listall(string, lp);
1772		return(-1);
1773	}
1774	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1775		return(-1);
1776	mib[3] = indx;
1777	*typep = lp->list[indx].ctl_type;
1778	return(4);
1779}
1780
1781/*
1782 * Scan a list of names searching for a particular name.
1783 */
1784int
1785findname(string, level, bufp, namelist)
1786	char *string;
1787	char *level;
1788	char **bufp;
1789	struct list *namelist;
1790{
1791	char *name;
1792	int i;
1793
1794	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1795		warnx("%s: incomplete specification", string);
1796		return(-1);
1797	}
1798	for (i = 0; i < namelist->size; i++)
1799		if (namelist->list[i].ctl_name != NULL &&
1800		    strcmp(name, namelist->list[i].ctl_name) == 0)
1801			break;
1802	if (i == namelist->size) {
1803		warnx("%s level name %s in %s is invalid", level, name, string);
1804		return(-1);
1805	}
1806	return(i);
1807}
1808
1809void
1810usage()
1811{
1812
1813	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
1814	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
1815	    "sysctl [-n] -a", "sysctl [-n] -A");
1816	exit(1);
1817}
1818