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