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