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