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