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