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