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