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