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