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