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