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