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