xref: /openbsd-src/sbin/sysctl/sysctl.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /*	$OpenBSD: sysctl.c,v 1.39 1999/04/11 19:41:41 niklas 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
38 static 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
45 static char sccsid[] = "@(#)sysctl.c	8.5 (Berkeley) 5/9/95";
46 #else
47 static char *rcsid = "$OpenBSD: sysctl.c,v 1.39 1999/04/11 19:41:41 niklas 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_ip4.h>
67 #include <netinet/ip_ah.h>
68 #include <netinet/ip_esp.h>
69 #include <netinet/icmp_var.h>
70 #include <netinet/ip_var.h>
71 #include <netinet/udp.h>
72 #include <netinet/udp_var.h>
73 #include <netinet/tcp.h>
74 #include <netinet/tcp_timer.h>
75 #include <netinet/tcp_var.h>
76 
77 #include <netipx/ipx.h>
78 #include <netipx/ipx_var.h>
79 #include <netipx/spx_var.h>
80 #include <ddb/db_var.h>
81 #include <dev/rndvar.h>
82 
83 #include <err.h>
84 #include <errno.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <ctype.h>
89 
90 #ifdef CPU_BIOS
91 #include <machine/biosvar.h>
92 #endif
93 
94 struct ctlname topname[] = CTL_NAMES;
95 struct ctlname kernname[] = CTL_KERN_NAMES;
96 struct ctlname vmname[] = CTL_VM_NAMES;
97 struct ctlname fsname[] = CTL_FS_NAMES;
98 struct ctlname netname[] = CTL_NET_NAMES;
99 struct ctlname hwname[] = CTL_HW_NAMES;
100 struct ctlname username[] = CTL_USER_NAMES;
101 struct ctlname debugname[CTL_DEBUG_MAXID];
102 struct ctlname *vfsname;
103 #ifdef CTL_MACHDEP_NAMES
104 struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
105 #endif
106 struct ctlname ddbname[] = CTL_DDB_NAMES;
107 char names[BUFSIZ];
108 int lastused;
109 
110 struct list {
111 	struct	ctlname *list;
112 	int	size;
113 };
114 struct list toplist = { topname, CTL_MAXID };
115 struct list secondlevel[] = {
116 	{ 0, 0 },			/* CTL_UNSPEC */
117 	{ kernname, KERN_MAXID },	/* CTL_KERN */
118 	{ vmname, VM_MAXID },		/* CTL_VM */
119 	{ fsname, FS_MAXID },		/* CTL_FS */
120 	{ netname, NET_MAXID },		/* CTL_NET */
121 	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
122 	{ hwname, HW_MAXID },		/* CTL_HW */
123 #ifdef CTL_MACHDEP_NAMES
124 	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
125 #else
126 	{ 0, 0 },			/* CTL_MACHDEP */
127 #endif
128 	{ username, USER_MAXID },	/* CTL_USER_NAMES */
129 	{ ddbname, DBCTL_MAXID },	/* CTL_DDB_NAMES */
130 	{ 0, 0 },			/* CTL_VFS */
131 };
132 
133 int	Aflag, aflag, nflag, wflag;
134 
135 /*
136  * Variables requiring special processing.
137  */
138 #define	CLOCK		0x00000001
139 #define	BOOTTIME	0x00000002
140 #define	CHRDEV		0x00000004
141 #define	BLKDEV		0x00000008
142 #define RNDSTATS	0x00000010
143 #define BADDYNAMIC	0x00000020
144 #define BIOSGEO		0x00000040
145 #define BIOSDEV		0x00000080
146 #define	MAJ2DEV		0x00000100
147 
148 /* prototypes */
149 void debuginit __P((void));
150 void listall __P((char *, struct list *));
151 void parse __P((char *, int));
152 void parse_baddynamic __P((int *, size_t, char *, void **, size_t *, int, int));
153 void usage __P((void));
154 int findname __P((char *, char *, char **, struct list *));
155 int sysctl_inet __P((char *, char **, int *, int, int *));
156 int sysctl_ipx __P((char *, char **, int *, int, int *));
157 int sysctl_fs __P((char *, char **, int *, int, int *));
158 int sysctl_bios __P((char *, char **, int *, int, int *));
159 void vfsinit __P((void));
160 
161 int
162 main(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  */
211 void
212 listall(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  */
238 void
239 parse(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 (flags == 0)
395 			return;
396 		warnx("use netstat to view %s information", string);
397 		return;
398 
399 	case CTL_DEBUG:
400 		mib[2] = CTL_DEBUG_VALUE;
401 		len = 3;
402 		break;
403 
404 	case CTL_MACHDEP:
405 #ifdef CPU_CONSDEV
406 		if (mib[1] == CPU_CONSDEV)
407 			special |= CHRDEV;
408 #endif
409 #ifdef CPU_BLK2CHR
410 		if (mib[1] == CPU_BLK2CHR) {
411 			if (bufp == NULL)
412 				return;
413 			mib[2] = makedev(atoi(bufp),0);
414 			bufp = NULL;
415 			len = 3;
416 			special |= CHRDEV;
417 			break;
418 		}
419 #endif
420 #ifdef CPU_CHR2BLK
421 		if (mib[1] == CPU_CHR2BLK) {
422 			if (bufp == NULL)
423 				return;
424 			mib[2] = makedev(atoi(bufp),0);
425 			bufp = NULL;
426 			len = 3;
427 			special |= BLKDEV;
428 			break;
429 		}
430 #endif
431 #ifdef CPU_BIOS
432 		if (mib[1] == CPU_BIOS) {
433 			len = sysctl_bios(string, &bufp, mib, flags, &type);
434 			if (len < 0)
435 				return;
436 			if (mib[2] == BIOS_DEV)
437 				special |= BIOSDEV;
438 			if (mib[2] == BIOS_DISKINFO)
439 				special |= BIOSGEO;
440 			break;
441 		}
442 #endif
443 		break;
444 
445 	case CTL_FS:
446 		len = sysctl_fs(string, &bufp, mib, flags, &type);
447 		if (len >= 0)
448 			break;
449 		return;
450 
451 	case CTL_VFS:
452 		mib[3] = mib[1];
453 		mib[1] = VFS_GENERIC;
454 		mib[2] = VFS_CONF;
455 		len = 4;
456 		size = sizeof vfc;
457 		if (sysctl(mib, 4, &vfc, &size, (void *)0, (size_t)0) < 0) {
458 			if (errno != EOPNOTSUPP)
459 				perror("vfs print");
460 			return;
461 		}
462 		if (flags == 0 && vfc.vfc_refcount == 0)
463 			return;
464 		if (!nflag)
465 			fprintf(stdout, "%s has %d mounted instance%s\n",
466 			    string, vfc.vfc_refcount,
467 			    vfc.vfc_refcount != 1 ? "s" : "");
468 		else
469 			fprintf(stdout, "%d\n", vfc.vfc_refcount);
470 		return;
471 
472 	case CTL_USER:
473 	case CTL_DDB:
474 		break;
475 
476 	default:
477 		warnx("illegal top level value: %d", mib[0]);
478 		return;
479 
480 	}
481 	if (bufp) {
482 		warnx("name %s in %s is unknown", bufp, string);
483 		return;
484 	}
485 	if (newsize > 0) {
486 		switch (type) {
487 		case CTLTYPE_INT:
488 			intval = atoi(newval);
489 			newval = &intval;
490 			newsize = sizeof(intval);
491 			break;
492 
493 		case CTLTYPE_QUAD:
494 			(void)sscanf(newval, "%qd", &quadval);
495 			newval = &quadval;
496 			newsize = sizeof(quadval);
497 			break;
498 		}
499 	}
500 	size = BUFSIZ;
501 	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
502 		if (flags == 0)
503 			return;
504 		switch (errno) {
505 		case EOPNOTSUPP:
506 			warnx("%s: value is not available", string);
507 			return;
508 		case ENOTDIR:
509 			warnx("%s: specification is incomplete", string);
510 			return;
511 		case ENOMEM:
512 			warnx("%s: type is unknown to this program", string);
513 			return;
514 		case ENXIO:
515 			if (special & BIOSGEO)
516 				return;
517 		default:
518 			warn(string);
519 			return;
520 		}
521 	}
522 	if (special & CLOCK) {
523 		struct clockinfo *clkp = (struct clockinfo *)buf;
524 
525 		if (!nflag)
526 			(void)printf("%s = ", string);
527 		(void)printf(
528 		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
529 		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
530 		return;
531 	}
532 	if (special & BOOTTIME) {
533 		struct timeval *btp = (struct timeval *)buf;
534 		time_t boottime;
535 
536 		if (!nflag) {
537 			boottime = btp->tv_sec;
538 			(void)printf("%s = %s", string, ctime(&boottime));
539 		} else
540 			(void)printf("%ld\n", btp->tv_sec);
541 		return;
542 	}
543 	if (special & BLKDEV) {
544 		dev_t dev = *(dev_t *)buf;
545 
546 		if (!nflag)
547 			(void)printf("%s = %s\n", string,
548 			    devname(dev, S_IFBLK));
549 		else
550 			(void)printf("0x%x\n", dev);
551 		return;
552 	}
553 	if (special & CHRDEV) {
554 		dev_t dev = *(dev_t *)buf;
555 
556 		if (!nflag)
557 			(void)printf("%s = %s\n", string,
558 			    devname(dev, S_IFCHR));
559 		else
560 			(void)printf("0x%x\n", dev);
561 		return;
562 	}
563 #ifdef CPU_BIOS
564 	if (special & BIOSGEO) {
565 		bios_diskinfo_t *pdi = (bios_diskinfo_t *)buf;
566 
567 		if (!nflag)
568 			(void)printf("%s = ", string);
569 		(void)printf("bootdev = 0x%x, "
570 			     "cylinders = %u, heads = %u, sectors = %u\n",
571 			     pdi->bsd_dev, pdi->bios_cylinders, pdi->bios_heads,
572 			     pdi->bios_sectors);
573 		return;
574 	}
575 	if (special & BIOSDEV) {
576 		int dev = *(int*)buf;
577 
578 		if (!nflag)
579 			(void)printf("%s = ", string);
580 		(void) printf("0x%02x\n", dev);
581 		return;
582 	}
583 #endif
584 	if (special & RNDSTATS) {
585 		struct rndstats *rndstats = (struct rndstats *)buf;
586 
587 		if (!nflag)
588 			(void)printf("%s = ", string);
589 		(void)printf(
590 		    "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u\n",
591 		    rndstats->rnd_total, rndstats->rnd_used,
592 		    rndstats->arc4_reads, rndstats->rnd_timer,
593 		    rndstats->rnd_mouse, rndstats->rnd_tty,
594 		    rndstats->rnd_disk, rndstats->rnd_net,
595 		    rndstats->rnd_reads, rndstats->rnd_waits,
596 		    rndstats->rnd_enqs, rndstats->rnd_deqs,
597 		    rndstats->rnd_drops, rndstats->rnd_drople,
598 		    rndstats->rnd_asleep, rndstats->rnd_queued);
599 		return;
600 	}
601 	if (special & BADDYNAMIC) {
602 		in_port_t port, lastport;
603 		u_int32_t *baddynamic = (u_int32_t *)buf;
604 
605 		if (!nflag)
606 			(void)printf("%s%s", string, newsize ? ": " : " = ");
607 		lastport = 0;
608 		for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED; port++)
609 			if (DP_ISSET(baddynamic, port)) {
610 				(void)printf("%s%hd", lastport ? "," : "",
611 				    port);
612 				lastport = port;
613 			}
614 		if (newsize != 0) {
615 			if (!nflag)
616 				fputs(" -> ", stdout);
617 			baddynamic = (u_int32_t *)newval;
618 			lastport = 0;
619 			for (port = IPPORT_RESERVED/2; port < IPPORT_RESERVED;
620 			    port++)
621 				if (DP_ISSET(baddynamic, port)) {
622 					(void)printf("%s%hd",
623 					    lastport ? "," : "", port);
624 					lastport = port;
625 				}
626 		}
627 		(void)putchar('\n');
628 		return;
629 	}
630 	switch (type) {
631 	case CTLTYPE_INT:
632 		if (newsize == 0) {
633 			if (!nflag)
634 				(void)printf("%s = ", string);
635 			(void)printf("%d\n", *(int *)buf);
636 		} else {
637 			if (!nflag)
638 				(void)printf("%s: %d -> ", string,
639 				    *(int *)buf);
640 			(void)printf("%d\n", *(int *)newval);
641 		}
642 		return;
643 
644 	case CTLTYPE_STRING:
645 		if (newsize == 0) {
646 			if (!nflag)
647 				(void)printf("%s = ", string);
648 			(void)puts(buf);
649 		} else {
650 			if (!nflag)
651 				(void)printf("%s: %s -> ", string, buf);
652 			(void)puts((char *)newval);
653 		}
654 		return;
655 
656 	case CTLTYPE_QUAD:
657 		if (newsize == 0) {
658 			if (!nflag)
659 				(void)printf("%s = ", string);
660 			(void)printf("%qd\n", *(quad_t *)buf);
661 		} else {
662 			if (!nflag)
663 				(void)printf("%s: %qd -> ", string,
664 				    *(quad_t *)buf);
665 			(void)printf("%qd\n", *(quad_t *)newval);
666 		}
667 		return;
668 
669 	case CTLTYPE_STRUCT:
670 		warnx("%s: unknown structure returned", string);
671 		return;
672 
673 	default:
674 	case CTLTYPE_NODE:
675 		warnx("%s: unknown type returned", string);
676 		return;
677 	}
678 }
679 
680 void
681 parse_baddynamic(mib, len, string, newvalp, newsizep, flags, nflag)
682 	int mib[];
683 	size_t len;
684 	char *string;
685 	void **newvalp;
686 	size_t *newsizep;
687 	int flags;
688 	int nflag;
689 {
690 	static u_int32_t newbaddynamic[DP_MAPSIZE];
691 	in_port_t port;
692 	size_t size;
693 	char action, *cp;
694 
695 	if (strchr((char *)*newvalp, '+') || strchr((char *)*newvalp, '-')) {
696 		size = sizeof(newbaddynamic);
697 		if (sysctl(mib, len, newbaddynamic, &size, 0, 0) == -1) {
698 			if (flags == 0)
699 				return;
700 			if (!nflag)
701 				(void)printf("%s: ", string);
702 			(void)puts("kernel does contain bad dynamic port tables");
703 			return;
704 		}
705 
706 		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
707 			if (*cp != '+' && *cp != '-')
708 				errx(1, "cannot mix +/- with full list");
709 			action = *cp++;
710 			port = atoi(cp);
711 			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
712 				errx(1, "invalid port, range is %d to %d",
713 				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
714 			if (action == '+')
715 				DP_SET(newbaddynamic, port);
716 			else
717 				DP_CLR(newbaddynamic, port);
718 		}
719 	} else {
720 		(void)memset((void *)newbaddynamic, 0, sizeof(newbaddynamic));
721 		while (*newvalp && (cp = strsep((char **)newvalp, ", \t")) && *cp) {
722 			port = atoi(cp);
723 			if (port < IPPORT_RESERVED/2 || port >= IPPORT_RESERVED)
724 				errx(1, "invalid port, range is %d to %d",
725 				    IPPORT_RESERVED/2, IPPORT_RESERVED-1);
726 			DP_SET(newbaddynamic, port);
727 		}
728 	}
729 
730 	*newvalp = (void *)newbaddynamic;
731 	*newsizep = sizeof(newbaddynamic);
732 }
733 
734 /*
735  * Initialize the set of debugging names
736  */
737 void
738 debuginit()
739 {
740 	int mib[3], loc, i;
741 	size_t size;
742 
743 	if (secondlevel[CTL_DEBUG].list != 0)
744 		return;
745 	secondlevel[CTL_DEBUG].list = debugname;
746 	mib[0] = CTL_DEBUG;
747 	mib[2] = CTL_DEBUG_NAME;
748 	for (loc = lastused, i = 0; i < CTL_DEBUG_MAXID; i++) {
749 		mib[1] = i;
750 		size = BUFSIZ - loc;
751 		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
752 			continue;
753 		debugname[i].ctl_name = &names[loc];
754 		debugname[i].ctl_type = CTLTYPE_INT;
755 		loc += size;
756 	}
757 	lastused = loc;
758 }
759 
760 /*
761  * Initialize the set of filesystem names
762  */
763 void
764 vfsinit()
765 {
766 	int mib[4], maxtypenum, cnt, loc, size;
767 	struct vfsconf vfc;
768 	size_t buflen;
769 
770 	if (secondlevel[CTL_VFS].list != 0)
771 		return;
772 	mib[0] = CTL_VFS;
773 	mib[1] = VFS_GENERIC;
774 	mib[2] = VFS_MAXTYPENUM;
775 	buflen = 4;
776 	if (sysctl(mib, 3, &maxtypenum, &buflen, (void *)0, (size_t)0) < 0)
777 		return;
778 	if ((vfsname = malloc(maxtypenum * sizeof(*vfsname))) == 0)
779 		return;
780 	memset(vfsname, 0, maxtypenum * sizeof(*vfsname));
781 	mib[2] = VFS_CONF;
782 	buflen = sizeof vfc;
783 	for (loc = lastused, cnt = 0; cnt < maxtypenum; cnt++) {
784 		mib[3] = cnt;
785 		if (sysctl(mib, 4, &vfc, &buflen, (void *)0, (size_t)0) < 0) {
786 			if (errno == EOPNOTSUPP)
787 				continue;
788 			perror("vfsinit");
789 			free(vfsname);
790 			return;
791 		}
792 		strcat(&names[loc], vfc.vfc_name);
793 		vfsname[cnt].ctl_name = &names[loc];
794 		vfsname[cnt].ctl_type = CTLTYPE_INT;
795 		size = strlen(vfc.vfc_name) + 1;
796 		loc += size;
797 	}
798 	lastused = loc;
799 	secondlevel[CTL_VFS].list = vfsname;
800 	secondlevel[CTL_VFS].size = maxtypenum;
801 	return;
802 }
803 
804 struct ctlname posixname[] = CTL_FS_POSIX_NAMES;
805 struct list fslist = { posixname, FS_POSIX_MAXID };
806 
807 /*
808  * handle file system requests
809  */
810 int
811 sysctl_fs(string, bufpp, mib, flags, typep)
812 	char *string;
813 	char **bufpp;
814 	int mib[];
815 	int flags;
816 	int *typep;
817 {
818 	int indx;
819 
820 	if (*bufpp == NULL) {
821 		listall(string, &fslist);
822 		return(-1);
823 	}
824 	if ((indx = findname(string, "third", bufpp, &fslist)) == -1)
825 		return(-1);
826 	mib[2] = indx;
827 	*typep = fslist.list[indx].ctl_type;
828 	return(3);
829 }
830 
831 #ifdef CPU_BIOS
832 struct ctlname biosname[] = CTL_BIOS_NAMES;
833 struct list bioslist = { biosname, BIOS_MAXID };
834 
835 /*
836  * handle BIOS requests
837  */
838 int
839 sysctl_bios(string, bufpp, mib, flags, typep)
840 	char *string;
841 	char **bufpp;
842 	int mib[];
843 	int flags;
844 	int *typep;
845 {
846 	char *name;
847 	int indx;
848 
849 	if (*bufpp == NULL) {
850 		listall(string, &bioslist);
851 		return(-1);
852 	}
853 	if ((indx = findname(string, "third", bufpp, &bioslist)) == -1)
854 		return(-1);
855 	mib[2] = indx;
856 	if (indx == BIOS_DISKINFO) {
857 		if (*bufpp == NULL) {
858 			char name[BUFSIZ];
859 
860 			/* scan all the bios devices */
861 			for (indx = 0; indx < 256; indx++) {
862 				snprintf(name, sizeof(name), "%s.%u",
863 					 string, indx);
864 				parse(name, 1);
865 			}
866 			return(-1);
867 		}
868 		if ((name = strsep(bufpp, ".")) == NULL) {
869 			warnx("%s: incomplete specification", string);
870 			return(-1);
871 		}
872 		mib[3] = atoi(name);
873 		*typep = CTLTYPE_STRUCT;
874 		return 4;
875 	} else {
876 		*typep = bioslist.list[indx].ctl_type;
877 		return(3);
878 	}
879 }
880 #endif
881 
882 struct ctlname inetname[] = CTL_IPPROTO_NAMES;
883 struct ctlname ipname[] = IPCTL_NAMES;
884 struct ctlname icmpname[] = ICMPCTL_NAMES;
885 struct ctlname ip4name[] = IP4CTL_NAMES;
886 struct ctlname tcpname[] = TCPCTL_NAMES;
887 struct ctlname udpname[] = UDPCTL_NAMES;
888 struct ctlname espname[] = ESPCTL_NAMES;
889 struct ctlname ahname[] = AHCTL_NAMES;
890 struct list inetlist = { inetname, IPPROTO_MAXID };
891 struct list inetvars[] = {
892 	{ ipname, IPCTL_MAXID },	/* ip */
893 	{ icmpname, ICMPCTL_MAXID },	/* icmp */
894 	{ 0, 0 },			/* igmp */
895 	{ 0, 0 },			/* ggmp */
896 	{ ip4name, IP4CTL_MAXID },	/* ipencap */
897 	{ 0, 0 },
898 	{ tcpname, TCPCTL_MAXID },	/* tcp */
899 	{ 0, 0 },
900 	{ 0, 0 },			/* egp */
901 	{ 0, 0 },
902 	{ 0, 0 },
903 	{ 0, 0 },
904 	{ 0, 0 },			/* pup */
905 	{ 0, 0 },
906 	{ 0, 0 },
907 	{ 0, 0 },
908 	{ 0, 0 },
909 	{ udpname, UDPCTL_MAXID },	/* udp */
910 	{ 0, 0 },
911 	{ 0, 0 },
912 	{ 0, 0 },
913 	{ 0, 0 },
914 	{ 0, 0 },
915 	{ 0, 0 },
916 	{ 0, 0 },
917 	{ 0, 0 },
918 	{ 0, 0 },
919 	{ 0, 0 },
920 	{ 0, 0 },
921 	{ 0, 0 },
922 	{ 0, 0 },
923 	{ 0, 0 },
924 	{ 0, 0 },
925 	{ 0, 0 },
926 	{ 0, 0 },
927 	{ 0, 0 },
928 	{ 0, 0 },
929 	{ 0, 0 },
930 	{ 0, 0 },
931 	{ 0, 0 },
932 	{ 0, 0 },
933 	{ 0, 0 },
934 	{ 0, 0 },
935 	{ 0, 0 },
936 	{ 0, 0 },
937 	{ 0, 0 },
938 	{ 0, 0 },
939 	{ 0, 0 },
940 	{ 0, 0 },
941 	{ 0, 0 },
942 	{ espname, ESPCTL_MAXID },	/* esp */
943 	{ ahname, AHCTL_MAXID },	/* ah */
944 };
945 
946 /*
947  * handle internet requests
948  */
949 int
950 sysctl_inet(string, bufpp, mib, flags, typep)
951 	char *string;
952 	char **bufpp;
953 	int mib[];
954 	int flags;
955 	int *typep;
956 {
957 	struct list *lp;
958 	int indx;
959 
960 	if (*bufpp == NULL) {
961 		listall(string, &inetlist);
962 		return(-1);
963 	}
964 	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
965 		return(-1);
966 	mib[2] = indx;
967 	if (indx < IPPROTO_MAXID && inetvars[indx].list != NULL)
968 		lp = &inetvars[indx];
969 	else if (!flags)
970 		return(-1);
971 	else {
972 		warnx("%s: no variables defined for this protocol", string);
973 		return(-1);
974 	}
975 	if (*bufpp == NULL) {
976 		listall(string, lp);
977 		return(-1);
978 	}
979 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
980 		return(-1);
981 	mib[3] = indx;
982 	*typep = lp->list[indx].ctl_type;
983 	return(4);
984 }
985 
986 struct ctlname ipxname[] = CTL_IPXPROTO_NAMES;
987 struct ctlname ipxpname[] = IPXCTL_NAMES;
988 struct ctlname spxpname[] = SPXCTL_NAMES;
989 struct list ipxlist = { ipxname, IPXCTL_MAXID };
990 struct list ipxvars[] = {
991 	{ ipxpname, IPXCTL_MAXID },	/* ipx */
992 	{ 0, 0 },
993 	{ 0, 0 },
994 	{ 0, 0 },
995 	{ 0, 0 },
996 	{ spxpname, SPXCTL_MAXID },
997 };
998 
999 /*
1000  * Handle internet requests
1001  */
1002 int
1003 sysctl_ipx(string, bufpp, mib, flags, typep)
1004 	char *string;
1005 	char **bufpp;
1006 	int mib[];
1007 	int flags;
1008 	int *typep;
1009 {
1010 	struct list *lp;
1011 	int indx;
1012 
1013 	if (*bufpp == NULL) {
1014 		listall(string, &ipxlist);
1015 		return(-1);
1016 	}
1017 	if ((indx = findname(string, "third", bufpp, &ipxlist)) == -1)
1018 		return(-1);
1019 	mib[2] = indx;
1020 	if (indx <= IPXPROTO_SPX && ipxvars[indx].list != NULL)
1021 		lp = &ipxvars[indx];
1022 	else if (!flags)
1023 		return(-1);
1024 	else {
1025 		warnx("%s: no variables defined for this protocol", string);
1026 		return(-1);
1027 	}
1028 	if (*bufpp == NULL) {
1029 		listall(string, lp);
1030 		return(-1);
1031 	}
1032 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1033 		return(-1);
1034 	mib[3] = indx;
1035 	*typep = lp->list[indx].ctl_type;
1036 	return(4);
1037 }
1038 
1039 /*
1040  * Scan a list of names searching for a particular name.
1041  */
1042 int
1043 findname(string, level, bufp, namelist)
1044 	char *string;
1045 	char *level;
1046 	char **bufp;
1047 	struct list *namelist;
1048 {
1049 	char *name;
1050 	int i;
1051 
1052 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1053 		warnx("%s: incomplete specification", string);
1054 		return(-1);
1055 	}
1056 	for (i = 0; i < namelist->size; i++)
1057 		if (namelist->list[i].ctl_name != NULL &&
1058 		    strcmp(name, namelist->list[i].ctl_name) == 0)
1059 			break;
1060 	if (i == namelist->size) {
1061 		warnx("%s level name %s in %s is invalid", level, name, string);
1062 		return(-1);
1063 	}
1064 	return(i);
1065 }
1066 
1067 void
1068 usage()
1069 {
1070 
1071 	(void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
1072 	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
1073 	    "sysctl [-n] -a", "sysctl [-n] -A");
1074 	exit(1);
1075 }
1076