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