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