xref: /netbsd-src/sbin/sysctl/sysctl.c (revision 27578b9aac214cc7796ead81dcc5427e79d5f2a0)
1 /*	$NetBSD: sysctl.c,v 1.49 2001/07/27 04:22:09 itojun Exp $	*/
2 
3 /*
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __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.1 (Berkeley) 6/6/93";
46 #else
47 __RCSID("$NetBSD: sysctl.c,v 1.49 2001/07/27 04:22:09 itojun Exp $");
48 #endif
49 #endif /* not lint */
50 
51 #include <sys/param.h>
52 #include <sys/gmon.h>
53 #include <sys/stat.h>
54 #include <sys/sysctl.h>
55 #include <sys/socket.h>
56 #include <sys/mount.h>
57 #include <sys/mbuf.h>
58 #include <sys/resource.h>
59 #include <uvm/uvm_param.h>
60 #include <machine/cpu.h>
61 
62 #include <ufs/ufs/dinode.h>
63 #include <ufs/ufs/dir.h>
64 #include <ufs/ffs/fs.h>
65 #include <ufs/ffs/ffs_extern.h>
66 
67 #include <nfs/rpcv2.h>
68 #include <nfs/nfsproto.h>
69 #include <nfs/nfs.h>
70 
71 #include <netinet/in.h>
72 #include <netinet/in_systm.h>
73 #include <netinet/ip.h>
74 #include <netinet/ip_icmp.h>
75 #include <netinet/icmp_var.h>
76 #include <netinet/ip_var.h>
77 #include <netinet/udp.h>
78 #include <netinet/udp_var.h>
79 #include <netinet/tcp.h>
80 #include <netinet/tcp_timer.h>
81 #include <netinet/tcp_var.h>
82 
83 #ifdef INET6
84 #include <netinet/ip6.h>
85 #include <netinet/icmp6.h>
86 #include <netinet6/ip6_var.h>
87 #include <netinet6/udp6.h>
88 #include <netinet6/udp6_var.h>
89 #ifdef TCP6
90 #include <netinet6/tcp6.h>
91 #include <netinet6/tcp6_timer.h>
92 #include <netinet6/tcp6_var.h>
93 #endif
94 #include <netinet6/pim6_var.h>
95 #endif /* INET6 */
96 
97 #ifdef IPSEC
98 #include <net/route.h>
99 #include <netinet6/ipsec.h>
100 #include <netkey/key_var.h>
101 #endif /* IPSEC */
102 
103 #include <sys/pipe.h>
104 
105 #include <err.h>
106 #include <ctype.h>
107 #include <errno.h>
108 #include <stdio.h>
109 #include <stdlib.h>
110 #include <string.h>
111 #include <unistd.h>
112 #include <util.h>
113 
114 struct ctlname topname[] = CTL_NAMES;
115 struct ctlname kernname[] = CTL_KERN_NAMES;
116 struct ctlname vmname[] = CTL_VM_NAMES;
117 struct ctlname vfsname[] = CTL_VFS_NAMES;
118 struct ctlname netname[] = CTL_NET_NAMES;
119 struct ctlname hwname[] = CTL_HW_NAMES;
120 struct ctlname username[] = CTL_USER_NAMES;
121 struct ctlname ddbname[] = CTL_DDB_NAMES;
122 struct ctlname debugname[CTL_DEBUG_MAXID];
123 #ifdef CTL_MACHDEP_NAMES
124 struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
125 #endif
126 /* this one is dummy, it's used only for '-a' or '-A' */
127 struct ctlname procname[] = { {0, 0}, {"curproc", CTLTYPE_NODE} };
128 
129 char names[BUFSIZ];
130 
131 struct list {
132 	struct	ctlname *list;
133 	int	size;
134 };
135 struct list toplist = { topname, CTL_MAXID };
136 struct list secondlevel[] = {
137 	{ 0, 0 },			/* CTL_UNSPEC */
138 	{ kernname, KERN_MAXID },	/* CTL_KERN */
139 	{ vmname, VM_MAXID },		/* CTL_VM */
140 	{ vfsname, VFS_MAXID },		/* CTL_VFS */
141 	{ netname, NET_MAXID },		/* CTL_NET */
142 	{ 0, CTL_DEBUG_MAXID },		/* CTL_DEBUG */
143 	{ hwname, HW_MAXID },		/* CTL_HW */
144 #ifdef CTL_MACHDEP_NAMES
145 	{ machdepname, CPU_MAXID },	/* CTL_MACHDEP */
146 #else
147 	{ 0, 0 },			/* CTL_MACHDEP */
148 #endif
149 	{ username, USER_MAXID },	/* CTL_USER_NAMES */
150 	{ ddbname, DDBCTL_MAXID },	/* CTL_DDB_NAMES */
151 	{ procname, 2 },		/* dummy name */
152 	{ 0, 0},
153 };
154 
155 int	Aflag, aflag, nflag, wflag;
156 
157 /*
158  * Variables requiring special processing.
159  */
160 #define	CLOCK		0x00000001
161 #define	BOOTTIME	0x00000002
162 #define	CONSDEV		0x00000004
163 #define	DISKINFO	0x00000008
164 #define	CPTIME		0x00000010
165 
166 /*
167  * A dummy type for limits, which requires special parsing
168  */
169 #define CTLTYPE_LIMIT	((~0x1) << 31)
170 
171 int main __P((int, char *[]));
172 
173 static void listall __P((const char *, struct list *));
174 static void parse __P((char *, int));
175 static void debuginit __P((void));
176 static int sysctl_inet __P((char *, char **, int[], int, int *));
177 #ifdef INET6
178 static int sysctl_inet6 __P((char *, char **, int[], int, int *));
179 #endif
180 #ifdef IPSEC
181 static int sysctl_key __P((char *, char **, int[], int, int *));
182 #endif
183 static int sysctl_vfs __P((char *, char **, int[], int, int *));
184 static int sysctl_vfsgen __P((char *, char **, int[], int, int *));
185 static int sysctl_mbuf __P((char *, char **, int[], int, int *));
186 static int sysctl_pipe __P((char *, char **, int[], int, int *));
187 static int sysctl_proc __P((char *, char **, int[], int, int *));
188 static int findname __P((char *, char *, char **, struct list *));
189 static void usage __P((void));
190 
191 int
192 main(argc, argv)
193 	int argc;
194 	char *argv[];
195 {
196 	char *fn = NULL;
197 	int ch, lvl1;
198 
199 	while ((ch = getopt(argc, argv, "Aaf:nw")) != -1) {
200 		switch (ch) {
201 
202 		case 'A':
203 			Aflag = 1;
204 			break;
205 
206 		case 'a':
207 			aflag = 1;
208 			break;
209 
210 		case 'f':
211 			fn = optarg;
212 			wflag = 1;
213 			break;
214 
215 		case 'n':
216 			nflag = 1;
217 			break;
218 
219 		case 'w':
220 			wflag = 1;
221 			break;
222 
223 		default:
224 			usage();
225 		}
226 	}
227 	argc -= optind;
228 	argv += optind;
229 
230 	if (Aflag || aflag) {
231 		debuginit();
232 		for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
233 			listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
234 		return 0;
235 	}
236 
237 	if (fn) {
238 		FILE *fp;
239 		char *l;
240 
241 		fp = fopen(fn, "r");
242 		if (fp == NULL) {
243 			err(1, "%s", fn);
244 		} else {
245 			for (; (l = fparseln(fp, NULL, NULL, NULL, 0)) != NULL;
246 			    free(l)) {
247 				if (*l)
248 					parse(l, 1);
249 			}
250 			fclose(fp);
251 		}
252 	} else {
253 		if (argc == 0)
254 			usage();
255 		while (argc-- > 0)
256 			parse(*argv++, 1);
257 	}
258 	return 0;
259 }
260 
261 /*
262  * List all variables known to the system.
263  */
264 static void
265 listall(prefix, lp)
266 	const char *prefix;
267 	struct list *lp;
268 {
269 	int lvl2;
270 	char *cp, name[BUFSIZ];
271 
272 	if (lp->list == 0)
273 		return;
274 	strcpy(name, prefix);
275 	cp = &name[strlen(name)];
276 	*cp++ = '.';
277 	for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
278 		if (lp->list[lvl2].ctl_name == 0)
279 			continue;
280 		strcpy(cp, lp->list[lvl2].ctl_name);
281 		parse(name, Aflag);
282 	}
283 }
284 
285 /*
286  * Parse a name into a MIB entry.
287  * Lookup and print out the MIB entry if it exists.
288  * Set a new value if requested.
289  */
290 static void
291 parse(string, flags)
292 	char *string;
293 	int flags;
294 {
295 	int indx, type, state, len;
296 	int special = 0;
297 	void *newval = 0;
298 	int intval, newsize = 0;
299 	quad_t quadval;
300 	size_t size;
301 	struct list *lp;
302 	int mib[CTL_MAXNAME];
303 	char *cp, *bufp, buf[BUFSIZ];
304 	double loads[3];
305 
306 	bufp = buf;
307 	snprintf(buf, BUFSIZ, "%s", string);
308 	if ((cp = strchr(string, '=')) != NULL) {
309 		if (!wflag)
310 			errx(2, "Must specify -w to set variables");
311 		*strchr(buf, '=') = '\0';
312 		*cp++ = '\0';
313 		while (isspace((unsigned char) *cp))
314 			cp++;
315 		newval = cp;
316 		newsize = strlen(cp);
317 	}
318 	if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
319 		return;
320 	mib[0] = indx;
321 	if (indx == CTL_DEBUG)
322 		debuginit();
323 	if (mib[0] == CTL_PROC) {
324 		type = CTLTYPE_NODE;
325 		len = 1;
326 	} else {
327 		lp = &secondlevel[indx];
328 		if (lp->list == 0) {
329 			warnx("Class `%s' is not implemented",
330 			topname[indx].ctl_name);
331 			return;
332 		}
333 		if (bufp == NULL) {
334 			listall(topname[indx].ctl_name, lp);
335 			return;
336 		}
337 		if ((indx = findname(string, "second", &bufp, lp)) == -1)
338 			return;
339 		mib[1] = indx;
340 		type = lp->list[indx].ctl_type;
341 		len = 2;
342 	}
343 	switch (mib[0]) {
344 
345 	case CTL_KERN:
346 		switch (mib[1]) {
347 		case KERN_PROF:
348 			mib[2] = GPROF_STATE;
349 			size = sizeof state;
350 			if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
351 				if (flags == 0)
352 					return;
353 				if (!nflag)
354 					printf("%s: ", string);
355 				warnx("Kernel is not compiled for profiling");
356 				return;
357 			}
358 			if (!nflag)
359 				printf("%s: %s\n", string,
360 				    state == GMON_PROF_OFF ? "off" : "running");
361 			return;
362 		case KERN_VNODE:
363 		case KERN_FILE:
364 			if (flags == 0)
365 				return;
366 			warnx("Use pstat to view %s information", string);
367 			return;
368 		case KERN_PROC:
369 		case KERN_PROC2:
370 		case KERN_PROC_ARGS:
371 			if (flags == 0)
372 				return;
373 			warnx("Use ps to view %s information", string);
374 			return;
375 		case KERN_CLOCKRATE:
376 			special |= CLOCK;
377 			break;
378 		case KERN_BOOTTIME:
379 			special |= BOOTTIME;
380 			break;
381 		case KERN_NTPTIME:
382 			if (flags == 0)
383 				return;
384 			warnx("Use ntpdc -c kerninfo to view %s information",
385 			    string);
386 			return;
387 		case KERN_MBUF:
388 			len = sysctl_mbuf(string, &bufp, mib, flags, &type);
389 			if (len < 0)
390 				return;
391 			break;
392 		case KERN_CP_TIME:
393 			special |= CPTIME;
394 			break;
395 		case KERN_MSGBUF:
396 			if (flags == 0)
397 				return;
398 			warnx("Use dmesg to view %s information", string);
399 			return;
400 		case KERN_CONSDEV:
401 			special |= CONSDEV;
402 			break;
403 		case KERN_PIPE:
404 			len = sysctl_pipe(string, &bufp, mib, flags, &type);
405 			if (len < 0)
406 				return;
407 			break;
408 		}
409 		break;
410 
411 	case CTL_HW:
412 		break;
413 
414 	case CTL_VM:
415 		switch (mib[1]) {
416 		case VM_LOADAVG:
417 			getloadavg(loads, 3);
418 			if (!nflag)
419 				printf("%s: ", string);
420 			printf("%.2f %.2f %.2f\n", loads[0], loads[1],
421 			    loads[2]);
422 			return;
423 
424 		case VM_METER:
425 		case VM_UVMEXP:
426 		case VM_UVMEXP2:
427 			if (flags) {
428 				warnx("Use vmstat or systat to view %s"
429 				    "information", string);
430 			}
431 			return;
432 		}
433 		break;
434 
435 	case CTL_NET:
436 		if (mib[1] == PF_INET) {
437 			len = sysctl_inet(string, &bufp, mib, flags, &type);
438 			if (len >= 0)
439 				break;
440 			return;
441 		}
442 #ifdef INET6
443 		else if (mib[1] == PF_INET6) {
444 			len = sysctl_inet6(string, &bufp, mib, flags, &type);
445 			if (len >= 0)
446 				break;
447 			return;
448 		}
449 #endif /* INET6 */
450 #ifdef IPSEC
451 		else if (mib[1] == PF_KEY) {
452 			len = sysctl_key(string, &bufp, mib, flags, &type);
453 			if (len >= 0)
454 				break;
455 			return;
456 		}
457 #endif /* IPSEC */
458 		if (flags == 0)
459 			return;
460 		warnx("Use netstat to view %s information", string);
461 		return;
462 
463 	case CTL_DEBUG:
464 		mib[2] = CTL_DEBUG_VALUE;
465 		len = 3;
466 		break;
467 
468 	case CTL_MACHDEP:
469 #ifdef CPU_CONSDEV
470 		if (mib[1] == CPU_CONSDEV)
471 			special |= CONSDEV;
472 #endif
473 #ifdef CPU_DISKINFO
474 		if (mib[1] == CPU_DISKINFO)
475 			special |= DISKINFO;
476 #endif
477 		break;
478 
479 	case CTL_VFS:
480 		if (mib[1] == VFS_GENERIC)
481 			len = sysctl_vfsgen(string, &bufp, mib, flags, &type);
482 		else
483 			len = sysctl_vfs(string, &bufp, mib, flags, &type);
484 		if (len < 0)
485 			return;
486 
487 		/* XXX Special-case for NFS stats. */
488 		if (mib[1] == 2 && mib[2] == NFS_NFSSTATS) {
489 			if (flags == 0)
490 				return;
491 			warnx("Use nfsstat to view %s information", string);
492 			return;
493 		}
494 		break;
495 
496 	case CTL_VENDOR:
497 	case CTL_USER:
498 	case CTL_DDB:
499 		break;
500 	case CTL_PROC:
501 		len = sysctl_proc(string, &bufp, mib, flags, &type);
502 		if (len < 0)
503 			return;
504 		break;
505 	default:
506 		warnx("Illegal top level value: %d", mib[0]);
507 		return;
508 
509 	}
510 	if (bufp) {
511 		warnx("Name %s in %s is unknown", bufp, string);
512 		return;
513 	}
514 	if (newsize > 0) {
515 		switch (type) {
516 		case CTLTYPE_INT:
517 			intval = atoi(newval);
518 			newval = &intval;
519 			newsize = sizeof intval;
520 			break;
521 
522 		case CTLTYPE_LIMIT:
523 			if (strcmp(newval, "unlimited") == 0) {
524 				quadval = RLIM_INFINITY;
525 				newval = &quadval;
526 				newsize = sizeof quadval;
527 				break;
528 			}
529 			/* FALLTHROUGH */
530 		case CTLTYPE_QUAD:
531 			sscanf(newval, "%lld", (long long *)&quadval);
532 			newval = &quadval;
533 			newsize = sizeof quadval;
534 			break;
535 		}
536 	}
537 	size = BUFSIZ;
538 	if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
539 		if (flags == 0)
540 			return;
541 		switch (errno) {
542 		case EOPNOTSUPP:
543 			warnx("The value of %s is not available", string);
544 			return;
545 		case ENOTDIR:
546 			warnx("The specification of %s is incomplete",
547 			    string);
548 			return;
549 		case ENOMEM:
550 			warnx("The type %s is unknown to this program",
551 			    string);
552 			return;
553 		default:
554 			warn("sysctl() for %s failed", string);
555 			return;
556 		}
557 	}
558 	if (special & CLOCK) {
559 		struct clockinfo *clkp = (struct clockinfo *)buf;
560 
561 		if (!nflag)
562 			printf("%s: ", string);
563 		printf(
564 		    "tick = %d, tickadj = %d, hz = %d, profhz = %d, stathz = %d\n",
565 		    clkp->tick, clkp->tickadj, clkp->hz, clkp->profhz, clkp->stathz);
566 		return;
567 	}
568 	if (special & BOOTTIME) {
569 		struct timeval *btp = (struct timeval *)buf;
570 		time_t boottime;
571 
572 		if (!nflag) {
573 			boottime = btp->tv_sec;
574 			/* ctime() provides the trailing newline */
575 			printf("%s = %s", string, ctime(&boottime));
576 		} else
577 			printf("%ld\n", (long) btp->tv_sec);
578 		return;
579 	}
580 	if (special & CONSDEV) {
581 		dev_t dev = *(dev_t *)buf;
582 
583 		if (!nflag)
584 			printf("%s = %s\n", string, devname(dev, S_IFCHR));
585 		else
586 			printf("0x%x\n", dev);
587 		return;
588 	}
589 	if (special & DISKINFO) {
590 		/* Don't know a good way to deal with this i386 specific one */
591 		return;
592 	}
593 	if (special & CPTIME) {
594 		u_int64_t *cp_time = (u_int64_t *)buf;
595 
596 		if (!nflag)
597 			printf("%s: ", string);
598 		printf("user = %llu, nice = %llu, sys = %llu, intr = %llu, "
599 		    "idle = %llu\n", (unsigned long long) cp_time[0],
600 		    (unsigned long long) cp_time[1],
601 		    (unsigned long long) cp_time[2],
602 		    (unsigned long long) cp_time[3],
603 		    (unsigned long long) cp_time[4]);
604 		return;
605 	}
606 
607 	switch (type) {
608 	case CTLTYPE_INT:
609 		if (newsize == 0) {
610 			if (!nflag)
611 				printf("%s = ", string);
612 			printf("%d\n", *(int *)buf);
613 		} else {
614 			if (!nflag)
615 				printf("%s: %d -> ", string, *(int *)buf);
616 			printf("%d\n", *(int *)newval);
617 		}
618 		return;
619 
620 	case CTLTYPE_STRING:
621 		if (newsize == 0) {
622 			if (!nflag)
623 				printf("%s = ", string);
624 			printf("%s\n", buf);
625 		} else {
626 			if (!nflag)
627 				printf("%s: %s -> ", string, buf);
628 			printf("%s\n", (char *) newval);
629 		}
630 		return;
631 
632 	case CTLTYPE_LIMIT:
633 #define PRINTF_LIMIT(lim) { \
634 if ((lim) == RLIM_INFINITY) \
635 	printf("unlimited");\
636 else \
637 	printf("%lld", (long long)(lim)); \
638 }
639 
640 		if (newsize == 0) {
641 			if (!nflag)
642 				printf("%s = ", string);
643 			PRINTF_LIMIT((long long)(*(quad_t *)buf));
644 		} else {
645 			if (!nflag) {
646 				printf("%s: ", string);
647 				PRINTF_LIMIT((long long)(*(quad_t *)buf));
648 				printf(" -> ");
649 			}
650 			PRINTF_LIMIT((long long)(*(quad_t *)newval));
651 		}
652 		printf("\n");
653 		return;
654 #undef PRINTF_LIMIT
655 
656 	case CTLTYPE_QUAD:
657 		if (newsize == 0) {
658 			if (!nflag)
659 				printf("%s = ", string);
660 			printf("%lld\n", (long long)(*(quad_t *)buf));
661 		} else {
662 			if (!nflag)
663 				printf("%s: %lld -> ", string,
664 				    (long long)(*(quad_t *)buf));
665 			printf("%lld\n", (long long)(*(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 /*
681  * Initialize the set of debugging names
682  */
683 static void
684 debuginit()
685 {
686 	int mib[3], loc, i;
687 	size_t size;
688 
689 	if (secondlevel[CTL_DEBUG].list != 0)
690 		return;
691 	secondlevel[CTL_DEBUG].list = debugname;
692 	mib[0] = CTL_DEBUG;
693 	mib[2] = CTL_DEBUG_NAME;
694 	for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
695 		mib[1] = i;
696 		size = BUFSIZ - loc;
697 		if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
698 			continue;
699 		debugname[i].ctl_name = &names[loc];
700 		debugname[i].ctl_type = CTLTYPE_INT;
701 		loc += size;
702 	}
703 }
704 
705 struct ctlname inetname[] = CTL_IPPROTO_NAMES;
706 struct ctlname ipname[] = IPCTL_NAMES;
707 struct ctlname icmpname[] = ICMPCTL_NAMES;
708 struct ctlname tcpname[] = TCPCTL_NAMES;
709 struct ctlname udpname[] = UDPCTL_NAMES;
710 #ifdef IPSEC
711 struct ctlname ipsecname[] = IPSECCTL_NAMES;
712 #endif
713 struct list inetlist = { inetname, IPPROTO_MAXID };
714 struct list inetvars[] = {
715 /*0*/	{ ipname, IPCTL_MAXID },	/* ip */
716 	{ icmpname, ICMPCTL_MAXID },	/* icmp */
717 	{ 0, 0 },			/* igmp */
718 	{ 0, 0 },			/* ggmp */
719 	{ 0, 0 },
720 	{ 0, 0 },
721 	{ tcpname, TCPCTL_MAXID },	/* tcp */
722 	{ 0, 0 },
723 	{ 0, 0 },			/* egp */
724 	{ 0, 0 },
725 /*10*/	{ 0, 0 },
726 	{ 0, 0 },
727 	{ 0, 0 },			/* pup */
728 	{ 0, 0 },
729 	{ 0, 0 },
730 	{ 0, 0 },
731 	{ 0, 0 },
732 	{ udpname, UDPCTL_MAXID },	/* udp */
733 	{ 0, 0 },
734 	{ 0, 0 },
735 /*20*/	{ 0, 0 },
736 	{ 0, 0 },
737 	{ 0, 0 },			/* idp */
738 	{ 0, 0 },
739 	{ 0, 0 },
740 	{ 0, 0 },
741 	{ 0, 0 },
742 	{ 0, 0 },
743 	{ 0, 0 },
744 	{ 0, 0 },
745 /*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
746 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
747 /*40*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
748 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
749 #ifdef IPSEC
750 	{ ipsecname, IPSECCTL_MAXID },	/* esp - for backward compatibility */
751 	{ ipsecname, IPSECCTL_MAXID },	/* ah */
752 #else
753 	{ 0, 0 },
754 	{ 0, 0 },
755 #endif
756 };
757 
758 /*
759  * handle internet requests
760  */
761 static int
762 sysctl_inet(string, bufpp, mib, flags, typep)
763 	char *string;
764 	char **bufpp;
765 	int mib[];
766 	int flags;
767 	int *typep;
768 {
769 	struct list *lp;
770 	int indx;
771 
772 	if (*bufpp == NULL) {
773 		listall(string, &inetlist);
774 		return (-1);
775 	}
776 	if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
777 		return (-1);
778 	mib[2] = indx;
779 	if (indx <= IPPROTO_MAXID && inetvars[indx].list != NULL)
780 		lp = &inetvars[indx];
781 	else if (!flags)
782 		return (-1);
783 	else {
784 		warnx("No variables defined for protocol %s", string);
785 		return (-1);
786 	}
787 	if (*bufpp == NULL) {
788 		listall(string, lp);
789 		return (-1);
790 	}
791 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
792 		return (-1);
793 	mib[3] = indx;
794 	*typep = lp->list[indx].ctl_type;
795 	return (4);
796 }
797 
798 #ifdef INET6
799 struct ctlname inet6name[] = CTL_IPV6PROTO_NAMES;
800 struct ctlname ip6name[] = IPV6CTL_NAMES;
801 struct ctlname icmp6name[] = ICMPV6CTL_NAMES;
802 struct ctlname udp6name[] = UDP6CTL_NAMES;
803 struct ctlname pim6name[] = PIM6CTL_NAMES;
804 struct ctlname ipsec6name[] = IPSEC6CTL_NAMES;
805 struct list inet6list = { inet6name, IPV6PROTO_MAXID };
806 struct list inet6vars[] = {
807 /*0*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
808 	{ 0, 0 },
809 	{ tcpname, TCPCTL_MAXID },	/* tcp6 */
810 	{ 0, 0 },
811 	{ 0, 0 },
812 	{ 0, 0 },
813 /*10*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
814 	{ 0, 0 },
815 	{ 0, 0 },
816 	{ udp6name, UDP6CTL_MAXID },	/* udp6 */
817 	{ 0, 0 },
818 	{ 0, 0 },
819 /*20*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
820 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
821 /*30*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
822 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
823 /*40*/	{ 0, 0 },
824 	{ ip6name, IPV6CTL_MAXID },	/* ipv6 */
825 	{ 0, 0 },
826 	{ 0, 0 },
827 	{ 0, 0 },
828 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
829 #ifdef IPSEC
830 /*50*/	{ ipsec6name, IPSECCTL_MAXID },	/* esp6 - for backward compatibility */
831 	{ ipsec6name, IPSECCTL_MAXID },	/* ah6 */
832 #else
833 	{ 0, 0 },
834 	{ 0, 0 },
835 #endif
836 	{ 0, 0 },
837 	{ 0, 0 },
838 	{ 0, 0 },
839 	{ 0, 0 },
840 	{ 0, 0 },
841 	{ 0, 0 },
842 	{ icmp6name, ICMPV6CTL_MAXID },	/* icmp6 */
843 	{ 0, 0 },
844 /*60*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
845 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
846 /*70*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
847 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
848 /*80*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
849 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
850 /*90*/	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
851 	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
852 /*100*/	{ 0, 0 },
853 	{ 0, 0 },
854 	{ 0, 0 },
855 	{ pim6name, PIM6CTL_MAXID },	/* pim6 */
856 };
857 
858 /*
859  * handle internet6 requests
860  */
861 static int
862 sysctl_inet6(string, bufpp, mib, flags, typep)
863 	char *string;
864 	char **bufpp;
865 	int mib[];
866 	int flags;
867 	int *typep;
868 {
869 	struct list *lp;
870 	int indx;
871 
872 	if (*bufpp == NULL) {
873 		listall(string, &inet6list);
874 		return (-1);
875 	}
876 	if ((indx = findname(string, "third", bufpp, &inet6list)) == -1)
877 		return (-1);
878 	mib[2] = indx;
879 	if (indx <= sizeof(inet6vars)/sizeof(inet6vars[0])
880 	 && inet6vars[indx].list != NULL) {
881 		lp = &inet6vars[indx];
882 	} else if (!flags) {
883 		return (-1);
884 	} else {
885 		fprintf(stderr, "%s: no variables defined for this protocol\n",
886 		    string);
887 		return (-1);
888 	}
889 	if (*bufpp == NULL) {
890 		listall(string, lp);
891 		return (-1);
892 	}
893 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
894 		return (-1);
895 	mib[3] = indx;
896 	*typep = lp->list[indx].ctl_type;
897 	return (4);
898 }
899 #endif /* INET6 */
900 
901 #ifdef IPSEC
902 struct ctlname keynames[] = KEYCTL_NAMES;
903 struct list keylist = { keynames, KEYCTL_MAXID };
904 
905 /*
906  * handle key requests
907  */
908 static int
909 sysctl_key(string, bufpp, mib, flags, typep)
910 	char *string;
911 	char **bufpp;
912 	int mib[];
913 	int flags;
914 	int *typep;
915 {
916 	struct list *lp;
917 	int indx;
918 
919 	if (*bufpp == NULL) {
920 		listall(string, &keylist);
921 		return (-1);
922 	}
923 	if ((indx = findname(string, "third", bufpp, &keylist)) == -1)
924 		return (-1);
925 	mib[2] = indx;
926 	lp = &keylist;
927 	*typep = lp->list[indx].ctl_type;
928 	return 3;
929 }
930 #endif /*IPSEC*/
931 
932 struct ctlname ffsname[] = FFS_NAMES;
933 struct ctlname nfsname[] = NFS_NAMES;
934 struct list vfsvars[] = {
935 	{ 0, 0 },			/* generic */
936 	{ ffsname, FFS_MAXID },		/* FFS */
937 	{ nfsname, NFS_MAXID },		/* NFS */
938 	{ 0, 0 },			/* MFS */
939 	{ 0, 0 },			/* MSDOS */
940 	{ 0, 0 },			/* LFS */
941 	{ 0, 0 },			/* old LOFS */
942 	{ 0, 0 },			/* FDESC */
943 	{ 0, 0 },			/* PORTAL */
944 	{ 0, 0 },			/* NULL */
945 	{ 0, 0 },			/* UMAP */
946 	{ 0, 0 },			/* KERNFS */
947 	{ 0, 0 },			/* PROCFS */
948 	{ 0, 0 },			/* AFS */
949 	{ 0, 0 },			/* CD9660 */
950 	{ 0, 0 },			/* UNION */
951 	{ 0, 0 },			/* ADOSFS */
952 	{ 0, 0 },			/* EXT2FS */
953 	{ 0, 0 },			/* CODA */
954 	{ 0, 0 },			/* FILECORE */
955 };
956 
957 /*
958  * handle vfs requests
959  */
960 static int
961 sysctl_vfs(string, bufpp, mib, flags, typep)
962 	char *string;
963 	char **bufpp;
964 	int mib[];
965 	int flags;
966 	int *typep;
967 {
968 	struct list *lp = &vfsvars[mib[1]];
969 	int indx;
970 
971 	if (lp->list == NULL) {
972 		if (flags)
973 			warnx("No variables defined for file system %s",
974 			    string);
975 		return (-1);
976 	}
977 	if (*bufpp == NULL) {
978 		listall(string, lp);
979 		return (-1);
980 	}
981 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
982 		return (-1);
983 	mib[2] = indx;
984 	*typep = lp->list[indx].ctl_type;
985 	return (3);
986 }
987 
988 struct ctlname vfsgenname[] = CTL_VFSGENCTL_NAMES;
989 struct list vfsgenvars = { vfsgenname, VFSGEN_MAXID };
990 
991 /*
992  * handle vfs.generic requests
993  */
994 static int
995 sysctl_vfsgen(string, bufpp, mib, flags, typep)
996 	char *string;
997 	char **bufpp;
998 	int mib[];
999 	int flags;
1000 	int *typep;
1001 {
1002 	struct list *lp = &vfsgenvars;
1003 	int indx;
1004 
1005 	if (*bufpp == NULL) {
1006 		listall(string, lp);
1007 		return (-1);
1008 	}
1009 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1010 		return (-1);
1011 	/* Don't bother with VFS_CONF. */
1012 	if (indx == VFS_CONF)
1013 		return (-1);
1014 	mib[2] = indx;
1015 	*typep = lp->list[indx].ctl_type;
1016 	return (3);
1017 }
1018 
1019 struct ctlname procnames[] = PROC_PID_NAMES;
1020 struct list procvars = {procnames, PROC_PID_MAXID};
1021 struct ctlname proclimitnames[] = PROC_PID_LIMIT_NAMES;
1022 struct list proclimitvars = {proclimitnames, PROC_PID_LIMIT_MAXID};
1023 struct ctlname proclimittypenames[] = PROC_PID_LIMIT_TYPE_NAMES;
1024 struct list proclimittypevars = {proclimittypenames,
1025     PROC_PID_LIMIT_TYPE_MAXID};
1026 /*
1027  * handle kern.proc requests
1028  */
1029 static int
1030 sysctl_proc(string, bufpp, mib, flags, typep)
1031 	char *string;
1032 	char **bufpp;
1033 	int mib[];
1034 	int flags;
1035 	int *typep;
1036 {
1037 	char *cp, name[BUFSIZ];
1038 	struct list *lp;
1039 	int indx;
1040 
1041 	if (*bufpp == NULL) {
1042 		strcpy(name, string);
1043 		cp = &name[strlen(name)];
1044 		*cp++ = '.';
1045 		strcpy(cp, "curproc");
1046 		parse(name, Aflag);
1047 		return (-1);
1048 	}
1049 	cp = strsep(bufpp, ".");
1050 	if (cp == NULL) {
1051 		warnx("%s: incomplete specification", string);
1052 		return (-1);
1053 	}
1054 	if (strcmp(cp, "curproc") == 0) {
1055 		mib[1] = PROC_CURPROC;
1056 	} else {
1057 		mib[1] = atoi(cp);
1058 		if (mib[1] == 0) {
1059 			warnx("second level name %s in %s is invalid", cp,
1060 			    string);
1061 			return (-1);
1062 		}
1063 	}
1064 	*typep = CTLTYPE_NODE;
1065 	lp = &procvars;
1066 	if (*bufpp == NULL) {
1067 		listall(string, lp);
1068 		return (-1);
1069 	}
1070 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1071 		return (-1);
1072 	mib[2] = indx;
1073 	*typep = lp->list[indx].ctl_type;
1074 	if (*typep != CTLTYPE_NODE)
1075 		return(3);
1076 	lp = &proclimitvars;
1077 	if (*bufpp == NULL) {
1078 		listall(string, lp);
1079 		return (-1);
1080 	}
1081 	if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
1082 		return (-1);
1083 	mib[3] = indx;
1084 	lp = &proclimittypevars;
1085 	if (*bufpp == NULL) {
1086 		listall(string, lp);
1087 		return (-1);
1088 	}
1089 	if ((indx = findname(string, "fifth", bufpp, lp)) == -1)
1090 		return (-1);
1091 	mib[4] = indx;
1092 	*typep = CTLTYPE_LIMIT;
1093 	return(5);
1094 }
1095 
1096 struct ctlname mbufnames[] = CTL_MBUF_NAMES;
1097 struct list mbufvars = { mbufnames, MBUF_MAXID };
1098 /*
1099  * handle kern.mbuf requests
1100  */
1101 static int
1102 sysctl_mbuf(string, bufpp, mib, flags, typep)
1103 	char *string;
1104 	char **bufpp;
1105 	int mib[];
1106 	int flags;
1107 	int *typep;
1108 {
1109 	struct list *lp = &mbufvars;
1110 	int indx;
1111 
1112 	if (*bufpp == NULL) {
1113 		listall(string, lp);
1114 		return (-1);
1115 	}
1116 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1117 		return (-1);
1118 	mib[2] = indx;
1119 	*typep = lp->list[indx].ctl_type;
1120 	return (3);
1121 }
1122 
1123 struct ctlname pipenames[] = CTL_PIPE_NAMES;
1124 struct list pipevars = { pipenames, KERN_PIPE_MAXID };
1125 /*
1126  * handle kern.mbuf requests
1127  */
1128 static int
1129 sysctl_pipe(string, bufpp, mib, flags, typep)
1130 	char *string;
1131 	char **bufpp;
1132 	int mib[];
1133 	int flags;
1134 	int *typep;
1135 {
1136 	struct list *lp = &pipevars;
1137 	int indx;
1138 
1139 	if (*bufpp == NULL) {
1140 		listall(string, lp);
1141 		return (-1);
1142 	}
1143 	if ((indx = findname(string, "third", bufpp, lp)) == -1)
1144 		return (-1);
1145 	mib[2] = indx;
1146 	*typep = lp->list[indx].ctl_type;
1147 	return (3);
1148 }
1149 
1150 /*
1151  * Scan a list of names searching for a particular name.
1152  */
1153 static int
1154 findname(string, level, bufp, namelist)
1155 	char *string;
1156 	char *level;
1157 	char **bufp;
1158 	struct list *namelist;
1159 {
1160 	char *name;
1161 	int i;
1162 
1163 	if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
1164 		warnx("%s: incomplete specification", string);
1165 		return (-1);
1166 	}
1167 	for (i = 0; i < namelist->size; i++)
1168 		if (namelist->list[i].ctl_name != NULL &&
1169 		    strcmp(name, namelist->list[i].ctl_name) == 0)
1170 			break;
1171 	if (i == namelist->size) {
1172 		warnx("%s level name %s in %s is invalid",
1173 		    level, name, string);
1174 		return (-1);
1175 	}
1176 	return (i);
1177 }
1178 
1179 static void
1180 usage()
1181 {
1182 	const char *progname = getprogname();
1183 
1184 	(void)fprintf(stderr, "Usage:\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n",
1185 	    progname, "[-n] variable ...",
1186 	    progname, "[-n] -w variable=value ...",
1187 	    progname, "[-n] -a",
1188 	    progname, "[-n] -A",
1189 	    progname, "[-n] -f file");
1190 	exit(1);
1191 }
1192