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