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