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