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