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