sysctl.c revision 1.51
1/*	$OpenBSD: sysctl.c,v 1.51 2000/06/07 00:20:32 itojun 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. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44#if 0
45static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
46#else
47static char *rcsid = "$OpenBSD: sysctl.c,v 1.51 2000/06/07 00:20:32 itojun Exp $";
48#endif
49#endif /* not lint */
50
51#include <sys/param.h>
52#include <sys/gmon.h>
53#include <sys/mount.h>
54#include <sys/stat.h>
55#include <sys/sysctl.h>
56#include <sys/socket.h>
57#include <vm/vm_param.h>
58#include <machine/cpu.h>
59#include <net/route.h>
60
61#include <netinet/in.h>
62#include <netinet/in_systm.h>
63#include <netinet/ip.h>
64#include <netinet/in_pcb.h>
65#include <netinet/ip_icmp.h>
66#include <netinet/ip_ipip.h>
67#include <netinet/ip_ether.h>
68#include <netinet/ip_ah.h>
69#include <netinet/ip_esp.h>
70#include <netinet/icmp_var.h>
71#include <netinet/ip_var.h>
72#include <netinet/udp.h>
73#include <netinet/udp_var.h>
74#include <netinet/tcp.h>
75#include <netinet/tcp_timer.h>
76#include <netinet/tcp_var.h>
77#include <netinet/ip_gre.h>
78
79#ifdef INET6
80#include <netinet/ip6.h>
81#include <netinet/icmp6.h>
82#include <netinet6/ip6_var.h>
83#include <netinet6/pim6_var.h>
84#endif
85
86#include <ufs/ufs/quota.h>
87#include <ufs/ufs/inode.h>
88#include <ufs/ffs/fs.h>
89#include <ufs/ffs/ffs_extern.h>
90
91#include <nfs/rpcv2.h>
92#include <nfs/nfsproto.h>
93#include <nfs/nfs.h>
94
95#include <netipx/ipx.h>
96#include <netipx/ipx_var.h>
97#include <netipx/spx_var.h>
98#include <ddb/db_var.h>
99#include <dev/rndvar.h>
100
101#include <err.h>
102#include <errno.h>
103#include <stdio.h>
104#include <stdlib.h>
105#include <string.h>
106#include <ctype.h>
107
108#ifdef CPU_BIOS
109#include <machine/biosvar.h>
110#endif
111
112struct ctlname topname[] = CTL_NAMES;
113struct ctlname kernname[] = CTL_KERN_NAMES;
114struct ctlname vmname[] = CTL_VM_NAMES;
115struct ctlname fsname[] = CTL_FS_NAMES;
116struct ctlname netname[] = CTL_NET_NAMES;
117struct ctlname hwname[] = CTL_HW_NAMES;
118struct ctlname username[] = CTL_USER_NAMES;
119struct ctlname debugname[CTL_DEBUG_MAXID];
120struct ctlname *vfsname;
121#ifdef CTL_MACHDEP_NAMES
122struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
123#endif
124struct ctlname ddbname[] = CTL_DDB_NAMES;
125char names[BUFSIZ];
126int lastused;
127
128struct list {
129	struct	ctlname *list;
130	int	size;
131};
132struct list toplist = { topname, CTL_MAXID };
133struct list secondlevel[] = {
134	{ 0, 0 },			/* CTL_UNSPEC */
135	{ kernname, KERN_MAXID },	/* CTL_KERN */
136	{ vmname, VM_MAXID },		/* CTL_VM */
137	{ fsname, FS_MAXID },		/* CTL_FS */
138	{ netname, NET_MAXID },		/* CTL_NET */
139	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
140	{ hwname, HW_MAXID },		/* CTL_HW */
141#ifdef CTL_MACHDEP_NAMES
142	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
143#else
144	{ 0, 0 },			/* CTL_MACHDEP */
145#endif
146	{ username, USER_MAXID },	/* CTL_USER_NAMES */
147	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
148	{ 0, 0 },			/* CTL_VFS */
149};
150
151int	Aflag, aflag, nflag, wflag;
152
153/*
154 * Variables requiring special processing.
155 */
156#define	CLOCK		0x00000001
157#define	BOOTTIME	0x00000002
158#define	CHRDEV		0x00000004
159#define	BLKDEV		0x00000008
160#define	RNDSTATS	0x00000010
161#define	BADDYNAMIC	0x00000020
162#define	BIOSGEO		0x00000040
163#define	BIOSDEV		0x00000080
164#define	MAJ2DEV		0x00000100
165#define	UNSIGNED	0x00000200
166
167/* prototypes */
168void debuginit __P((void));
169void listall __P((char *, struct list *));
170void parse __P((char *, int));
171void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
172void usage __P((void));
173int findname __P((char *, char *, char **, struct list *));
174int sysctl_inet __P((char *, char **, int *, int, int *));
175#ifdef INET6
176int sysctl_inet6 __P((char *, char **, int *, int, int *));
177#endif
178int sysctl_ipx __P((char *, char **, int *, int, int *));
179int sysctl_fs __P((char *, char **, int *, int, int *));
180static int sysctl_vfs __P((char *, char **, int[], int, int *));
181static int sysctl_vfsgen __P((char *, char **, int[], int, int *));
182int sysctl_bios __P((char *, char **, int *, int, int *));
183void vfsinit __P((void));
184
185int
186main(argc, argv)
187	int argc;
188	char *argv[];
189{
190	int ch, lvl1;
191
192	while ((ch = getopt(argc, argv, "Aanw")) != -1) {
193		switch (ch) {
194
195		case 'A':
196			Aflag = 1;
197			break;
198
199		case 'a':
200			aflag = 1;
201			break;
202
203		case 'n':
204			nflag = 1;
205			break;
206
207		case 'w':
208			wflag = 1;
209			break;
210
211		default:
212			usage();
213		}
214	}
215	argc -= optind;
216	argv += optind;
217
218	if (argc == 0 && (Aflag || aflag)) {
219		debuginit();
220		vfsinit();
221		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
222			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
223		exit(0);
224	}
225	if (argc == 0)
226		usage();
227	for (; *argv != NULL; ++argv)
228		parse(*argv, 1);
229	exit(0);
230}
231
232/*
233 * List all variables known to the system.
234 */
235void
236listall(prefix, lp)
237	char *prefix;
238	struct list *lp;
239{
240	int lvl2;
241	char *cp, name[BUFSIZ];
242
243	if (lp->list == NULL)
244		return;
245	(void)strncpy(name, prefix, BUFSIZ-1);
246	name[BUFSIZ-1] = '\0';
247	cp = &name[strlen(name)];
248	*cp++ = '.';
249	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
250		if (lp->list[lvl2].ctl_name == NULL)
251			continue;
252		(void)strcpy(cp, lp->list[lvl2].ctl_name);
253		parse(name, Aflag);
254	}
255}
256
257/*
258 * Parse a name into a MIB entry.
259 * Lookup and print out the MIB entry if it exists.
260 * Set a new value if requested.
261 */
262void
263parse(string, flags)
264	char *string;
265	int flags;
266{
267	int indx, type, state, intval, len;
268	size_t size, newsize = 0;
269	int special = 0;
270	void *newval = 0;
271	quad_t quadval;
272	struct list *lp;
273	int mib[CTL_MAXNAME];
274	char *cp, *bufp, buf[BUFSIZ];
275
276	(void)strncpy(buf, string, sizeof(buf) - 1);
277	buf[sizeof(buf) - 1] = '\0';
278	bufp = buf;
279	if ((cp = strchr(string, '=')) != NULL) {
280		if (!wflag)
281			errx(2, "must specify -w to set variables");
282		*strchr(buf, '=') = '\0';
283		*cp++ = '\0';
284		while (isspace(*cp))
285			cp++;
286		newval = cp;
287		newsize = strlen(cp);
288	}
289	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
290		return;
291	mib[0] = indx;
292	if (indx == CTL_VFS)
293		vfsinit();
294	if (indx == CTL_DEBUG)
295		debuginit();
296	lp = &secondlevel[indx];
297	if (lp->list == 0) {
298		warnx("%s: class is not implemented", topname[indx].ctl_name);
299		return;
300	}
301	if (bufp == NULL) {
302		listall(topname[indx].ctl_name, lp);
303		return;
304	}
305	if ((indx = findname(string, "second", &bufp, lp)) == -1)
306		return;
307	mib[1] = indx;
308	type = lp->list[indx].ctl_type;
309	len = 2;
310	switch (mib[0]) {
311
312	case CTL_KERN:
313		switch (mib[1]) {
314		case KERN_PROF:
315			mib[2] = GPROF_STATE;
316			size = sizeof(state);
317			if (sysctl(mib, 3, &state, &size, NULL, 0) == -1) {
318				if (flags == 0)
319					return;
320				if (!nflag)
321					(void)printf("%s: ", string);
322				(void)puts("kernel is not compiled for profiling");
323				return;
324			}
325			if (!nflag)
326				(void)printf("%s = %s\n", string,
327				    state == GMON_PROF_OFF ? "off" : "running");
328			return;
329		case KERN_VNODE:
330		case KERN_FILE:
331			if (flags == 0)
332				return;
333			warnx("use pstat to view %s information", string);
334			return;
335		case KERN_PROC:
336			if (flags == 0)
337				return;
338			warnx("use ps to view %s information", string);
339			return;
340		case KERN_NTPTIME:
341			if (flags == 0)
342				return;
343			warnx("use xntpdc to view %s information", string);
344			return;
345		case KERN_CLOCKRATE:
346			special |= CLOCK;
347			break;
348		case KERN_BOOTTIME:
349			special |= BOOTTIME;
350			break;
351		case KERN_RND:
352			special |= RNDSTATS;
353			break;
354		case KERN_HOSTID:
355		case KERN_ARND:
356			special |= UNSIGNED;
357			break;
358		}
359		break;
360
361	case CTL_HW:
362		break;
363
364	case CTL_VM:
365		if (mib[1] == VM_LOADAVG) {
366			double loads[3];
367
368			getloadavg(loads, 3);
369			if (!nflag)
370				(void)printf("%s = ", string);
371			(void)printf("%.2f %.2f %.2f\n", loads[0],
372			    loads[1], loads[2]);
373			return;
374		} else if (mib[1] == VM_PSSTRINGS) {
375			struct _ps_strings _ps;
376
377			len = sizeof(_ps);
378			if (sysctl(mib, 2, &_ps, &len, NULL, 0) == -1) {
379				if (flags == 0)
380					return;
381				if (!nflag)
382					(void)printf("%s: ", string);
383				(void)puts("can't find ps strings");
384				return;
385			}
386			if (!nflag)
387				(void)printf("%s = ", string);
388			(void)printf("%p\n", _ps.val);
389			return;
390		}
391#ifdef UVM
392		if (mib[1] != VM_SWAPENCRYPT) {
393#endif
394		if (flags == 0)
395			return;
396		warnx("use vmstat or systat to view %s information", string);
397		return;
398#ifdef UVM
399		}
400#endif
401		break;
402
403	case CTL_NET:
404		if (mib[1] == PF_INET) {
405			len = sysctl_inet(string, &bufp, mib, flags, &type);
406			if (len < 0)
407				return;
408
409			if ((mib[2] == IPPROTO_TCP &&
410			     mib[3] == TCPCTL_BADDYNAMIC) ||
411			    (mib[2] == IPPROTO_UDP &&
412			     mib[3] == UDPCTL_BADDYNAMIC)) {
413
414				special |= BADDYNAMIC;
415
416				if (newval != NULL)
417					parse_baddynamic(mib, len, string,
418					    &newval, &newsize, flags, nflag);
419			}
420			break;
421		}
422#ifdef INET6
423		if (mib[1] == PF_INET6) {
424			len = sysctl_inet6(string, &bufp, mib, flags, &type);
425			if (len < 0)
426				return;
427
428			break;
429		}
430#endif
431		if (mib[1] == PF_IPX) {
432			len = sysctl_ipx(string, &bufp, mib, flags, &type);
433			if (len >= 0)
434				break;
435			return;
436		}
437		if (flags == 0)
438			return;
439		warnx("use netstat to view %s information", string);
440		return;
441
442	case CTL_DEBUG:
443		mib[2] = CTL_DEBUG_VALUE;
444		len = 3;
445		break;
446
447	case CTL_MACHDEP:
448#ifdef CPU_CONSDEV
449		if (mib[1] == CPU_CONSDEV)
450			special |= CHRDEV;
451#endif
452#ifdef CPU_BLK2CHR
453		if (mib[1] == CPU_BLK2CHR) {
454			if (bufp == NULL)
455				return;
456			mib[2] = makedev(atoi(bufp),0);
457			bufp = NULL;
458			len = 3;
459			special |= CHRDEV;
460			break;
461		}
462#endif
463#ifdef CPU_CHR2BLK
464		if (mib[1] == CPU_CHR2BLK) {
465			if (bufp == NULL)
466				return;
467			mib[2] = makedev(atoi(bufp),0);
468			bufp = NULL;
469			len = 3;
470			special |= BLKDEV;
471			break;
472		}
473#endif
474#ifdef CPU_BIOS
475		if (mib[1] == CPU_BIOS) {
476			len = sysctl_bios(string, &bufp, mib, flags, &type);
477			if (len < 0)
478				return;
479			if (mib[2] == BIOS_DEV)
480				special |= BIOSDEV;
481			if (mib[2] == BIOS_DISKINFO)
482				special |= BIOSGEO;
483			break;
484		}
485#endif
486		break;
487
488	case CTL_FS:
489		len = sysctl_fs(string, &bufp, mib, flags, &type);
490		if (len >= 0)
491			break;
492		return;
493
494	case CTL_VFS:
495		if (mib[1])
496			len = sysctl_vfs(string, &bufp, mib, flags, &type);
497		else
498			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
499		if (len >= 0) {
500			if (type == CTLTYPE_STRUCT) {
501				if (flags)
502					warnx("use nfsstat to view %s information",
503					    MOUNT_NFS);
504				return;
505			} else
506				break;
507		}
508		return;
509
510	case CTL_USER:
511	case CTL_DDB:
512		break;
513
514	default:
515		warnx("illegal top level value: %d", mib[0]);
516		return;
517
518	}
519	if (bufp) {
520		warnx("name %s in %s is unknown", bufp, string);
521		return;
522	}
523	if (newsize > 0) {
524		switch (type) {
525		case CTLTYPE_INT:
526			errno = 0;
527			if (special & UNSIGNED)
528				intval = strtoul(newval, &cp, 10);
529			else
530				intval = strtol(newval, &cp, 10);
531			if (*cp != '\0') {
532				warnx("%s: illegal value: %s", string,
533				    (char *)newval);
534				return;
535			}
536			if (errno == ERANGE) {
537				warnx("%s: value %s out of range", string,
538				    (char *)newval);
539				return;
540			}
541			newval = &intval;
542			newsize = sizeof(intval);
543			break;
544
545		case CTLTYPE_QUAD:
546			(void)sscanf(newval, "%qd", &quadval);
547			newval = &quadval;
548			newsize = sizeof(quadval);
549			break;
550		}
551	}
552	size = BUFSIZ;
553	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
554		if (flags == 0)
555			return;
556		switch (errno) {
557		case EOPNOTSUPP:
558			warnx("%s: value is not available", string);
559			return;
560		case ENOTDIR:
561			warnx("%s: specification is incomplete", string);
562			return;
563		case ENOMEM:
564			warnx("%s: type is unknown to this program", string);
565			return;
566		case ENXIO:
567			if (special & BIOSGEO)
568				return;
569		default:
570			warn(string);
571			return;
572		}
573	}
574	if (special & CLOCK) {
575		struct clockinfo *clkp = (struct clockinfo *)buf;
576
577		if (!nflag)
578			(void)printf("%s = ", string);
579		(void)printf(
580		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
581		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
582		return;
583	}
584	if (special & BOOTTIME) {
585		struct timeval *btp = (struct timeval *)buf;
586		time_t boottime;
587
588		if (!nflag) {
589			boottime = btp->tv_sec;
590			(void)printf("%s = %s", string, ctime(&boottime));
591		} else
592			(void)printf("%ld\n", btp->tv_sec);
593		return;
594	}
595	if (special & BLKDEV) {
596		dev_t dev = *(dev_t *)buf;
597
598		if (!nflag)
599			(void)printf("%s = %s\n", string,
600			    devname(dev, S_IFBLK));
601		else
602			(void)printf("0x%x\n", dev);
603		return;
604	}
605	if (special & CHRDEV) {
606		dev_t dev = *(dev_t *)buf;
607
608		if (!nflag)
609			(void)printf("%s = %s\n", string,
610			    devname(dev, S_IFCHR));
611		else
612			(void)printf("0x%x\n", dev);
613		return;
614	}
615#ifdef CPU_BIOS
616	if (special & BIOSGEO) {
617		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
618
619		if (!nflag)
620			(void)printf("%s = ", string);
621		(void)printf("bootdev = 0x%x, "
622			     "cylinders = %u, heads = %u, sectors = %u\n",
623			     pdi->bsd_dev, pdi->bios_cylinders, pdi->bios_heads,
624			     pdi->bios_sectors);
625		return;
626	}
627	if (special & BIOSDEV) {
628		int dev = *(int*)buf;
629
630		if (!nflag)
631			(void)printf("%s = ", string);
632		(void) printf("0x%02x\n", dev);
633		return;
634	}
635#endif
636	if (special & UNSIGNED) {
637		if (newsize == 0) {
638			if (!nflag)
639				(void)printf("%s = ", string);
640			(void)printf("%u\n", *(u_int *)buf);
641		} else {
642			if (!nflag)
643				(void)printf("%s: %u -> ", string,
644				    *(u_int *)buf);
645			(void)printf("%u\n", *(u_int *)newval);
646		}
647		return;
648	}
649	if (special & RNDSTATS) {
650		struct rndstats *rndstats = (struct rndstats *)buf;
651		int i;
652
653		if (!nflag)
654			(void)printf("%s = ", string);
655		(void)printf(
656		"%qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu %qu",
657		    rndstats->rnd_total,
658		    rndstats->rnd_used, rndstats->rnd_reads,
659		    rndstats->arc4_reads, rndstats->arc4_nstirs,
660		    rndstats->arc4_stirs,
661		    rndstats->rnd_pad[0],
662		    rndstats->rnd_pad[1],
663		    rndstats->rnd_pad[2],
664		    rndstats->rnd_pad[3],
665		    rndstats->rnd_pad[4],
666		    rndstats->rnd_waits,
667		    rndstats->rnd_enqs, rndstats->rnd_deqs,
668		    rndstats->rnd_drops, rndstats->rnd_drople);
669		for (i = 0; i < sizeof(rndstats->rnd_ed)/sizeof(rndstats->rnd_ed[0]); i++)
670			(void)printf(" %qu", rndstats->rnd_ed[i]);
671		for (i = 0; i < sizeof(rndstats->rnd_sc)/sizeof(rndstats->rnd_sc[0]); i++)
672			(void)printf(" %qu", rndstats->rnd_sc[i]);
673		for (i = 0; i < sizeof(rndstats->rnd_sb)/sizeof(rndstats->rnd_sb[0]); i++)
674			(void)printf(" %qu", rndstats->rnd_sb[i]);
675		printf("\n");
676		return;
677	}
678	if (special & BADDYNAMIC) {
679		in_port_t port, lastport;
680		u_int32_t *baddynamic = (u_int32_t *)buf;
681
682		if (!nflag)
683			(void)printf("%s%s", string, newsize ? ": " : " = ");
684		lastport = 0;
685		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
686			if (DP_ISSET(baddynamic, port)) {
687				(void)printf("%s%hd", lastport ? "," : "",
688				    port);
689				lastport = port;
690			}
691		if (newsize != 0) {
692			if (!nflag)
693				fputs(" -> ", stdout);
694			baddynamic = (u_int32_t *)newval;
695			lastport = 0;
696			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
697			    port++)
698				if (DP_ISSET(baddynamic, port)) {
699					(void)printf("%s%hd",
700					    lastport ? "," : "", port);
701					lastport = port;
702				}
703		}
704		(void)putchar('\n');
705		return;
706	}
707	switch (type) {
708	case CTLTYPE_INT:
709		if (newsize == 0) {
710			if (!nflag)
711				(void)printf("%s = ", string);
712			(void)printf("%d\n", *(int *)buf);
713		} else {
714			if (!nflag)
715				(void)printf("%s: %d -> ", string,
716				    *(int *)buf);
717			(void)printf("%d\n", *(int *)newval);
718		}
719		return;
720
721	case CTLTYPE_STRING:
722		if (newsize == 0) {
723			if (!nflag)
724				(void)printf("%s = ", string);
725			(void)puts(buf);
726		} else {
727			if (!nflag)
728				(void)printf("%s: %s -> ", string, buf);
729			(void)puts((char *)newval);
730		}
731		return;
732
733	case CTLTYPE_QUAD:
734		if (newsize == 0) {
735			if (!nflag)
736				(void)printf("%s = ", string);
737			(void)printf("%qd\n", *(quad_t *)buf);
738		} else {
739			if (!nflag)
740				(void)printf("%s: %qd -> ", string,
741				    *(quad_t *)buf);
742			(void)printf("%qd\n", *(quad_t *)newval);
743		}
744		return;
745
746	case CTLTYPE_STRUCT:
747		warnx("%s: unknown structure returned", string);
748		return;
749
750	default:
751	case CTLTYPE_NODE:
752		warnx("%s: unknown type returned", string);
753		return;
754	}
755}
756
757void
758parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
759	int mib[];
760	size_t len;
761	char *string;
762	void **newvalp;
763	size_t *newsizep;
764	int flags;
765	int nflag;
766{
767	static u_int32_t newbaddynamic[DP_MAPSIZE];
768	in_port_t port;
769	size_t size;
770	char action, *cp;
771
772	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
773		size = sizeof(newbaddynamic);
774		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
775			if (flags == 0)
776				return;
777			if (!nflag)
778				(void)printf("%s: ", string);
779			(void)puts("kernel does contain bad dynamic port tables");
780			return;
781		}
782
783		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
784			if (*cp != '+' && *cp != '-')
785				errx(1, "cannot mix +/- with full list");
786			action = *cp++;
787			port = atoi(cp);
788			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
789				errx(1, "invalid port, range is %d to %d",
790				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
791			if (action == '+')
792				DP_SET(newbaddynamic, port);
793			else
794				DP_CLR(newbaddynamic, port);
795		}
796	} else {
797		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
798		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
799			port = atoi(cp);
800			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
801				errx(1, "invalid port, range is %d to %d",
802				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
803			DP_SET(newbaddynamic, port);
804		}
805	}
806
807	*newvalp = (void *)newbaddynamic;
808	*newsizep = sizeof(newbaddynamic);
809}
810
811/*
812 * Initialize the set of debugging names
813 */
814void
815debuginit()
816{
817	int mib[3], loc, i;
818	size_t size;
819
820	if (secondlevel[CTL_DEBUG].list != 0)
821		return;
822	secondlevel[CTL_DEBUG].list = debugname;
823	mib[0] = CTL_DEBUG;
824	mib[2] = CTL_DEBUG_NAME;
825	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
826		mib[1] = i;
827		size = BUFSIZ - loc;
828		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
829			continue;
830		debugname[i].ctl_name = &names[loc];
831		debugname[i].ctl_type = CTLTYPE_INT;
832		loc += size;
833	}
834	lastused = loc;
835}
836
837struct ctlname vfsgennames[] = CTL_VFSGENCTL_NAMES;
838struct ctlname ffsname[] = FFS_NAMES;
839struct ctlname nfsname[] = FS_NFS_NAMES;
840struct list *vfsvars;
841int *vfs_typenums;
842
843/*
844 * Initialize the set of filesystem names
845 */
846void
847vfsinit()
848{
849	int mib[4], maxtypenum, cnt, loc, size;
850	struct vfsconf vfc;
851	size_t buflen;
852
853	if (secondlevel[CTL_VFS].list != 0)
854		return;
855	mib[0] = CTL_VFS;
856	mib[1] = VFS_GENERIC;
857	mib[2] = VFS_MAXTYPENUM;
858	buflen = 4;
859	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
860		return;
861	maxtypenum++;	/* + generic */
862	if ((vfs_typenums = malloc(maxtypenum * sizeof(int))) == NULL)
863		return;
864	memset(vfs_typenums, 0, maxtypenum * sizeof(int));
865	if ((vfsvars = malloc(maxtypenum * sizeof(*vfsvars))) == NULL) {
866		free(vfs_typenums);
867		return;
868	}
869	memset(vfsvars, 0, maxtypenum * sizeof(*vfsvars));
870	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == NULL) {
871		free(vfs_typenums);
872		free(vfsvars);
873		return;
874	}
875	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
876	mib[2] = VFS_CONF;
877	buflen = sizeof vfc;
878	for (loc = lastused, cnt = 1; cnt < maxtypenum; cnt++) {
879		mib[3] = cnt - 1;
880		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
881			if (errno == EOPNOTSUPP)
882				continue;
883			warn("vfsinit");
884			free(vfsname);
885			return;
886		}
887		if (!strcmp(vfc.vfc_name, MOUNT_FFS)) {
888			vfsvars[cnt].list = ffsname;
889			vfsvars[cnt].size = FFS_MAXID;
890		}
891		if (!strcmp(vfc.vfc_name, MOUNT_NFS)) {
892			vfsvars[cnt].list = nfsname;
893			vfsvars[cnt].size = NFS_MAXID;
894		}
895		vfs_typenums[cnt] = vfc.vfc_typenum;
896		strcat(&names[loc], vfc.vfc_name);
897		vfsname[cnt].ctl_name = &names[loc];
898		vfsname[cnt].ctl_type = CTLTYPE_NODE;
899		size = strlen(vfc.vfc_name) + 1;
900		loc += size;
901	}
902	lastused = loc;
903
904	vfsname[0].ctl_name = "mounts";
905	vfsname[0].ctl_type = CTLTYPE_NODE;
906	vfsvars[0].list = vfsname + 1;
907	vfsvars[0].size = maxtypenum - 1;
908
909	secondlevel[CTL_VFS].list = vfsname;
910	secondlevel[CTL_VFS].size = maxtypenum;
911	return;
912}
913
914int
915sysctl_vfsgen(string, bufpp, mib, flags, typep)
916	char *string;
917	char **bufpp;
918	int mib[];
919	int flags;
920	int *typep;
921{
922	int indx;
923	size_t size;
924	struct vfsconf vfc;
925
926	if (*bufpp == NULL) {
927		listall(string, vfsvars);
928		return (-1);
929	}
930
931	if ((indx = findname(string, "third", bufpp, vfsvars)) == -1)
932		return (-1);
933
934	mib[1] = VFS_GENERIC;
935	mib[2] = VFS_CONF;
936	mib[3] = indx;
937	size = sizeof vfc;
938	if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
939		if (errno != EOPNOTSUPP)
940			warn("vfs print");
941		return -1;
942	}
943	if (flags == 0 && vfc.vfc_refcount == 0)
944		return -1;
945	if (!nflag)
946		fprintf(stdout, "%s has %d mounted instance%s\n",
947		    string, vfc.vfc_refcount,
948		    vfc.vfc_refcount != 1 ? "s" : "");
949	else
950		fprintf(stdout, "%d\n", vfc.vfc_refcount);
951
952	return -1;
953}
954
955int
956sysctl_vfs(string, bufpp, mib, flags, typep)
957	char *string;
958	char **bufpp;
959	int mib[];
960	int flags;
961	int *typep;
962{
963	struct list *lp = &vfsvars[mib[1]];
964	int indx;
965
966	if (lp->list == NULL) {
967		if (flags)
968			warnx("No variables defined for file system %s", string);
969		return(-1);
970	}
971	if (*bufpp == NULL) {
972		listall(string, lp);
973		return (-1);
974	}
975	if ((indx = findname(string, "third", bufpp, lp)) == -1)
976		return (-1);
977
978	mib[1] = vfs_typenums[mib[1]];
979	mib[2] = indx;
980	*typep = lp->list[indx].ctl_type;
981	return (3);
982}
983
984struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
985struct list fslist = { posixname, FS_POSIX_MAXID };
986
987/*
988 * handle file system requests
989 */
990int
991sysctl_fs(string, bufpp, mib, flags, typep)
992	char *string;
993	char **bufpp;
994	int mib[];
995	int flags;
996	int *typep;
997{
998	int indx;
999
1000	if (*bufpp == NULL) {
1001		listall(string, &fslist);
1002		return(-1);
1003	}
1004	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
1005		return(-1);
1006	mib[2] = indx;
1007	*typep = fslist.list[indx].ctl_type;
1008	return(3);
1009}
1010
1011#ifdef CPU_BIOS
1012struct ctlname biosname[] = CTL_BIOS_NAMES;
1013struct list bioslist = { biosname, BIOS_MAXID };
1014
1015/*
1016 * handle BIOS requests
1017 */
1018int
1019sysctl_bios(string, bufpp, mib, flags, typep)
1020	char *string;
1021	char **bufpp;
1022	int mib[];
1023	int flags;
1024	int *typep;
1025{
1026	char *name;
1027	int indx;
1028
1029	if (*bufpp == NULL) {
1030		listall(string, &bioslist);
1031		return(-1);
1032	}
1033	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
1034		return(-1);
1035	mib[2] = indx;
1036	if (indx == BIOS_DISKINFO) {
1037		if (*bufpp == NULL) {
1038			char name[BUFSIZ];
1039
1040			/* scan all the bios devices */
1041			for (indx = 0; indx < 256; indx++) {
1042				snprintf(name, sizeof(name), "%s.%u",
1043					 string, indx);
1044				parse(name, 1);
1045			}
1046			return(-1);
1047		}
1048		if ((name = strsep(bufpp, ".")) == NULL) {
1049			warnx("%s: incomplete specification", string);
1050			return(-1);
1051		}
1052		mib[3] = atoi(name);
1053		*typep = CTLTYPE_STRUCT;
1054		return 4;
1055	} else {
1056		*typep = bioslist.list[indx].ctl_type;
1057		return(3);
1058	}
1059}
1060#endif
1061
1062struct ctlname inetname[] = CTL_IPPROTO_NAMES;
1063struct ctlname ipname[] = IPCTL_NAMES;
1064struct ctlname icmpname[] = ICMPCTL_NAMES;
1065struct ctlname ipipname[] = IPIPCTL_NAMES;
1066struct ctlname tcpname[] = TCPCTL_NAMES;
1067struct ctlname udpname[] = UDPCTL_NAMES;
1068struct ctlname espname[] = ESPCTL_NAMES;
1069struct ctlname ahname[] = AHCTL_NAMES;
1070struct ctlname etheripname[] = ETHERIPCTL_NAMES;
1071struct ctlname grename[] = GRECTL_NAMES;
1072struct ctlname mobileipname[] = MOBILEIPCTL_NAMES;
1073struct list inetlist = { inetname, IPPROTO_MAXID };
1074struct list inetvars[] = {
1075	{ ipname, IPCTL_MAXID },	/* ip */
1076	{ icmpname, ICMPCTL_MAXID },	/* icmp */
1077	{ 0, 0 },			/* igmp */
1078	{ 0, 0 },			/* ggmp */
1079	{ ipipname, IPIPCTL_MAXID },	/* ipencap */
1080	{ 0, 0 },
1081	{ tcpname, TCPCTL_MAXID },	/* tcp */
1082	{ 0, 0 },
1083	{ 0, 0 },			/* egp */
1084	{ 0, 0 },
1085	{ 0, 0 },
1086	{ 0, 0 },
1087	{ 0, 0 },			/* pup */
1088	{ 0, 0 },
1089	{ 0, 0 },
1090	{ 0, 0 },
1091	{ 0, 0 },
1092	{ udpname, UDPCTL_MAXID },	/* udp */
1093	{ 0, 0 },
1094	{ 0, 0 },
1095	{ 0, 0 },
1096	{ 0, 0 },
1097	{ 0, 0 },
1098	{ 0, 0 },
1099	{ 0, 0 },
1100	{ 0, 0 },
1101	{ 0, 0 },
1102	{ 0, 0 },
1103	{ 0, 0 },
1104	{ 0, 0 },
1105	{ 0, 0 },
1106	{ 0, 0 },
1107	{ 0, 0 },
1108	{ 0, 0 },
1109	{ 0, 0 },
1110	{ 0, 0 },
1111	{ 0, 0 },
1112	{ 0, 0 },
1113	{ 0, 0 },
1114	{ 0, 0 },
1115	{ 0, 0 },
1116	{ 0, 0 },
1117	{ 0, 0 },
1118	{ 0, 0 },
1119	{ 0, 0 },
1120	{ 0, 0 },
1121	{ 0, 0 },
1122	{ grename, GRECTL_MAXID }, /* GRE */
1123	{ 0, 0 },
1124	{ 0, 0 },
1125	{ espname, ESPCTL_MAXID },	/* esp */
1126	{ ahname, AHCTL_MAXID },	/* ah */
1127	{ 0, 0 },
1128	{ 0, 0 },
1129	{ 0, 0 },
1130	{ mobileipname, MOBILEIPCTL_MAXID }, /* mobileip */
1131	{ 0, 0 },
1132	{ 0, 0 },
1133	{ 0, 0 },
1134	{ 0, 0 },
1135	{ 0, 0 },
1136	{ 0, 0 },
1137	{ 0, 0 },
1138	{ 0, 0 },
1139	{ 0, 0 },
1140	{ 0, 0 },
1141	{ 0, 0 },
1142	{ 0, 0 },
1143	{ 0, 0 },
1144	{ 0, 0 },
1145	{ 0, 0 },
1146	{ 0, 0 },
1147	{ 0, 0 },
1148	{ 0, 0 },
1149	{ 0, 0 },
1150	{ 0, 0 },
1151	{ 0, 0 },
1152	{ 0, 0 },
1153	{ 0, 0 },
1154	{ 0, 0 },
1155	{ 0, 0 },
1156	{ 0, 0 },
1157	{ 0, 0 },
1158	{ 0, 0 },
1159	{ 0, 0 },
1160	{ 0, 0 },
1161	{ 0, 0 },
1162	{ 0, 0 },
1163	{ 0, 0 },
1164	{ 0, 0 },
1165	{ 0, 0 },
1166	{ 0, 0 },
1167	{ 0, 0 },
1168	{ 0, 0 },
1169	{ 0, 0 },
1170	{ 0, 0 },
1171	{ 0, 0 },
1172	{ etheripname, ETHERIPCTL_MAXID },
1173};
1174
1175/*
1176 * handle internet requests
1177 */
1178int
1179sysctl_inet(string, bufpp, mib, flags, typep)
1180	char *string;
1181	char **bufpp;
1182	int mib[];
1183	int flags;
1184	int *typep;
1185{
1186	struct list *lp;
1187	int indx;
1188
1189	if (*bufpp == NULL) {
1190		listall(string, &inetlist);
1191		return(-1);
1192	}
1193	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
1194		return(-1);
1195	mib[2] = indx;
1196	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
1197		lp = &inetvars[indx];
1198	else if (!flags)
1199		return(-1);
1200	else {
1201		warnx("%s: no variables defined for this protocol", string);
1202		return(-1);
1203	}
1204	if (*bufpp == NULL) {
1205		listall(string, lp);
1206		return(-1);
1207	}
1208	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1209		return(-1);
1210	mib[3] = indx;
1211	*typep = lp->list[indx].ctl_type;
1212	return(4);
1213}
1214
1215#ifdef INET6
1216struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
1217struct ctlname ip6name[] = IPV6CTL_NAMES;
1218struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
1219struct ctlname pim6name[] = PIM6CTL_NAMES;
1220struct list inet6list = { inet6name, IPV6PROTO_MAXID };
1221struct list inet6vars[] = {
1222/*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1223	{ 0, 0 },
1224	{ 0, 0 },
1225	{ 0, 0 },
1226	{ 0, 0 },
1227	{ 0, 0 },
1228/*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1229	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1230/*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1231	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1232/*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1233	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1234/*40*/	{ 0, 0 },
1235	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
1236	{ 0, 0 },
1237	{ 0, 0 },
1238	{ 0, 0 },
1239	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1240/*50*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1241	{ 0, 0 },
1242	{ 0, 0 },
1243	{ 0, 0 },
1244	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
1245	{ 0, 0 },
1246/*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1247	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1248/*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1249	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1250/*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1251	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1252/*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1253	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
1254/*100*/	{ 0, 0 },
1255	{ 0, 0 },
1256	{ 0, 0 },
1257	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
1258};
1259
1260/*
1261 * handle internet6 requests
1262 */
1263int
1264sysctl_inet6(string, bufpp, mib, flags, typep)
1265	char *string;
1266	char **bufpp;
1267	int mib[];
1268	int flags;
1269	int *typep;
1270{
1271	struct list *lp;
1272	int indx;
1273
1274	if (*bufpp == NULL) {
1275		listall(string, &inet6list);
1276		return(-1);
1277	}
1278	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
1279		return(-1);
1280	mib[2] = indx;
1281	if (indx < IPV6PROTO_MAXID && inet6vars[indx].list != NULL)
1282		lp = &inet6vars[indx];
1283	else if (!flags)
1284		return(-1);
1285	else {
1286		warnx("%s: no variables defined for this protocol", string);
1287		return(-1);
1288	}
1289	if (*bufpp == NULL) {
1290		listall(string, lp);
1291		return(-1);
1292	}
1293	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1294		return(-1);
1295	mib[3] = indx;
1296	*typep = lp->list[indx].ctl_type;
1297	return(4);
1298}
1299#endif
1300
1301struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
1302struct ctlname ipxpname[] = IPXCTL_NAMES;
1303struct ctlname spxpname[] = SPXCTL_NAMES;
1304struct list ipxlist = { ipxname, IPXCTL_MAXID };
1305struct list ipxvars[] = {
1306	{ ipxpname, IPXCTL_MAXID },	/* ipx */
1307	{ 0, 0 },
1308	{ 0, 0 },
1309	{ 0, 0 },
1310	{ 0, 0 },
1311	{ spxpname, SPXCTL_MAXID },
1312};
1313
1314/*
1315 * Handle internet requests
1316 */
1317int
1318sysctl_ipx(string, bufpp, mib, flags, typep)
1319	char *string;
1320	char **bufpp;
1321	int mib[];
1322	int flags;
1323	int *typep;
1324{
1325	struct list *lp;
1326	int indx;
1327
1328	if (*bufpp == NULL) {
1329		listall(string, &ipxlist);
1330		return(-1);
1331	}
1332	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1333		return(-1);
1334	mib[2] = indx;
1335	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1336		lp = &ipxvars[indx];
1337	else if (!flags)
1338		return(-1);
1339	else {
1340		warnx("%s: no variables defined for this protocol", string);
1341		return(-1);
1342	}
1343	if (*bufpp == NULL) {
1344		listall(string, lp);
1345		return(-1);
1346	}
1347	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1348		return(-1);
1349	mib[3] = indx;
1350	*typep = lp->list[indx].ctl_type;
1351	return(4);
1352}
1353
1354/*
1355 * Scan a list of names searching for a particular name.
1356 */
1357int
1358findname(string, level, bufp, namelist)
1359	char *string;
1360	char *level;
1361	char **bufp;
1362	struct list *namelist;
1363{
1364	char *name;
1365	int i;
1366
1367	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1368		warnx("%s: incomplete specification", string);
1369		return(-1);
1370	}
1371	for (i = 0; i < namelist->size; i++)
1372		if (namelist->list[i].ctl_name != NULL &&
1373		    strcmp(name, namelist->list[i].ctl_name) == 0)
1374			break;
1375	if (i == namelist->size) {
1376		warnx("%s level name %s in %s is invalid", level, name, string);
1377		return(-1);
1378	}
1379	return(i);
1380}
1381
1382void
1383usage()
1384{
1385
1386	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
1387	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
1388	    "sysctl [-n] -a", "sysctl [-n] -A");
1389	exit(1);
1390}
1391