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