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