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