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