sysctl.c revision 1.164
1/*	$OpenBSD: sysctl.c,v 1.164 2009/09/08 17:52:17 michele 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.164 2009/09/08 17:52:17 michele 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/igmp_var.h>
76#include <netinet/ip_var.h>
77#include <netinet/udp.h>
78#include <netinet/udp_var.h>
79#include <netinet/tcp.h>
80#include <netinet/tcp_timer.h>
81#include <netinet/tcp_var.h>
82#include <netinet/ip_gre.h>
83#include <netinet/ip_ipcomp.h>
84#include <netinet/ip_carp.h>
85
86#include <net/pfvar.h>
87#include <net/if_pfsync.h>
88
89#ifdef INET6
90#include <netinet/ip6.h>
91#include <netinet/icmp6.h>
92#include <netinet6/ip6_var.h>
93#include <netinet6/pim6_var.h>
94#endif
95
96#include <netmpls/mpls.h>
97
98#include <uvm/uvm_swap_encrypt.h>
99
100#include <ufs/ufs/quota.h>
101#include <ufs/ufs/inode.h>
102#include <ufs/ffs/fs.h>
103#include <ufs/ffs/ffs_extern.h>
104
105#include <nfs/rpcv2.h>
106#include <nfs/nfsproto.h>
107#include <nfs/nfs.h>
108
109#include <ddb/db_var.h>
110#include <dev/rndvar.h>
111
112#include <err.h>
113#include <errno.h>
114#include <stdio.h>
115#include <stdlib.h>
116#include <string.h>
117#include <ctype.h>
118
119#ifdef CPU_BIOS
120#include <machine/biosvar.h>
121#endif
122
123struct ctlname topname[] = CTL_NAMES;
124struct ctlname kernname[] = CTL_KERN_NAMES;
125struct ctlname vmname[] = CTL_VM_NAMES;
126struct ctlname fsname[] = CTL_FS_NAMES;
127struct ctlname netname[] = CTL_NET_NAMES;
128struct ctlname hwname[] = CTL_HW_NAMES;
129struct ctlname username[] = CTL_USER_NAMES;
130struct ctlname debugname[CTL_DEBUG_MAXID];
131struct ctlname kernmallocname[] = CTL_KERN_MALLOC_NAMES;
132struct ctlname forkstatname[] = CTL_KERN_FORKSTAT_NAMES;
133struct ctlname nchstatsname[] = CTL_KERN_NCHSTATS_NAMES;
134struct ctlname ttysname[] = CTL_KERN_TTY_NAMES;
135struct ctlname semname[] = CTL_KERN_SEMINFO_NAMES;
136struct ctlname shmname[] = CTL_KERN_SHMINFO_NAMES;
137struct ctlname watchdogname[] = CTL_KERN_WATCHDOG_NAMES;
138struct ctlname tcname[] = CTL_KERN_TIMECOUNTER_NAMES;
139struct ctlname *vfsname;
140#ifdef CTL_MACHDEP_NAMES
141struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
142#endif
143struct ctlname ddbname[] = CTL_DDB_NAMES;
144char names[BUFSIZ];
145int lastused;
146
147/* Maximum size object to expect from sysctl(3) */
148#define SYSCTL_BUFSIZ	8192
149
150struct list {
151	struct	ctlname *list;
152	int	size;
153};
154struct list toplist = { topname, CTL_MAXID };
155struct list secondlevel[] = {
156	{ 0, 0 },			/* CTL_UNSPEC */
157	{ kernname, KERN_MAXID },	/* CTL_KERN */
158	{ vmname, VM_MAXID },		/* CTL_VM */
159	{ fsname, FS_MAXID },		/* CTL_FS */
160	{ netname, NET_MAXID },		/* CTL_NET */
161	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
162	{ hwname, HW_MAXID },		/* CTL_HW */
163#ifdef CTL_MACHDEP_NAMES
164	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
165#else
166	{ 0, 0 },			/* CTL_MACHDEP */
167#endif
168	{ username, USER_MAXID },	/* CTL_USER_NAMES */
169	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
170	{ 0, 0 },			/* CTL_VFS */
171};
172
173int	Aflag, aflag, nflag, qflag;
174
175/*
176 * Variables requiring special processing.
177 */
178#define	CLOCK		0x00000001
179#define	BOOTTIME	0x00000002
180#define	CHRDEV		0x00000004
181#define	BLKDEV		0x00000008
182#define	RNDSTATS	0x00000010
183#define	BADDYNAMIC	0x00000020
184#define	BIOSGEO		0x00000040
185#define	BIOSDEV		0x00000080
186#define	MAJ2DEV		0x00000100
187#define	UNSIGNED	0x00000200
188#define	KMEMBUCKETS	0x00000400
189#define	LONGARRAY	0x00000800
190#define	KMEMSTATS	0x00001000
191#define	SENSORS		0x00002000
192
193/* prototypes */
194void debuginit(void);
195void listall(char *, struct list *);
196void parse(char *, int);
197void parse_baddynamic(int *, size_t, char *, void **, size_t *, int, int);
198void usage(void);
199int findname(char *, char *, char **, struct list *);
200int sysctl_inet(char *, char **, int *, int, int *);
201#ifdef INET6
202int sysctl_inet6(char *, char **, int *, int, int *);
203#endif
204int sysctl_bpf(char *, char **, int *, int, int *);
205int sysctl_mpls(char *, char **, int *, int, int *);
206int sysctl_fs(char *, char **, int *, int, int *);
207static int sysctl_vfs(char *, char **, int[], int, int *);
208static int sysctl_vfsgen(char *, char **, int[], int, int *);
209int sysctl_bios(char *, char **, int *, int, int *);
210int sysctl_swpenc(char *, char **, int *, int, int *);
211int sysctl_forkstat(char *, char **, int *, int, int *);
212int sysctl_tty(char *, char **, int *, int, int *);
213int sysctl_nchstats(char *, char **, int *, int, int *);
214int sysctl_malloc(char *, char **, int *, int, int *);
215int sysctl_seminfo(char *, char **, int *, int, int *);
216int sysctl_shminfo(char *, char **, int *, int, int *);
217int sysctl_watchdog(char *, char **, int *, int, int *);
218int sysctl_tc(char *, char **, int *, int, int *);
219int sysctl_sensors(char *, char **, int *, int, int *);
220void print_sensordev(char *, int *, u_int, struct sensordev *);
221void print_sensor(struct sensor *);
222int sysctl_emul(char *, char *, int);
223#ifdef CPU_CHIPSET
224int sysctl_chipset(char *, char **, int *, int, int *);
225#endif
226void vfsinit(void);
227
228char *equ = "=";
229
230int
231main(int argc, char *argv[])
232{
233	int ch, lvl1;
234
235	while ((ch = getopt(argc, argv, "Aanqw")) != -1) {
236		switch (ch) {
237
238		case 'A':
239			Aflag = 1;
240			break;
241
242		case 'a':
243			aflag = 1;
244			break;
245
246		case 'n':
247			nflag = 1;
248			break;
249
250		case 'q':
251			qflag = 1;
252			break;
253
254		case 'w':
255			/* flag no longer needed; var=value implies write */
256			break;
257
258		default:
259			usage();
260		}
261	}
262	argc -= optind;
263	argv += optind;
264
265	if (argc == 0 || (Aflag || aflag)) {
266		debuginit();
267		vfsinit();
268		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
269			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
270		return (0);
271	}
272	for (; *argv != NULL; ++argv)
273		parse(*argv, 1);
274	return (0);
275}
276
277/*
278 * List all variables known to the system.
279 */
280void
281listall(char *prefix, struct list *lp)
282{
283	char *cp, name[BUFSIZ];
284	int lvl2, len;
285
286	if (lp->list == NULL)
287		return;
288	if ((len = strlcpy(name, prefix, sizeof(name))) >= sizeof(name))
289		errx(1, "%s: name too long", prefix);
290	cp = name + len++;
291	*cp++ = '.';
292	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
293		if (lp->list[lvl2].ctl_name == NULL)
294			continue;
295		if (strlcpy(cp, lp->list[lvl2].ctl_name,
296		    sizeof(name) - len) >= sizeof(name) - len)
297			warn("%s: name too long", lp->list[lvl2].ctl_name);
298		parse(name, Aflag);
299	}
300}
301
302/*
303 * Parse a name into a MIB entry.
304 * Lookup and print out the MIB entry if it exists.
305 * Set a new value if requested.
306 */
307void
308parse(char *string, int flags)
309{
310	int indx, type, state, intval, len;
311	size_t size, newsize = 0;
312	int lal = 0, special = 0;
313	void *newval = NULL;
314	int64_t quadval;
315	struct list *lp;
316	int mib[CTL_MAXNAME];
317	char *cp, *bufp, buf[SYSCTL_BUFSIZ];
318
319	(void)strlcpy(buf, string, sizeof(buf));
320	bufp = buf;
321	if ((cp = strchr(string, '=')) != NULL) {
322		*strchr(buf, '=') = '\0';
323		*cp++ = '\0';
324		while (isspace(*cp))
325			cp++;
326		newval = cp;
327		newsize = strlen(cp);
328	}
329	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
330		return;
331	mib[0] = indx;
332	if (indx == CTL_VFS)
333		vfsinit();
334	if (indx == CTL_DEBUG)
335		debuginit();
336	lp = &secondlevel[indx];
337	if (lp->list == 0) {
338		warnx("%s: class is not implemented", topname[indx].ctl_name);
339		return;
340	}
341	if (bufp == NULL) {
342		listall(topname[indx].ctl_name, lp);
343		return;
344	}
345	if ((indx = findname(string, "second", &bufp, lp)) == -1)
346		return;
347	mib[1] = indx;
348	type = lp->list[indx].ctl_type;
349	len = 2;
350	switch (mib[0]) {
351
352	case CTL_KERN:
353		switch (mib[1]) {
354		case KERN_PROF:
355			mib[2] = GPROF_STATE;
356			size = sizeof(state);
357			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
358				if (flags == 0)
359					return;
360				if (!nflag)
361					(void)printf("%s: ", string);
362				(void)puts("kernel is not compiled for profiling");
363				return;
364			}
365			if (!nflag)
366				(void)printf("%s = %s\n", string,
367				    state == GMON_PROF_OFF ? "off" : "running");
368			return;
369		case KERN_FORKSTAT:
370			sysctl_forkstat(string, &bufp, mib, flags, &type);
371			return;
372		case KERN_TTY:
373			len = sysctl_tty(string, &bufp, mib, flags, &type);
374			if (len < 0)
375				return;
376			break;
377		case KERN_NCHSTATS:
378			sysctl_nchstats(string, &bufp, mib, flags, &type);
379			return;
380		case KERN_MALLOCSTATS:
381			len = sysctl_malloc(string, &bufp, mib, flags, &type);
382			if (len < 0)
383				return;
384			if (mib[2] == KERN_MALLOC_BUCKET)
385				special |= KMEMBUCKETS;
386			if (mib[2] == KERN_MALLOC_KMEMSTATS)
387				special |= KMEMSTATS;
388			newsize = 0;
389			break;
390		case KERN_MBSTAT:
391			if (flags == 0)
392				return;
393			warnx("use netstat to view %s", string);
394			return;
395		case KERN_MSGBUF:
396			if (flags == 0)
397				return;
398			warnx("use dmesg to view %s", string);
399			return;
400		case KERN_VNODE:
401		case KERN_FILE:
402			if (flags == 0)
403				return;
404			warnx("use pstat to view %s information", string);
405			return;
406		case KERN_PROC:
407		case KERN_PROC2:
408			if (flags == 0)
409				return;
410			warnx("use ps to view %s information", string);
411			return;
412		case KERN_CLOCKRATE:
413			special |= CLOCK;
414			break;
415		case KERN_BOOTTIME:
416			special |= BOOTTIME;
417			break;
418		case KERN_RND:
419			special |= RNDSTATS;
420			break;
421		case KERN_HOSTID:
422		case KERN_ARND:
423			special |= UNSIGNED;
424			break;
425		case KERN_CPTIME:
426			special |= LONGARRAY;
427			lal = CPUSTATES;
428			break;
429		case KERN_SEMINFO:
430			len = sysctl_seminfo(string, &bufp, mib, flags, &type);
431			if (len < 0)
432				return;
433			break;
434		case KERN_SHMINFO:
435			len = sysctl_shminfo(string, &bufp, mib, flags, &type);
436			if (len < 0)
437				return;
438			break;
439		case KERN_WATCHDOG:
440			len = sysctl_watchdog(string, &bufp, mib, flags,
441			    &type);
442			if (len < 0)
443				return;
444			break;
445		case KERN_TIMECOUNTER:
446			len = sysctl_tc(string, &bufp, mib, flags,
447			    &type);
448			if (len < 0)
449				return;
450			break;
451		case KERN_EMUL:
452			sysctl_emul(string, newval, flags);
453			return;
454		case KERN_FILE2:
455			if (flags == 0)
456				return;
457			warnx("use fstat to view %s information", string);
458			return;
459		}
460		break;
461
462	case CTL_HW:
463		switch (mib[1]) {
464		case HW_DISKSTATS:
465			/*
466			 * Only complain if someone asks explicitly for this,
467			 * otherwise "fail" silently.
468			 */
469			if (flags)
470				warnx("use vmstat to view %s information",
471				    string);
472			return;
473		case HW_SENSORS:
474			special |= SENSORS;
475			len = sysctl_sensors(string, &bufp, mib, flags, &type);
476			if (len < 0)
477				return;
478			break;
479		case HW_PHYSMEM:
480		case HW_USERMEM:
481			/*
482			 * Don't print these; we'll print the 64-bit
483			 * variants instead.
484			 */
485			return;
486		}
487		break;
488
489	case CTL_VM:
490		if (mib[1] == VM_LOADAVG) {
491			double loads[3];
492
493			getloadavg(loads, 3);
494			if (!nflag)
495				(void)printf("%s%s", string, equ);
496			(void)printf("%.2f %.2f %.2f\n", loads[0],
497			    loads[1], loads[2]);
498			return;
499		} else if (mib[1] == VM_PSSTRINGS) {
500			struct _ps_strings _ps;
501
502			size = sizeof(_ps);
503			if (sysctl(mib, 2, &_ps, &size, NULL, 0) == -1) {
504				if (flags == 0)
505					return;
506				if (!nflag)
507					(void)printf("%s: ", string);
508				(void)puts("can't find ps strings");
509				return;
510			}
511			if (!nflag)
512				(void)printf("%s%s", string, equ);
513			(void)printf("%p\n", _ps.val);
514			return;
515		} else if (mib[1] == VM_SWAPENCRYPT) {
516			len = sysctl_swpenc(string, &bufp, mib, flags, &type);
517			if (len < 0)
518				return;
519
520			break;
521		} else if (mib[1] == VM_NKMEMPAGES ||
522		    mib[1] == VM_ANONMIN ||
523		    mib[1] == VM_VTEXTMIN ||
524		    mib[1] == VM_VNODEMIN) {
525			break;
526		}
527		if (flags == 0)
528			return;
529		warnx("use vmstat or systat to view %s information", string);
530		return;
531
532		break;
533
534	case CTL_NET:
535		if (mib[1] == PF_INET) {
536			len = sysctl_inet(string, &bufp, mib, flags, &type);
537			if (len < 0)
538				return;
539
540			if ((mib[2] == IPPROTO_IP && mib[3] == IPCTL_MRTSTATS) ||
541			    (mib[2] == IPPROTO_IP && mib[3] == IPCTL_STATS) ||
542			    (mib[2] == IPPROTO_TCP && mib[3] == TCPCTL_STATS) ||
543			    (mib[2] == IPPROTO_UDP && mib[3] == UDPCTL_STATS) ||
544			    (mib[2] == IPPROTO_ESP && mib[3] == ESPCTL_STATS) ||
545			    (mib[2] == IPPROTO_AH && mib[3] == AHCTL_STATS) ||
546			    (mib[2] == IPPROTO_IGMP && mib[3] == IGMPCTL_STATS) ||
547			    (mib[2] == IPPROTO_ETHERIP && mib[3] == ETHERIPCTL_STATS) ||
548			    (mib[2] == IPPROTO_IPIP && mib[3] == IPIPCTL_STATS) ||
549			    (mib[2] == IPPROTO_IPCOMP && mib[3] == IPCOMPCTL_STATS) ||
550			    (mib[2] == IPPROTO_ICMP && mib[3] == ICMPCTL_STATS) ||
551			    (mib[2] == IPPROTO_CARP && mib[3] == CARPCTL_STATS) ||
552			    (mib[2] == IPPROTO_PFSYNC && mib[3] == PFSYNCCTL_STATS)) {
553				if (flags == 0)
554					return;
555				warnx("use netstat to view %s information",
556				    string);
557				return;
558			} else if ((mib[2] == IPPROTO_TCP &&
559			    mib[3] == TCPCTL_BADDYNAMIC) ||
560			    (mib[2] == IPPROTO_UDP &&
561			    mib[3] == UDPCTL_BADDYNAMIC)) {
562
563				special |= BADDYNAMIC;
564
565				if (newval != NULL)
566					parse_baddynamic(mib, len, string,
567					    &newval, &newsize, flags, nflag);
568			}
569			break;
570		}
571#ifdef INET6
572		if (mib[1] == PF_INET6) {
573			len = sysctl_inet6(string, &bufp, mib, flags, &type);
574			if (len < 0)
575				return;
576
577			if ((mib[2] == IPPROTO_PIM && mib[3] == PIM6CTL_STATS)) {
578				if (flags == 0)
579					return;
580				warnx("use netstat to view %s information",
581				    string);
582				return;
583			}
584			break;
585		}
586#endif
587		if (mib[1] == PF_BPF) {
588			len = sysctl_bpf(string, &bufp, mib, flags, &type);
589			if (len < 0)
590				return;
591			break;
592		}
593		if (mib[1] == PF_MPLS) {
594			len = sysctl_mpls(string, &bufp, mib, flags, &type);
595			if (len < 0)
596				return;
597			break;
598		}
599		if (flags == 0)
600			return;
601		warnx("use netstat to view %s information", string);
602		return;
603
604	case CTL_DEBUG:
605		mib[2] = CTL_DEBUG_VALUE;
606		len = 3;
607		break;
608
609	case CTL_MACHDEP:
610#ifdef CPU_CONSDEV
611		if (mib[1] == CPU_CONSDEV)
612			special |= CHRDEV;
613#endif
614#ifdef CPU_BLK2CHR
615		if (mib[1] == CPU_BLK2CHR) {
616			if (bufp == NULL)
617				return;
618			mib[2] = makedev(atoi(bufp),0);
619			bufp = NULL;
620			len = 3;
621			special |= CHRDEV;
622			break;
623		}
624#endif
625#ifdef CPU_CHR2BLK
626		if (mib[1] == CPU_CHR2BLK) {
627			if (bufp == NULL)
628				return;
629			mib[2] = makedev(atoi(bufp),0);
630			bufp = NULL;
631			len = 3;
632			special |= BLKDEV;
633			break;
634		}
635#endif
636#ifdef CPU_BIOS
637		if (mib[1] == CPU_BIOS) {
638			len = sysctl_bios(string, &bufp, mib, flags, &type);
639			if (len < 0)
640				return;
641			if (mib[2] == BIOS_DEV)
642				special |= BIOSDEV;
643			if (mib[2] == BIOS_DISKINFO)
644				special |= BIOSGEO;
645			break;
646		}
647#endif
648#ifdef CPU_CHIPSET
649		if (mib[1] == CPU_CHIPSET) {
650			len = sysctl_chipset(string, &bufp, mib, flags, &type);
651			if (len < 0)
652				return;
653			break;
654		}
655#endif
656		break;
657
658	case CTL_FS:
659		len = sysctl_fs(string, &bufp, mib, flags, &type);
660		if (len >= 0)
661			break;
662		return;
663
664	case CTL_VFS:
665		if (mib[1])
666			len = sysctl_vfs(string, &bufp, mib, flags, &type);
667		else
668			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
669		if (len >= 0) {
670			if (type == CTLTYPE_STRUCT) {
671				if (flags)
672					warnx("use nfsstat to view %s information",
673					    MOUNT_NFS);
674				return;
675			} else
676				break;
677		}
678		return;
679
680	case CTL_USER:
681	case CTL_DDB:
682		break;
683
684	default:
685		warnx("illegal top level value: %d", mib[0]);
686		return;
687
688	}
689	if (bufp) {
690		warnx("name %s in %s is unknown", bufp, string);
691		return;
692	}
693	if (newsize > 0) {
694		switch (type) {
695		case CTLTYPE_INT:
696			errno = 0;
697			if (special & UNSIGNED)
698				intval = strtoul(newval, &cp, 10);
699			else
700				intval = strtol(newval, &cp, 10);
701			if (*cp != '\0') {
702				warnx("%s: illegal value: %s", string,
703				    (char *)newval);
704				return;
705			}
706			if (errno == ERANGE) {
707				warnx("%s: value %s out of range", string,
708				    (char *)newval);
709				return;
710			}
711			newval = &intval;
712			newsize = sizeof(intval);
713			break;
714
715		case CTLTYPE_QUAD:
716			/* XXX - assumes sizeof(long long) == sizeof(quad_t) */
717			(void)sscanf(newval, "%lld", (long long *)&quadval);
718			newval = &quadval;
719			newsize = sizeof(quadval);
720			break;
721		}
722	}
723	size = SYSCTL_BUFSIZ;
724	if (sysctl(mib, len, buf, &size, newval, newsize) == -1) {
725		if (flags == 0)
726			return;
727		switch (errno) {
728		case EOPNOTSUPP:
729			warnx("%s: value is not available", string);
730			return;
731		case ENOTDIR:
732			warnx("%s: specification is incomplete", string);
733			return;
734		case ENOMEM:
735			warnx("%s: type is unknown to this program", string);
736			return;
737		case ENXIO:
738			if (special & BIOSGEO)
739				return;
740		default:
741			warn("%s", string);
742			return;
743		}
744	}
745	if (special & KMEMBUCKETS) {
746		struct kmembuckets *kb = (struct kmembuckets *)buf;
747		if (!nflag)
748			(void)printf("%s%s", string, equ);
749		printf("(");
750		printf("calls = %llu ", (long long)kb->kb_calls);
751		printf("total_allocated = %llu ", (long long)kb->kb_total);
752		printf("total_free = %lld ", (long long)kb->kb_totalfree);
753		printf("elements = %lld ", (long long)kb->kb_elmpercl);
754		printf("high watermark = %lld ", (long long)kb->kb_highwat);
755		printf("could_free = %lld", (long long)kb->kb_couldfree);
756		printf(")\n");
757		return;
758	}
759	if (special & KMEMSTATS) {
760		struct kmemstats *km = (struct kmemstats *)buf;
761		int j, first = 1;
762
763		if (!nflag)
764			(void)printf("%s%s", string, equ);
765		(void)printf("(inuse = %ld, calls = %ld, memuse = %ldK, "
766		    "limblocks = %d, mapblocks = %d, maxused = %ldK, "
767		    "limit = %ldK, spare = %ld, sizes = (",
768		    km->ks_inuse, km->ks_calls,
769		    (km->ks_memuse + 1023) / 1024, km->ks_limblocks,
770		    km->ks_mapblocks, (km->ks_maxused + 1023) / 1024,
771		    (km->ks_limit + 1023) / 1024, km->ks_spare);
772		for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
773			if ((km->ks_size & j ) == 0)
774				continue;
775			if (first)
776				(void)printf("%d", j);
777			else
778				(void)printf(",%d", j);
779			first = 0;
780		}
781		if (first)
782			(void)printf("none");
783		(void)printf("))\n");
784		return;
785	}
786	if (special & CLOCK) {
787		struct clockinfo *clkp = (struct clockinfo *)buf;
788
789		if (!nflag)
790			(void)printf("%s%s", string, equ);
791		(void)printf(
792		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
793		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
794		return;
795	}
796	if (special & BOOTTIME) {
797		struct timeval *btp = (struct timeval *)buf;
798		time_t boottime;
799
800		if (!nflag) {
801			boottime = btp->tv_sec;
802			(void)printf("%s%s%s", string, equ, ctime(&boottime));
803		} else
804			(void)printf("%ld\n", btp->tv_sec);
805		return;
806	}
807	if (special & BLKDEV) {
808		dev_t dev = *(dev_t *)buf;
809
810		if (!nflag)
811			(void)printf("%s%s%s\n", string, equ,
812			    devname(dev, S_IFBLK));
813		else
814			(void)printf("0x%x\n", dev);
815		return;
816	}
817	if (special & CHRDEV) {
818		dev_t dev = *(dev_t *)buf;
819
820		if (!nflag)
821			(void)printf("%s%s%s\n", string, equ,
822			    devname(dev, S_IFCHR));
823		else
824			(void)printf("0x%x\n", dev);
825		return;
826	}
827#ifdef CPU_BIOS
828	if (special & BIOSGEO) {
829		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
830
831		if (!nflag)
832			(void)printf("%s%s", string, equ);
833		(void)printf("bootdev = 0x%x, "
834		    "cylinders = %u, heads = %u, sectors = %u\n",
835		    pdi->bsd_dev, pdi->bios_cylinders,
836		    pdi->bios_heads, pdi->bios_sectors);
837		return;
838	}
839	if (special & BIOSDEV) {
840		int dev = *(int*)buf;
841
842		if (!nflag)
843			(void)printf("%s%s", string, equ);
844		(void) printf("0x%02x\n", dev);
845		return;
846	}
847#endif
848	if (special & UNSIGNED) {
849		if (newsize == 0) {
850			if (!nflag)
851				(void)printf("%s%s", string, equ);
852			(void)printf("%u\n", *(u_int *)buf);
853		} else {
854			if (!qflag) {
855				if (!nflag)
856					(void)printf("%s: %u -> ", string,
857					    *(u_int *)buf);
858				(void)printf("%u\n", *(u_int *)newval);
859			}
860		}
861		return;
862	}
863	if (special & RNDSTATS) {
864		struct rndstats *rndstats = (struct rndstats *)buf;
865		int i;
866
867		if (!nflag)
868			(void)printf("%s%s", string, equ);
869		(void)printf(
870		"%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
871		    (unsigned long long)rndstats->rnd_total,
872		    (unsigned long long)rndstats->rnd_used,
873		    (unsigned long long)rndstats->rnd_reads,
874		    (unsigned long long)rndstats->arc4_reads,
875		    (unsigned long long)rndstats->arc4_nstirs,
876		    (unsigned long long)rndstats->arc4_stirs,
877		    (unsigned long long)rndstats->rnd_pad[0],
878		    (unsigned long long)rndstats->rnd_pad[1],
879		    (unsigned long long)rndstats->rnd_pad[2],
880		    (unsigned long long)rndstats->rnd_pad[3],
881		    (unsigned long long)rndstats->rnd_pad[4],
882		    (unsigned long long)rndstats->rnd_waits,
883		    (unsigned long long)rndstats->rnd_enqs,
884		    (unsigned long long)rndstats->rnd_deqs,
885		    (unsigned long long)rndstats->rnd_drops,
886		    (unsigned long long)rndstats->rnd_drople);
887		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]);
888		    i++)
889			(void)printf(" %llu", (unsigned long long)rndstats->rnd_ed[i]);
890		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]);
891		    i++)
892			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sc[i]);
893		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]);
894		    i++)
895			(void)printf(" %llu", (unsigned long long)rndstats->rnd_sb[i]);
896		printf("\n");
897		return;
898	}
899	if (special & BADDYNAMIC) {
900		u_int port, lastport;
901		u_int32_t *baddynamic = (u_int32_t *)buf;
902
903		if (!qflag) {
904			if (!nflag)
905				(void)printf("%s%s", string,
906				    newsize ? ": " : equ);
907			lastport = 0;
908			for (port = 0; port < 65536; port++)
909				if (DP_ISSET(baddynamic, port)) {
910					(void)printf("%s%u",
911					    lastport ? "," : "", port);
912					lastport = port;
913				}
914			if (newsize != 0) {
915				if (!nflag)
916					fputs(" -> ", stdout);
917				baddynamic = (u_int32_t *)newval;
918				lastport = 0;
919				for (port = 0; port < 65536; port++)
920					if (DP_ISSET(baddynamic, port)) {
921						(void)printf("%s%u",
922						    lastport ? "," : "", port);
923						lastport = port;
924					}
925			}
926			(void)putchar('\n');
927		}
928		return;
929	}
930	if (special & LONGARRAY) {
931		long *la = (long *)buf;
932		if (!nflag)
933			printf("%s%s", string, equ);
934		while (lal--)
935			printf("%ld%s", *la++, lal? ",":"");
936		putchar('\n');
937		return;
938	}
939	if (special & SENSORS) {
940		struct sensor *s = (struct sensor *)buf;
941
942		if (size > 0 && (s->flags & SENSOR_FINVALID) == 0) {
943			if (!nflag)
944				printf("%s%s", string, equ);
945			print_sensor(s);
946			printf("\n");
947		}
948		return;
949	}
950	switch (type) {
951	case CTLTYPE_INT:
952		if (newsize == 0) {
953			if (!nflag)
954				(void)printf("%s%s", string, equ);
955			(void)printf("%d\n", *(int *)buf);
956		} else {
957			if (!qflag) {
958				if (!nflag)
959					(void)printf("%s: %d -> ", string,
960					    *(int *)buf);
961				(void)printf("%d\n", *(int *)newval);
962			}
963		}
964		return;
965
966	case CTLTYPE_STRING:
967		if (newval == NULL) {
968			if (!nflag)
969				(void)printf("%s%s", string, equ);
970			(void)puts(buf);
971		} else {
972			if (!qflag) {
973				if (!nflag)
974					(void)printf("%s: %s -> ", string, buf);
975				(void)puts((char *)newval);
976			}
977		}
978		return;
979
980	case CTLTYPE_QUAD:
981		if (newsize == 0) {
982			long long tmp = *(quad_t *)buf;
983
984			if (!nflag)
985				(void)printf("%s%s", string, equ);
986			(void)printf("%lld\n", tmp);
987		} else {
988			long long tmp = *(quad_t *)buf;
989
990			if (!qflag) {
991				if (!nflag)
992					(void)printf("%s: %lld -> ",
993					    string, tmp);
994				tmp = *(quad_t *)newval;
995				(void)printf("%qd\n", tmp);
996			}
997		}
998		return;
999
1000	case CTLTYPE_STRUCT:
1001		warnx("%s: unknown structure returned", string);
1002		return;
1003
1004	default:
1005	case CTLTYPE_NODE:
1006		warnx("%s: unknown type returned", string);
1007		return;
1008	}
1009}
1010
1011void
1012parse_baddynamic(int mib[], size_t len, char *string, void **newvalp,
1013    size_t *newsizep, int flags, int nflag)
1014{
1015	static u_int32_t newbaddynamic[DP_MAPSIZE];
1016	in_port_t port;
1017	size_t size;
1018	char action, *cp;
1019	const char *errstr;
1020
1021	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
1022		size = sizeof(newbaddynamic);
1023		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
1024			if (flags == 0)
1025				return;
1026			if (!nflag)
1027				(void)printf("%s: ", string);
1028			(void)puts("kernel does contain bad dynamic port tables");
1029			return;
1030		}
1031
1032		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1033			if (*cp != '+' && *cp != '-')
1034				errx(1, "cannot mix +/- with full list");
1035			action = *cp++;
1036			port = strtonum(cp, 0, 65535, &errstr);
1037			if (errstr != NULL)
1038				errx(1, "port is %s: %s", errstr, cp);
1039			if (action == '+')
1040				DP_SET(newbaddynamic, port);
1041			else
1042				DP_CLR(newbaddynamic, port);
1043		}
1044	} else {
1045		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
1046		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
1047			port = strtonum(cp, 0, 65535, &errstr);
1048			if (errstr != NULL)
1049				errx(1, "port is %s: %s", errstr, cp);
1050			DP_SET(newbaddynamic, port);
1051		}
1052	}
1053
1054	*newvalp = (void *)newbaddynamic;
1055	*newsizep = sizeof(newbaddynamic);
1056}
1057
1058/*
1059 * Initialize the set of debugging names
1060 */
1061void
1062debuginit(void)
1063{
1064	int mib[3], loc, i;
1065	size_t size;
1066
1067	if (secondlevel[CTL_DEBUG].list != 0)
1068		return;
1069	secondlevel[CTL_DEBUG].list = debugname;
1070	mib[0] = CTL_DEBUG;
1071	mib[2] = CTL_DEBUG_NAME;
1072	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
1073		mib[1] = i;
1074		size = BUFSIZ - loc;
1075		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
1076			continue;
1077		debugname[i].ctl_name = &names[loc];
1078		debugname[i].ctl_type = CTLTYPE_INT;
1079		loc += size;
1080	}
1081	lastused = loc;
1082}
1083
1084struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
1085struct ctlname ffsname[] = FFS_NAMES;
1086struct ctlname nfsname[] = FS_NFS_NAMES;
1087struct list *vfsvars;
1088int *vfs_typenums;
1089
1090/*
1091 * Initialize the set of filesystem names
1092 */
1093void
1094vfsinit(void)
1095{
1096	int mib[4], maxtypenum, cnt, loc, size;
1097	struct vfsconf vfc;
1098	size_t buflen;
1099
1100	if (secondlevel[CTL_VFS].list != 0)
1101		return;
1102	mib[0] = CTL_VFS;
1103	mib[1] = VFS_GENERIC;
1104	mib[2] = VFS_MAXTYPENUM;
1105	buflen = 4;
1106	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
1107		return;
1108	maxtypenum++;	/* + generic */
1109	if ((vfs_typenums = calloc(maxtypenum, sizeof(int))) == NULL)
1110		return;
1111	if ((vfsvars = calloc(maxtypenum, sizeof(*vfsvars))) == NULL) {
1112		free(vfs_typenums);
1113		return;
1114	}
1115	if ((vfsname = calloc(maxtypenum, sizeof(*vfsname))) == NULL) {
1116		free(vfs_typenums);
1117		free(vfsvars);
1118		return;
1119	}
1120	mib[2] = VFS_CONF;
1121	buflen = sizeof vfc;
1122	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
1123		mib[3] = cnt - 1;
1124		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
1125			if (errno == EOPNOTSUPP)
1126				continue;
1127			warn("vfsinit");
1128			free(vfsname);
1129			free(vfsvars);
1130			free(vfs_typenums);
1131			return;
1132		}
1133		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
1134			vfsvars[cnt].list = ffsname;
1135			vfsvars[cnt].size = FFS_MAXID;
1136		}
1137		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
1138			vfsvars[cnt].list = nfsname;
1139			vfsvars[cnt].size = NFS_MAXID;
1140		}
1141		vfs_typenums[cnt] = vfc.vfc_typenum;
1142		strlcat(&names[loc], vfc.vfc_name, sizeof names - loc);
1143		vfsname[cnt].ctl_name = &names[loc];
1144		vfsname[cnt].ctl_type = CTLTYPE_NODE;
1145		size = strlen(vfc.vfc_name) + 1;
1146		loc += size;
1147	}
1148	lastused = loc;
1149
1150	vfsname[0].ctl_name = "mounts";
1151	vfsname[0].ctl_type = CTLTYPE_NODE;
1152	vfsvars[0].list = vfsname + 1;
1153	vfsvars[0].size = maxtypenum - 1;
1154
1155	secondlevel[CTL_VFS].list = vfsname;
1156	secondlevel[CTL_VFS].size = maxtypenum;
1157	return;
1158}
1159
1160int
1161sysctl_vfsgen(char *string, char **bufpp, int mib[], int flags, int *typep)
1162{
1163	int indx;
1164	size_t size;
1165	struct vfsconf vfc;
1166
1167	if (*bufpp == NULL) {
1168		listall(string, vfsvars);
1169		return (-1);
1170	}
1171
1172	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
1173		return (-1);
1174
1175	mib[1] = VFS_GENERIC;
1176	mib[2] = VFS_CONF;
1177	mib[3] = indx;
1178	size = sizeof vfc;
1179	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
1180		if (errno != EOPNOTSUPP)
1181			warn("vfs print");
1182		return -1;
1183	}
1184	if (flags == 0 && vfc.vfc_refcount == 0)
1185		return -1;
1186	if (!nflag)
1187		fprintf(stdout, "%s has %d mounted instance%s\n",
1188		    string, vfc.vfc_refcount,
1189		    vfc.vfc_refcount != 1 ? "s" : "");
1190	else
1191		fprintf(stdout, "%d\n", vfc.vfc_refcount);
1192
1193	return -1;
1194}
1195
1196int
1197sysctl_vfs(char *string, char **bufpp, int mib[], int flags, int *typep)
1198{
1199	struct list *lp = &vfsvars[mib[1]];
1200	int indx;
1201
1202	if (lp->list == NULL) {
1203		if (flags)
1204			warnx("No variables defined for file system %s", string);
1205		return (-1);
1206	}
1207	if (*bufpp == NULL) {
1208		listall(string, lp);
1209		return (-1);
1210	}
1211	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1212		return (-1);
1213
1214	mib[1] = vfs_typenums[mib[1]];
1215	mib[2] = indx;
1216	*typep = lp->list[indx].ctl_type;
1217	return (3);
1218}
1219
1220struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
1221struct list fslist = { posixname, FS_POSIX_MAXID };
1222
1223/*
1224 * handle file system requests
1225 */
1226int
1227sysctl_fs(char *string, char **bufpp, int mib[], int flags, int *typep)
1228{
1229	int indx;
1230
1231	if (*bufpp == NULL) {
1232		listall(string, &fslist);
1233		return (-1);
1234	}
1235	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1236		return (-1);
1237	mib[2] = indx;
1238	*typep = fslist.list[indx].ctl_type;
1239	return (3);
1240}
1241
1242#ifdef CPU_BIOS
1243struct ctlname biosname[] = CTL_BIOS_NAMES;
1244struct list bioslist = { biosname, BIOS_MAXID };
1245
1246/*
1247 * handle BIOS requests
1248 */
1249int
1250sysctl_bios(char *string, char **bufpp, int mib[], int flags, int *typep)
1251{
1252	char *name;
1253	int indx;
1254
1255	if (*bufpp == NULL) {
1256		listall(string, &bioslist);
1257		return (-1);
1258	}
1259	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1260		return (-1);
1261	mib[2] = indx;
1262	if (indx == BIOS_DISKINFO) {
1263		if (*bufpp == NULL) {
1264			char name[BUFSIZ];
1265
1266			/* scan all the bios devices */
1267			for (indx = 0; indx < 256; indx++) {
1268				snprintf(name, sizeof(name), "%s.%u",
1269				    string, indx);
1270				parse(name, 1);
1271			}
1272			return (-1);
1273		}
1274		if ((name = strsep(bufpp, ".")) == NULL) {
1275			warnx("%s: incomplete specification", string);
1276			return (-1);
1277		}
1278		mib[3] = atoi(name);
1279		*typep = CTLTYPE_STRUCT;
1280		return (4);
1281	} else {
1282		*typep = bioslist.list[indx].ctl_type;
1283		return (3);
1284	}
1285}
1286#endif
1287
1288struct ctlname swpencname[] = CTL_SWPENC_NAMES;
1289struct list swpenclist = { swpencname, SWPENC_MAXID };
1290
1291/*
1292 * handle swap encrypt requests
1293 */
1294int
1295sysctl_swpenc(char *string, char **bufpp, int mib[], int flags, int *typep)
1296{
1297	int indx;
1298
1299	if (*bufpp == NULL) {
1300		listall(string, &swpenclist);
1301		return (-1);
1302	}
1303	if ((indx = findname(string, "third", bufpp, &swpenclist)) == -1)
1304		return (-1);
1305	mib[2] = indx;
1306	*typep = swpenclist.list[indx].ctl_type;
1307	return (3);
1308}
1309
1310struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1311struct ctlname ipname[] = IPCTL_NAMES;
1312struct ctlname icmpname[] = ICMPCTL_NAMES;
1313struct ctlname igmpname[] = IGMPCTL_NAMES;
1314struct ctlname ipipname[] = IPIPCTL_NAMES;
1315struct ctlname tcpname[] = TCPCTL_NAMES;
1316struct ctlname udpname[] = UDPCTL_NAMES;
1317struct ctlname espname[] = ESPCTL_NAMES;
1318struct ctlname ahname[] = AHCTL_NAMES;
1319struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1320struct ctlname grename[] = GRECTL_NAMES;
1321struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1322struct ctlname ipcompname[] = IPCOMPCTL_NAMES;
1323struct ctlname carpname[] = CARPCTL_NAMES;
1324struct ctlname pfsyncname[] = PFSYNCCTL_NAMES;
1325struct ctlname bpfname[] = CTL_NET_BPF_NAMES;
1326struct ctlname ifqname[] = CTL_IFQ_NAMES;
1327struct list inetlist = { inetname, IPPROTO_MAXID };
1328struct list inetvars[] = {
1329	{ ipname, IPCTL_MAXID },	/* ip */
1330	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1331	{ igmpname, IGMPCTL_MAXID },	/* igmp */
1332	{ 0, 0 },			/* ggmp */
1333	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1334	{ 0, 0 },
1335	{ tcpname, TCPCTL_MAXID },	/* tcp */
1336	{ 0, 0 },
1337	{ 0, 0 },			/* egp */
1338	{ 0, 0 },
1339	{ 0, 0 },
1340	{ 0, 0 },
1341	{ 0, 0 },			/* pup */
1342	{ 0, 0 },
1343	{ 0, 0 },
1344	{ 0, 0 },
1345	{ 0, 0 },
1346	{ udpname, UDPCTL_MAXID },	/* udp */
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	{ 0, 0 },
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	{ grename, GRECTL_MAXID },	/* gre */
1377	{ 0, 0 },
1378	{ 0, 0 },
1379	{ espname, ESPCTL_MAXID },	/* esp */
1380	{ ahname, AHCTL_MAXID },	/* ah */
1381	{ 0, 0 },
1382	{ 0, 0 },
1383	{ 0, 0 },
1384	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1385	{ 0, 0 },
1386	{ 0, 0 },
1387	{ 0, 0 },
1388	{ 0, 0 },
1389	{ 0, 0 },
1390	{ 0, 0 },
1391	{ 0, 0 },
1392	{ 0, 0 },
1393	{ 0, 0 },
1394	{ 0, 0 },
1395	{ 0, 0 },
1396	{ 0, 0 },
1397	{ 0, 0 },
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	{ etheripname, ETHERIPCTL_MAXID },
1427	{ 0, 0 },
1428	{ 0, 0 },
1429	{ 0, 0 },
1430	{ 0, 0 },
1431	{ 0, 0 },
1432	{ 0, 0 },
1433	{ 0, 0 },
1434	{ 0, 0 },
1435	{ 0, 0 },
1436	{ 0, 0 },
1437	{ ipcompname, IPCOMPCTL_MAXID },
1438	{ 0, 0 },
1439	{ 0, 0 },
1440	{ 0, 0 },
1441	{ carpname, CARPCTL_MAXID },
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	{ 0, 0 },
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	{ 0, 0 },
1489	{ 0, 0 },
1490	{ 0, 0 },
1491	{ 0, 0 },
1492	{ 0, 0 },
1493	{ 0, 0 },
1494	{ 0, 0 },
1495	{ 0, 0 },
1496	{ 0, 0 },
1497	{ 0, 0 },
1498	{ 0, 0 },
1499	{ 0, 0 },
1500	{ 0, 0 },
1501	{ 0, 0 },
1502	{ 0, 0 },
1503	{ 0, 0 },
1504	{ 0, 0 },
1505	{ 0, 0 },
1506	{ 0, 0 },
1507	{ 0, 0 },
1508	{ 0, 0 },
1509	{ 0, 0 },
1510	{ 0, 0 },
1511	{ 0, 0 },
1512	{ 0, 0 },
1513	{ 0, 0 },
1514	{ 0, 0 },
1515	{ 0, 0 },
1516	{ 0, 0 },
1517	{ 0, 0 },
1518	{ 0, 0 },
1519	{ 0, 0 },
1520	{ 0, 0 },
1521	{ 0, 0 },
1522	{ 0, 0 },
1523	{ 0, 0 },
1524	{ 0, 0 },
1525	{ 0, 0 },
1526	{ 0, 0 },
1527	{ 0, 0 },
1528	{ 0, 0 },
1529	{ 0, 0 },
1530	{ 0, 0 },
1531	{ 0, 0 },
1532	{ 0, 0 },
1533	{ 0, 0 },
1534	{ 0, 0 },
1535	{ 0, 0 },
1536	{ 0, 0 },
1537	{ 0, 0 },
1538	{ 0, 0 },
1539	{ 0, 0 },
1540	{ 0, 0 },
1541	{ 0, 0 },
1542	{ 0, 0 },
1543	{ 0, 0 },
1544	{ 0, 0 },
1545	{ 0, 0 },
1546	{ 0, 0 },
1547	{ 0, 0 },
1548	{ 0, 0 },
1549	{ 0, 0 },
1550	{ 0, 0 },
1551	{ 0, 0 },
1552	{ 0, 0 },
1553	{ 0, 0 },
1554	{ 0, 0 },
1555	{ 0, 0 },
1556	{ 0, 0 },
1557	{ 0, 0 },
1558	{ 0, 0 },
1559	{ 0, 0 },
1560	{ 0, 0 },
1561	{ 0, 0 },
1562	{ 0, 0 },
1563	{ 0, 0 },
1564	{ 0, 0 },
1565	{ 0, 0 },
1566	{ 0, 0 },
1567	{ 0, 0 },
1568	{ 0, 0 },
1569	{ 0, 0 },
1570	{ 0, 0 },
1571	{ 0, 0 },
1572	{ 0, 0 },
1573	{ 0, 0 },
1574	{ 0, 0 },
1575	{ 0, 0 },
1576	{ 0, 0 },
1577	{ 0, 0 },
1578	{ pfsyncname, PFSYNCCTL_MAXID },
1579};
1580struct list bpflist = { bpfname, NET_BPF_MAXID };
1581struct list ifqlist = { ifqname, IFQCTL_MAXID };
1582
1583struct list kernmalloclist = { kernmallocname, KERN_MALLOC_MAXID };
1584struct list forkstatlist = { forkstatname, KERN_FORKSTAT_MAXID };
1585struct list nchstatslist = { nchstatsname, KERN_NCHSTATS_MAXID };
1586struct list ttylist = { ttysname, KERN_TTY_MAXID };
1587struct list semlist = { semname, KERN_SEMINFO_MAXID };
1588struct list shmlist = { shmname, KERN_SHMINFO_MAXID };
1589struct list watchdoglist = { watchdogname, KERN_WATCHDOG_MAXID };
1590struct list tclist = { tcname, KERN_TIMECOUNTER_MAXID };
1591
1592/*
1593 * handle vfs namei cache statistics
1594 */
1595int
1596sysctl_nchstats(char *string, char **bufpp, int mib[], int flags, int *typep)
1597{
1598	static struct nchstats nch;
1599	int indx;
1600	size_t size;
1601	static int keepvalue = 0;
1602
1603	if (*bufpp == NULL) {
1604		bzero(&nch, sizeof(struct nchstats));
1605		listall(string, &nchstatslist);
1606		return (-1);
1607	}
1608	if ((indx = findname(string, "third", bufpp, &nchstatslist)) == -1)
1609		return (-1);
1610	mib[2] = indx;
1611	if (*bufpp != NULL) {
1612		warnx("fourth level name in %s is invalid", string);
1613		return (-1);
1614	}
1615	if (keepvalue == 0) {
1616		size = sizeof(struct nchstats);
1617		if (sysctl(mib, 2, &nch, &size, NULL, 0) < 0)
1618			return (-1);
1619		keepvalue = 1;
1620	}
1621	if (!nflag)
1622		(void)printf("%s%s", string, equ);
1623	switch (indx) {
1624	case KERN_NCHSTATS_GOODHITS:
1625		(void)printf("%llu\n", nch.ncs_goodhits);
1626		break;
1627	case KERN_NCHSTATS_NEGHITS:
1628		(void)printf("%llu\n", nch.ncs_neghits);
1629		break;
1630	case KERN_NCHSTATS_BADHITS:
1631		(void)printf("%llu\n", nch.ncs_badhits);
1632		break;
1633	case KERN_NCHSTATS_FALSEHITS:
1634		(void)printf("%llu\n", nch.ncs_falsehits);
1635		break;
1636	case KERN_NCHSTATS_MISS:
1637		(void)printf("%llu\n", nch.ncs_miss);
1638		break;
1639	case KERN_NCHSTATS_LONG:
1640		(void)printf("%llu\n", nch.ncs_long);
1641		break;
1642	case KERN_NCHSTATS_PASS2:
1643		(void)printf("%llu\n", nch.ncs_pass2);
1644		break;
1645	case KERN_NCHSTATS_2PASSES:
1646		(void)printf("%llu\n", nch.ncs_2passes);
1647		break;
1648	case KERN_NCHSTATS_REVHITS:
1649		(void)printf("%llu\n", nch.ncs_revhits);
1650		break;
1651	case KERN_NCHSTATS_REVMISS:
1652		(void)printf("%llu\n", nch.ncs_revmiss);
1653		break;
1654	case KERN_NCHSTATS_DOTHITS:
1655		(void)printf("%llu\n", nch.ncs_dothits);
1656		break;
1657	case KERN_NCHSTATS_DOTDOTHITS:
1658		(void)printf("%llu\n", nch.ncs_dotdothits);
1659		break;
1660	}
1661	return (-1);
1662}
1663
1664/*
1665 * handle tty statistics
1666 */
1667int
1668sysctl_tty(char *string, char **bufpp, int mib[], int flags, int *typep)
1669{
1670	int indx;
1671
1672	if (*bufpp == NULL) {
1673		listall(string, &ttylist);
1674		return (-1);
1675	}
1676	if ((indx = findname(string, "third", bufpp, &ttylist)) == -1)
1677		return (-1);
1678	mib[2] = indx;
1679
1680	if ((*typep = ttylist.list[indx].ctl_type) == CTLTYPE_STRUCT) {
1681		if (flags)
1682			warnx("use pstat -t to view %s information",
1683			    string);
1684		return (-1);
1685	}
1686	return (3);
1687}
1688
1689/*
1690 * handle fork statistics
1691 */
1692int
1693sysctl_forkstat(char *string, char **bufpp, int mib[], int flags, int *typep)
1694{
1695	static struct forkstat fks;
1696	static int keepvalue = 0;
1697	int indx;
1698	size_t size;
1699
1700	if (*bufpp == NULL) {
1701		bzero(&fks, sizeof(struct forkstat));
1702		listall(string, &forkstatlist);
1703		return (-1);
1704	}
1705	if ((indx = findname(string, "third", bufpp, &forkstatlist)) == -1)
1706		return (-1);
1707	if (*bufpp != NULL) {
1708		warnx("fourth level name in %s is invalid", string);
1709		return (-1);
1710	}
1711	if (keepvalue == 0) {
1712		size = sizeof(struct forkstat);
1713		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0)
1714			return (-1);
1715		keepvalue = 1;
1716	}
1717	if (!nflag)
1718		(void)printf("%s%s", string, equ);
1719	switch (indx)	{
1720	case KERN_FORKSTAT_FORK:
1721		(void)printf("%d\n", fks.cntfork);
1722		break;
1723	case KERN_FORKSTAT_VFORK:
1724		(void)printf("%d\n", fks.cntvfork);
1725		break;
1726	case KERN_FORKSTAT_RFORK:
1727		(void)printf("%d\n", fks.cntrfork);
1728		break;
1729	case KERN_FORKSTAT_KTHREAD:
1730		(void)printf("%d\n", fks.cntkthread);
1731		break;
1732	case KERN_FORKSTAT_SIZFORK:
1733		(void)printf("%d\n", fks.sizfork);
1734		break;
1735	case KERN_FORKSTAT_SIZVFORK:
1736		(void)printf("%d\n", fks.sizvfork);
1737		break;
1738	case KERN_FORKSTAT_SIZRFORK:
1739		(void)printf("%d\n", fks.sizrfork);
1740		break;
1741	case KERN_FORKSTAT_SIZKTHREAD:
1742		(void)printf("%d\n", fks.sizkthread);
1743		break;
1744	}
1745	return (-1);
1746}
1747
1748/*
1749 * handle malloc statistics
1750 */
1751int
1752sysctl_malloc(char *string, char **bufpp, int mib[], int flags, int *typep)
1753{
1754	int indx, stor, i;
1755	char *name, bufp[SYSCTL_BUFSIZ], *buf, *ptr;
1756	struct list lp;
1757	size_t size;
1758
1759	if (*bufpp == NULL) {
1760		listall(string, &kernmalloclist);
1761		return (-1);
1762	}
1763	if ((indx = findname(string, "third", bufpp, &kernmalloclist)) == -1)
1764		return (-1);
1765	mib[2] = indx;
1766	if (mib[2] == KERN_MALLOC_BUCKET) {
1767		if ((name = strsep(bufpp, ".")) == NULL) {
1768			size = SYSCTL_BUFSIZ;
1769			stor = mib[2];
1770			mib[2] = KERN_MALLOC_BUCKETS;
1771			buf = bufp;
1772			if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1773				return (-1);
1774			mib[2] = stor;
1775			for (stor = 0, i = 0; i < size; i++)
1776				if (buf[i] == ',')
1777					stor++;
1778			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1779			if (lp.list == NULL)
1780				return (-1);
1781			lp.size = stor + 2;
1782			for (i = 1;
1783			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL;
1784			    i++) {
1785				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1786			}
1787			lp.list[i].ctl_name = buf;
1788			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1789			listall(string, &lp);
1790			free(lp.list);
1791			return (-1);
1792		}
1793		mib[3] = atoi(name);
1794		return (4);
1795	} else if (mib[2] == KERN_MALLOC_BUCKETS) {
1796		*typep = CTLTYPE_STRING;
1797		return (3);
1798	} else if (mib[2] == KERN_MALLOC_KMEMSTATS) {
1799		size = SYSCTL_BUFSIZ;
1800		stor = mib[2];
1801		mib[2] = KERN_MALLOC_KMEMNAMES;
1802		buf = bufp;
1803		if (sysctl(mib, 3, buf, &size, NULL, 0) < 0)
1804			return (-1);
1805		mib[2] = stor;
1806		if ((name = strsep(bufpp, ".")) == NULL) {
1807			for (stor = 0, i = 0; i < size; i++)
1808				if (buf[i] == ',')
1809					stor++;
1810			lp.list = calloc(stor + 2, sizeof(struct ctlname));
1811			if (lp.list == NULL)
1812				return (-1);
1813			lp.size = stor + 2;
1814			for (i = 1;
1815			    (lp.list[i].ctl_name = strsep(&buf, ",")) != NULL;
1816			    i++) {
1817				if (lp.list[i].ctl_name[0] == '\0') {
1818					i--;
1819					continue;
1820				}
1821				lp.list[i].ctl_type = CTLTYPE_STRUCT;
1822			}
1823			lp.list[i].ctl_name = buf;
1824			lp.list[i].ctl_type = CTLTYPE_STRUCT;
1825			listall(string, &lp);
1826			free(lp.list);
1827			return (-1);
1828		}
1829		ptr = strstr(buf, name);
1830 tryagain:
1831		if (ptr == NULL) {
1832			warnx("fourth level name %s in %s is invalid", name,
1833			    string);
1834			return (-1);
1835		}
1836		if ((*(ptr + strlen(name)) != ',') &&
1837		    (*(ptr + strlen(name)) != '\0')) {
1838			ptr = strstr(ptr + 1, name); /* retry */
1839			goto tryagain;
1840		}
1841		if ((ptr != buf) && (*(ptr - 1) != ',')) {
1842			ptr = strstr(ptr + 1, name); /* retry */
1843			goto tryagain;
1844		}
1845		for (i = 0, stor = 0; buf + i < ptr; i++)
1846			if (buf[i] == ',')
1847				stor++;
1848		mib[3] = stor;
1849		return (4);
1850	} else if (mib[2] == KERN_MALLOC_KMEMNAMES) {
1851		*typep = CTLTYPE_STRING;
1852		return (3);
1853	}
1854	return (-1);
1855}
1856
1857#ifdef CPU_CHIPSET
1858/*
1859 * handle machdep.chipset requests
1860 */
1861struct ctlname chipsetname[] = CTL_CHIPSET_NAMES;
1862struct list chipsetlist = { chipsetname, CPU_CHIPSET_MAXID };
1863
1864int
1865sysctl_chipset(char *string, char **bufpp, int mib[], int flags, int *typep)
1866{
1867	int indx, bwx;
1868	static void *q;
1869	size_t len;
1870	char *p;
1871
1872	if (*bufpp == NULL) {
1873		listall(string, &chipsetlist);
1874		return (-1);
1875	}
1876	if ((indx = findname(string, "third", bufpp, &chipsetlist)) == -1)
1877		return (-1);
1878	mib[2] = indx;
1879	if (!nflag)
1880		printf("%s%s", string, equ);
1881	switch(mib[2]) {
1882	case CPU_CHIPSET_MEM:
1883	case CPU_CHIPSET_DENSE:
1884	case CPU_CHIPSET_PORTS:
1885	case CPU_CHIPSET_HAE_MASK:
1886		len = sizeof(void *);
1887		if (sysctl(mib, 3, &q, &len, NULL, 0) < 0)
1888			goto done;
1889		printf("%p", q);
1890		break;
1891	case CPU_CHIPSET_BWX:
1892		len = sizeof(int);
1893		if (sysctl(mib, 3, &bwx, &len, NULL, 0) < 0)
1894			goto done;
1895		printf("%d", bwx);
1896		break;
1897	case CPU_CHIPSET_TYPE:
1898		if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0)
1899			goto done;
1900		p = malloc(len + 1);
1901		if (p == NULL)
1902			goto done;
1903		if (sysctl(mib, 3, p, &len, NULL, 0) < 0) {
1904			free(p);
1905			goto done;
1906		}
1907		p[len] = '\0';
1908		printf("%s", p);
1909		free(p);
1910		break;
1911	}
1912done:
1913	printf("\n");
1914	return (-1);
1915}
1916#endif
1917/*
1918 * handle internet requests
1919 */
1920int
1921sysctl_inet(char *string, char **bufpp, int mib[], int flags, int *typep)
1922{
1923	struct list *lp;
1924	int indx;
1925
1926	if (*bufpp == NULL) {
1927		listall(string, &inetlist);
1928		return (-1);
1929	}
1930	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1931		return (-1);
1932	mib[2] = indx;
1933	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1934		lp = &inetvars[indx];
1935	else if (!flags)
1936		return (-1);
1937	else {
1938		warnx("%s: no variables defined for this protocol", string);
1939		return (-1);
1940	}
1941	if (*bufpp == NULL) {
1942		listall(string, lp);
1943		return (-1);
1944	}
1945	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1946		return (-1);
1947	mib[3] = indx;
1948	*typep = lp->list[indx].ctl_type;
1949	if (*typep == CTLTYPE_NODE) {
1950		int tindx;
1951
1952		if (*bufpp == NULL) {
1953			listall(string, &ifqlist);
1954			return(-1);
1955		}
1956		lp = &ifqlist;
1957		if ((tindx = findname(string, "fifth", bufpp, lp)) == -1)
1958			return (-1);
1959		mib[4] = tindx;
1960		*typep = lp->list[tindx].ctl_type;
1961		return(5);
1962	}
1963	return (4);
1964}
1965
1966#ifdef INET6
1967struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1968struct ctlname ip6name[] = IPV6CTL_NAMES;
1969struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1970struct ctlname pim6name[] = PIM6CTL_NAMES;
1971struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1972struct list inet6vars[] = {
1973/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1974	{ 0, 0 },
1975	{ 0, 0 },
1976	{ 0, 0 },
1977	{ 0, 0 },
1978	{ 0, 0 },
1979/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1980	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1981/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1982	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1983/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1984	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1985/*40*/	{ 0, 0 },
1986	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1987	{ 0, 0 },
1988	{ 0, 0 },
1989	{ 0, 0 },
1990	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1991/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1992	{ 0, 0 },
1993	{ 0, 0 },
1994	{ 0, 0 },
1995	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1996	{ 0, 0 },
1997/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1998	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1999/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2000	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2001/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2002	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2003/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2004	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2005/*100*/	{ 0, 0 },
2006	{ 0, 0 },
2007	{ 0, 0 },
2008	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
2009};
2010
2011/*
2012 * handle internet6 requests
2013 */
2014int
2015sysctl_inet6(char *string, char **bufpp, int mib[], int flags, int *typep)
2016{
2017	struct list *lp;
2018	int indx;
2019
2020	if (*bufpp == NULL) {
2021		listall(string, &inet6list);
2022		return (-1);
2023	}
2024	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
2025		return (-1);
2026	mib[2] = indx;
2027	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
2028		lp = &inet6vars[indx];
2029	else if (!flags)
2030		return (-1);
2031	else {
2032		warnx("%s: no variables defined for this protocol", string);
2033		return (-1);
2034	}
2035	if (*bufpp == NULL) {
2036		listall(string, lp);
2037		return (-1);
2038	}
2039	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
2040		return (-1);
2041	mib[3] = indx;
2042	*typep = lp->list[indx].ctl_type;
2043	return (4);
2044}
2045#endif
2046
2047/* handle bpf requests */
2048int
2049sysctl_bpf(char *string, char **bufpp, int mib[], int flags, int *typep)
2050{
2051	int indx;
2052
2053	if (*bufpp == NULL) {
2054		listall(string, &bpflist);
2055		return (-1);
2056	}
2057	if ((indx = findname(string, "third", bufpp, &bpflist)) == -1)
2058		return (-1);
2059	mib[2] = indx;
2060	*typep = CTLTYPE_INT;
2061	return (3);
2062}
2063
2064struct ctlname mplsname[] = MPLSCTL_NAMES;
2065struct list mplslist = { mplsname, MPLSCTL_MAXID };
2066
2067/* handle MPLS requests */
2068int
2069sysctl_mpls(char *string, char **bufpp, int mib[], int flags, int *typep)
2070{
2071	struct list *lp;
2072	int indx;
2073
2074	if (*bufpp == NULL) {
2075		listall(string, &mplslist);
2076		return (-1);
2077	}
2078	if ((indx = findname(string, "third", bufpp, &mplslist)) == -1)
2079		return (-1);
2080	mib[2] = indx;
2081	*typep = mplslist.list[indx].ctl_type;
2082	if (*typep == CTLTYPE_NODE) {
2083		int tindx;
2084
2085		if (*bufpp == NULL) {
2086			listall(string, &ifqlist);
2087			return(-1);
2088		}
2089		lp = &ifqlist;
2090		if ((tindx = findname(string, "fourth", bufpp, lp)) == -1)
2091			return (-1);
2092		mib[3] = tindx;
2093		*typep = lp->list[tindx].ctl_type;
2094		return(4);
2095	}
2096	return (3);
2097}
2098
2099/*
2100 * Handle SysV semaphore info requests
2101 */
2102int
2103sysctl_seminfo(string, bufpp, mib, flags, typep)
2104	char *string;
2105	char **bufpp;
2106	int mib[];
2107	int flags;
2108	int *typep;
2109{
2110	int indx;
2111
2112	if (*bufpp == NULL) {
2113		listall(string, &semlist);
2114		return (-1);
2115	}
2116	if ((indx = findname(string, "third", bufpp, &semlist)) == -1)
2117		return (-1);
2118	mib[2] = indx;
2119	*typep = CTLTYPE_INT;
2120	return (3);
2121}
2122
2123/*
2124 * Handle SysV shared memory info requests
2125 */
2126int
2127sysctl_shminfo(string, bufpp, mib, flags, typep)
2128	char *string;
2129	char **bufpp;
2130	int mib[];
2131	int flags;
2132	int *typep;
2133{
2134	int indx;
2135
2136	if (*bufpp == NULL) {
2137		listall(string, &shmlist);
2138		return (-1);
2139	}
2140	if ((indx = findname(string, "third", bufpp, &shmlist)) == -1)
2141		return (-1);
2142	mib[2] = indx;
2143	*typep = CTLTYPE_INT;
2144	return (3);
2145}
2146
2147/*
2148 * Handle watchdog support
2149 */
2150int
2151sysctl_watchdog(char *string, char **bufpp, int mib[], int flags,
2152    int *typep)
2153{
2154	int indx;
2155
2156	if (*bufpp == NULL) {
2157		listall(string, &watchdoglist);
2158		return (-1);
2159	}
2160	if ((indx = findname(string, "third", bufpp, &watchdoglist)) == -1)
2161		return (-1);
2162	mib[2] = indx;
2163	*typep = watchdoglist.list[indx].ctl_type;
2164	return (3);
2165}
2166
2167/*
2168 * Handle timecounter support
2169 */
2170int
2171sysctl_tc(char *string, char **bufpp, int mib[], int flags,
2172    int *typep)
2173{
2174	int indx;
2175
2176	if (*bufpp == NULL) {
2177		listall(string, &tclist);
2178		return (-1);
2179	}
2180	if ((indx = findname(string, "third", bufpp, &tclist)) == -1)
2181		return (-1);
2182	mib[2] = indx;
2183	*typep = tclist.list[indx].ctl_type;
2184	return (3);
2185}
2186
2187/*
2188 * Handle hardware monitoring sensors support
2189 */
2190int
2191sysctl_sensors(char *string, char **bufpp, int mib[], int flags, int *typep)
2192{
2193	char *devname, *typename;
2194	int dev, numt, i;
2195	enum sensor_type type;
2196	struct sensordev snsrdev;
2197	size_t sdlen = sizeof(snsrdev);
2198
2199	if (*bufpp == NULL) {
2200		char buf[SYSCTL_BUFSIZ];
2201
2202		/* scan all sensor devices */
2203		for (dev = 0; dev < MAXSENSORDEVICES; dev++) {
2204			mib[2] = dev;
2205			if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1)
2206				continue;
2207			snprintf(buf, sizeof(buf), "%s.%s",
2208			    string, snsrdev.xname);
2209			print_sensordev(buf, mib, 3, &snsrdev);
2210		}
2211		return (-1);
2212	}
2213
2214	/*
2215	 * If we get this far, it means that some arguments were
2216	 * provided below hw.sensors tree.
2217	 * The first branch of hw.sensors tree is the device name.
2218	 */
2219	if ((devname = strsep(bufpp, ".")) == NULL) {
2220		warnx("%s: incomplete specification", string);
2221		return (-1);
2222	}
2223	/* convert sensor device string to an integer */
2224	for (dev = 0; dev < MAXSENSORDEVICES; dev++) {
2225		mib[2] = dev;
2226		if (sysctl(mib, 3, &snsrdev, &sdlen, NULL, 0) == -1)
2227			continue;
2228		if (strcmp(devname, snsrdev.xname) == 0)
2229			break;
2230	}
2231	if (strcmp(devname, snsrdev.xname) != 0) {
2232		warnx("%s: sensor device not found: %s", string, devname);
2233		return (-1);
2234	}
2235	if (*bufpp == NULL) {
2236		/* only device name was provided -- let's print all sensors
2237		 * that are attached to the specified device
2238		 */
2239		print_sensordev(string, mib, 3, &snsrdev);
2240		return (-1);
2241	}
2242
2243	/*
2244	 * At this point we have identified the sensor device,
2245	 * now let's go further and identify sensor type.
2246	 */
2247	if ((typename = strsep(bufpp, ".")) == NULL) {
2248		warnx("%s: incomplete specification", string);
2249		return (-1);
2250	}
2251	numt = -1;
2252	for (i = 0; typename[i] != '\0'; i++)
2253		if (isdigit(typename[i])) {
2254			numt = atoi(&typename[i]);
2255			typename[i] = '\0';
2256			break;
2257		}
2258	for (type = 0; type < SENSOR_MAX_TYPES; type++)
2259		if (strcmp(typename, sensor_type_s[type]) == 0)
2260			break;
2261	if (type == SENSOR_MAX_TYPES) {
2262		warnx("%s: sensor type not recognised: %s", string, typename);
2263		return (-1);
2264	}
2265	mib[3] = type;
2266
2267	/*
2268	 * If no integer was provided after sensor_type, let's
2269	 * print all sensors of the specified type.
2270	 */
2271	if (numt == -1) {
2272		print_sensordev(string, mib, 4, &snsrdev);
2273		return (-1);
2274	}
2275
2276	/*
2277	 * At this point we know that we have received a direct request
2278	 * via command-line for a specific sensor. Let's have the parse()
2279	 * function deal with it further, and report any errors if such
2280	 * sensor node does not exist.
2281	 */
2282	mib[4] = numt;
2283	*typep = CTLTYPE_STRUCT;
2284	return (5);
2285}
2286
2287/*
2288 * Print sensors from the specified device.
2289 */
2290
2291void
2292print_sensordev(char *string, int mib[], u_int mlen, struct sensordev *snsrdev)
2293{
2294	char buf[SYSCTL_BUFSIZ];
2295	enum sensor_type type;
2296
2297	if (mlen == 3) {
2298		for (type = 0; type < SENSOR_MAX_TYPES; type++) {
2299			mib[3] = type;
2300			snprintf(buf, sizeof(buf), "%s.%s",
2301			    string, sensor_type_s[type]);
2302			print_sensordev(buf, mib, mlen+1, snsrdev);
2303		}
2304		return;
2305	}
2306
2307	if (mlen == 4) {
2308		int numt;
2309
2310		type = mib[3];
2311		for (numt = 0; numt < snsrdev->maxnumt[type]; numt++) {
2312			mib[4] = numt;
2313			snprintf(buf, sizeof(buf), "%s%u", string, numt);
2314			print_sensordev(buf, mib, mlen+1, snsrdev);
2315		}
2316		return;
2317	}
2318
2319	if (mlen == 5) {
2320		struct sensor snsr;
2321		size_t slen = sizeof(snsr);
2322
2323		/* this function is only printing sensors in bulk, so we
2324		 * do not return any error messages if the requested sensor
2325		 * is not found by sysctl(3)
2326		 */
2327		if (sysctl(mib, 5, &snsr, &slen, NULL, 0) == -1)
2328			return;
2329
2330		if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0) {
2331			if (!nflag)
2332				printf("%s%s", string, equ);
2333			print_sensor(&snsr);
2334			printf("\n");
2335		}
2336		return;
2337	}
2338}
2339
2340void
2341print_sensor(struct sensor *s)
2342{
2343	const char *name;
2344
2345	if (s->flags & SENSOR_FUNKNOWN)
2346		printf("unknown");
2347	else {
2348		switch (s->type) {
2349		case SENSOR_TEMP:
2350			printf("%.2f degC",
2351			    (s->value - 273150000) / 1000000.0);
2352			break;
2353		case SENSOR_FANRPM:
2354			printf("%lld RPM", s->value);
2355			break;
2356		case SENSOR_VOLTS_DC:
2357			printf("%.2f VDC", s->value / 1000000.0);
2358			break;
2359		case SENSOR_WATTS:
2360			printf("%.2f W", s->value / 1000000.0);
2361			break;
2362		case SENSOR_AMPS:
2363			printf("%.2f A", s->value / 1000000.0);
2364			break;
2365		case SENSOR_WATTHOUR:
2366			printf("%.2f Wh", s->value / 1000000.0);
2367			break;
2368		case SENSOR_AMPHOUR:
2369			printf("%.2f Ah", s->value / 1000000.0);
2370			break;
2371		case SENSOR_INDICATOR:
2372			printf("%s", s->value ? "On" : "Off");
2373			break;
2374		case SENSOR_INTEGER:
2375			printf("%lld", s->value);
2376			break;
2377		case SENSOR_PERCENT:
2378			printf("%.2f%%", s->value / 1000.0);
2379			break;
2380		case SENSOR_LUX:
2381			printf("%.2f lx", s->value / 1000000.0);
2382			break;
2383		case SENSOR_DRIVE:
2384			switch (s->value) {
2385			case SENSOR_DRIVE_EMPTY:
2386				name = "empty";
2387				break;
2388			case SENSOR_DRIVE_READY:
2389				name = "ready";
2390				break;
2391			case SENSOR_DRIVE_POWERUP:
2392				name = "powering up";
2393				break;
2394			case SENSOR_DRIVE_ONLINE:
2395				name = "online";
2396				break;
2397			case SENSOR_DRIVE_IDLE:
2398				name = "idle";
2399				break;
2400			case SENSOR_DRIVE_ACTIVE:
2401				name = "active";
2402				break;
2403			case SENSOR_DRIVE_REBUILD:
2404				name = "rebuilding";
2405				break;
2406			case SENSOR_DRIVE_POWERDOWN:
2407				name = "powering down";
2408				break;
2409			case SENSOR_DRIVE_FAIL:
2410				name = "failed";
2411				break;
2412			case SENSOR_DRIVE_PFAIL:
2413				name = "degraded";
2414				break;
2415			default:
2416				name = "unknown";
2417				break;
2418			}
2419			printf(name);
2420			break;
2421		case SENSOR_TIMEDELTA:
2422			printf("%.6f secs", s->value / 1000000000.0);
2423			break;
2424		default:
2425			printf("unknown");
2426		}
2427	}
2428
2429	if (s->desc[0] != '\0')
2430		printf(" (%s)", s->desc);
2431
2432	switch (s->status) {
2433	case SENSOR_S_UNSPEC:
2434		break;
2435	case SENSOR_S_OK:
2436		printf(", OK");
2437		break;
2438	case SENSOR_S_WARN:
2439		printf(", WARNING");
2440		break;
2441	case SENSOR_S_CRIT:
2442		printf(", CRITICAL");
2443		break;
2444	case SENSOR_S_UNKNOWN:
2445		printf(", UNKNOWN");
2446		break;
2447	}
2448
2449	if (s->tv.tv_sec) {
2450		time_t t = s->tv.tv_sec;
2451		char ct[26];
2452
2453		ctime_r(&t, ct);
2454		ct[19] = '\0';
2455		printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
2456	}
2457}
2458
2459struct emulname {
2460	char *name;
2461	int index;
2462} *emul_names;
2463int	emul_num, nemuls;
2464int	emul_init(void);
2465
2466int
2467sysctl_emul(char *string, char *newval, int flags)
2468{
2469	int mib[4], enabled, i, old, print, found = 0;
2470	char *head, *target;
2471	size_t len;
2472
2473	if (emul_init() == -1) {
2474		warnx("emul_init: out of memory");
2475		return (1);
2476	}
2477
2478	mib[0] = CTL_KERN;
2479	mib[1] = KERN_EMUL;
2480	mib[3] = KERN_EMUL_ENABLED;
2481	head = "kern.emul.";
2482
2483	if (aflag || strcmp(string, "kern.emul") == 0) {
2484		if (newval) {
2485			warnx("%s: specification is incomplete", string);
2486			return (1);
2487		}
2488		if (nflag)
2489			printf("%d\n", nemuls);
2490		else
2491			printf("%snemuls%s%d\n", head, equ, nemuls);
2492		for (i = 0; i < emul_num; i++) {
2493			if (emul_names[i].name == NULL)
2494				break;
2495			if (i > 0 && strcmp(emul_names[i].name,
2496			    emul_names[i-1].name) == 0)
2497				continue;
2498			mib[2] = emul_names[i].index;
2499			len = sizeof(int);
2500			if (sysctl(mib, 4, &enabled, &len, NULL, 0) == -1) {
2501				warn("%s", string);
2502				continue;
2503			}
2504			if (nflag)
2505				printf("%d\n", enabled);
2506			else
2507				printf("%s%s%s%d\n", head, emul_names[i].name,
2508				    equ, enabled);
2509		}
2510		return (0);
2511	}
2512	/* User specified a third level name */
2513	target = strrchr(string, '.');
2514	target++;
2515	if (strcmp(target, "nemuls") == 0) {
2516		if (newval) {
2517			warnx("Operation not permitted");
2518			return (1);
2519		}
2520		if (nflag)
2521			printf("%d\n", nemuls);
2522		else
2523			printf("%snemuls = %d\n", head, nemuls);
2524		return (0);
2525	}
2526	print = 1;
2527	for (i = 0; i < emul_num; i++) {
2528		if (!emul_names[i].name || (strcmp(target, emul_names[i].name)))
2529			continue;
2530		found = 1;
2531		mib[2] = emul_names[i].index;
2532		len = sizeof(int);
2533		if (newval) {
2534			enabled = atoi(newval);
2535			if (sysctl(mib, 4, &old, &len, &enabled, len) == -1) {
2536				warn("%s", string);
2537				print = 0;
2538				continue;
2539			}
2540			if (print) {
2541				if (nflag)
2542					printf("%d\n", enabled);
2543				else
2544					printf("%s%s: %d -> %d\n", head,
2545					    target, old, enabled);
2546			}
2547		} else {
2548			if (sysctl(mib, 4, &enabled, &len, NULL, 0) == -1) {
2549				warn("%s", string);
2550				continue;
2551			}
2552			if (print) {
2553				if (nflag)
2554					printf("%d\n", enabled);
2555				else
2556					printf("%s%s = %d\n", head, target,
2557					    enabled);
2558			}
2559		}
2560		print = 0;
2561	}
2562	if (!found)
2563		warnx("third level name %s in kern.emul is invalid",
2564		    string);
2565	return (0);
2566
2567
2568}
2569
2570int
2571emulcmp(const void *m, const void *n)
2572{
2573	const struct emulname *a = m, *b = n;
2574
2575	if (!a || !a->name)
2576		return 1;
2577	if (!b || !b->name)
2578		return -1;
2579	return (strcmp(a->name, b->name));
2580}
2581
2582int
2583emul_init(void)
2584{
2585	static int done;
2586	char string[16];
2587	int mib[4], i;
2588	size_t len;
2589
2590	if (done)
2591		return (0);
2592	done = 1;
2593
2594	mib[0] = CTL_KERN;
2595	mib[1] = KERN_EMUL;
2596	mib[2] = KERN_EMUL_NUM;
2597	len = sizeof(int);
2598	if (sysctl(mib, 3, &emul_num, &len, NULL, 0) == -1)
2599		return (-1);
2600
2601	emul_names = calloc(emul_num, sizeof(*emul_names));
2602	if (emul_names == NULL)
2603		return (-1);
2604
2605	nemuls = emul_num;
2606	for (i = 0; i < emul_num; i++) {
2607		emul_names[i].index = mib[2] = i + 1;
2608		mib[3] = KERN_EMUL_NAME;
2609		len = sizeof(string);
2610		if (sysctl(mib, 4, string, &len, NULL, 0) == -1)
2611			continue;
2612		if (strcmp(string, "native") == 0)
2613			continue;
2614		emul_names[i].name = strdup(string);
2615		if (emul_names[i].name == NULL) {
2616			free(emul_names);
2617			return (-1);
2618		}
2619	}
2620	qsort(emul_names, nemuls, sizeof(*emul_names), emulcmp);
2621	for (i = 0; i < emul_num; i++) {
2622		if (!emul_names[i].name || (i > 0 &&
2623		    strcmp(emul_names[i].name, emul_names[i - 1].name) == 0))
2624			nemuls--;
2625	}
2626	return (0);
2627}
2628
2629/*
2630 * Scan a list of names searching for a particular name.
2631 */
2632int
2633findname(char *string, char *level, char **bufp, struct list *namelist)
2634{
2635	char *name;
2636	int i;
2637
2638	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
2639		warnx("%s: incomplete specification", string);
2640		return (-1);
2641	}
2642	for (i = 0; i < namelist->size; i++)
2643		if (namelist->list[i].ctl_name != NULL &&
2644		    strcmp(name, namelist->list[i].ctl_name) == 0)
2645			break;
2646	if (i == namelist->size) {
2647		warnx("%s level name %s in %s is invalid", level, name, string);
2648		return (-1);
2649	}
2650	return (i);
2651}
2652
2653void
2654usage(void)
2655{
2656
2657	(void)fprintf(stderr,
2658	    "usage: sysctl [-Aan]\n"
2659	    "       sysctl [-n] name ...\n"
2660	    "       sysctl [-nq] name=value ...\n");
2661	exit(1);
2662}
2663