1: /* 2: * Copyright (c) 1993 3: * The Regents of the University of California. All rights reserved. 4: * 5: * Redistribution and use in source and binary forms, with or without 6: * modification, are permitted provided that the following conditions 7: * are met: 8: * 1. Redistributions of source code must retain the above copyright 9: * notice, this list of conditions and the following disclaimer. 10: * 2. Redistributions in binary form must reproduce the above copyright 11: * notice, this list of conditions and the following disclaimer in the 12: * documentation and/or other materials provided with the distribution. 13: * 3. All advertising materials mentioning features or use of this software 14: * must display the following acknowledgement: 15: * This product includes software developed by the University of 16: * California, Berkeley and its contributors. 17: * 4. Neither the name of the University nor the names of its contributors 18: * may be used to endorse or promote products derived from this software 19: * without specific prior written permission. 20: * 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31: * SUCH DAMAGE. 32: */ 33: 34: #if !defined(lint) && defined(DOSCCS) 35: static char copyright[] = 36: "@(#) Copyright (c) 1993\n\ 37: The Regents of the University of California. All rights reserved.\n"; 38: 39: static char sccsid[] = "@(#)sysctl.c 8.1.4 (2.11BSD GTE) 1998/4/3"; 40: #endif /* not lint */ 41: 42: #include <sys/param.h> 43: #include <sys/stat.h> 44: #include <sys/sysctl.h> 45: #include <sys/socket.h> 46: #include <machine/cpu.h> 47: 48: #include <netinet/in.h> 49: #include <netinet/in_systm.h> 50: #include <netinet/ip.h> 51: #include <netinet/ip_icmp.h> 52: #include <netinet/icmp_var.h> 53: #include <netinet/ip_var.h> 54: #include <netinet/udp.h> 55: #include <netinet/udp_var.h> 56: 57: #include <errno.h> 58: #include <stdio.h> 59: #include <string.h> 60: #include <ctype.h> 61: 62: struct ctlname topname[] = CTL_NAMES; 63: struct ctlname kernname[] = CTL_KERN_NAMES; 64: struct ctlname vmname[] = CTL_VM_NAMES; 65: #ifdef CTL_NET_NAMES 66: struct ctlname netname[] = CTL_NET_NAMES; 67: #endif 68: struct ctlname hwname[] = CTL_HW_NAMES; 69: struct ctlname username[] = CTL_USER_NAMES; 70: struct ctlname debugname[CTL_DEBUG_MAXID]; 71: struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 72: char names[BUFSIZ]; 73: 74: struct list { 75: struct ctlname *list; 76: int size; 77: }; 78: struct list toplist = { topname, CTL_MAXID }; 79: struct list secondlevel[] = { 80: { 0, 0 }, /* CTL_UNSPEC */ 81: { kernname, KERN_MAXID }, /* CTL_KERN */ 82: { vmname, VM_MAXID }, /* CTL_VM */ 83: { 0, 0 }, /* CTL_FS */ 84: #ifdef CTL_NET_NAMES 85: { netname, NET_MAXID }, /* CTL_NET */ 86: #else 87: { 0, 0 }, 88: #endif 89: { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 90: { hwname, HW_MAXID }, /* CTL_HW */ 91: { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 92: { username, USER_MAXID }, /* CTL_USER_NAMES */ 93: }; 94: 95: int Aflag, aflag, nflag, wflag; 96: 97: extern char *optarg; 98: extern int optind, errno; 99: 100: /* 101: * Variables requiring special processing. 102: */ 103: #define CLOCK 0x0001 104: #define BOOTTIME 0x0002 105: #define CONSDEV 0x0004 106: 107: int 108: main(argc, argv) 109: int argc; 110: char *argv[]; 111: { 112: int ch, lvl1; 113: 114: while ((ch = getopt(argc, argv, "Aanw")) != EOF) { 115: switch (ch) { 116: 117: case 'A': 118: Aflag = 1; 119: break; 120: 121: case 'a': 122: aflag = 1; 123: break; 124: 125: case 'n': 126: nflag = 1; 127: break; 128: 129: case 'w': 130: wflag = 1; 131: break; 132: 133: default: 134: usage(); 135: } 136: } 137: argc -= optind; 138: argv += optind; 139: 140: if (Aflag || aflag) { 141: debuginit(); 142: for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 143: listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 144: exit(0); 145: } 146: if (argc == 0) 147: usage(); 148: while (argc-- > 0) 149: parse(*argv, 1); 150: exit(0); 151: } 152: 153: /* 154: * List all variables known to the system. 155: */ 156: listall(prefix, lp) 157: char *prefix; 158: struct list *lp; 159: { 160: int lvl2; 161: char *cp, name[BUFSIZ]; 162: 163: if (lp->list == 0) 164: return; 165: strcpy(name, prefix); 166: cp = &name[strlen(name)]; 167: *cp++ = '.'; 168: for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 169: if (lp->list[lvl2].ctl_name == 0) 170: continue; 171: strcpy(cp, lp->list[lvl2].ctl_name); 172: parse(name, Aflag); 173: } 174: } 175: 176: /* 177: * Parse a name into a MIB entry. 178: * Lookup and print out the MIB entry if it exists. 179: * Set a new value if requested. 180: */ 181: parse(string, flags) 182: char *string; 183: int flags; 184: { 185: int indx, type, state, size, len; 186: int special = 0; 187: void *newval = (void *)0; 188: int intval, newsize = 0; 189: long longval; 190: struct list *lp; 191: int mib[CTL_MAXNAME]; 192: char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 193: 194: bufp = buf; 195: strcpy(buf, string); 196: if ((cp = strchr(string, '=')) != NULL) { 197: if (!wflag) { 198: fprintf(stderr, "Must specify -w to set variables\n"); 199: exit(2); 200: } 201: *strchr(buf, '=') = '\0'; 202: *cp++ = '\0'; 203: while (isspace(*cp)) 204: cp++; 205: newval = (void *)cp; 206: newsize = strlen(cp); 207: } 208: if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 209: return; 210: mib[0] = indx; 211: if (indx == CTL_DEBUG) 212: debuginit(); 213: lp = &secondlevel[indx]; 214: if (lp->list == 0) { 215: fprintf(stderr, "%s: class is not implemented\n", 216: topname[indx]); 217: return; 218: } 219: if (bufp == NULL) { 220: listall(topname[indx].ctl_name, lp); 221: return; 222: } 223: if ((indx = findname(string, "second", &bufp, lp)) == -1) 224: return; 225: mib[1] = indx; 226: type = lp->list[indx].ctl_type; 227: len = 2; 228: switch (mib[0]) { 229: 230: case CTL_KERN: 231: switch (mib[1]) { 232: case KERN_PROF: 233: fprintf(stderr, 234: "kern.prof = not supported in 2.11BSD\n"); 235: return; 236: case KERN_INODE: 237: case KERN_FILE: 238: case KERN_TEXT: 239: if (flags == 0) 240: return; 241: fprintf(stderr, 242: "Use pstat to view %s information\n", string); 243: return; 244: case KERN_PROC: 245: if (flags == 0) 246: return; 247: fprintf(stderr, 248: "Use ps to view %s information\n", string); 249: return; 250: case KERN_CLOCKRATE: 251: special |= CLOCK; 252: break; 253: case KERN_BOOTTIME: 254: special |= BOOTTIME; 255: break; 256: } 257: break; 258: 259: case CTL_HW: 260: break; 261: 262: case CTL_VM: 263: if (mib[1] == VM_LOADAVG) { 264: double loads[3]; 265: 266: getloadavg(loads, 3); 267: if (!nflag) 268: fprintf(stdout, "%s: ", string); 269: fprintf(stdout, "%.2f %.2f %.2f\n", 270: loads[0], loads[1], loads[2]); 271: return; 272: } 273: if (flags == 0) 274: return; 275: fprintf(stderr, 276: "Use vmstat or pstat to view %s information\n", string); 277: return; 278: 279: case CTL_NET: 280: if (mib[1] == PF_INET) { 281: len = sysctl_inet(string, &bufp, mib, flags, &type); 282: if (len >= 0) 283: break; 284: return; 285: } 286: if (flags == 0) 287: return; 288: fprintf(stderr, "Use netstat to view %s information\n", string); 289: return; 290: 291: case CTL_DEBUG: 292: mib[2] = CTL_DEBUG_VALUE; 293: len = 3; 294: break; 295: 296: case CTL_MACHDEP: 297: if (mib[1] == CPU_CONSDEV) 298: special |= CONSDEV; 299: if (mib[1] == CPU_TMSCP) { 300: len = sysctl_tmscp(string, &bufp, mib, flags, &type); 301: if (len >= 0) 302: goto doit; 303: return; 304: } 305: if (mib[1] == CPU_MSCP) { 306: len = sysctl_mscp(string, &bufp, mib, flags, &type); 307: if (len >= 0) 308: goto doit; 309: return; 310: } 311: break; 312: 313: case CTL_FS: 314: case CTL_USER: 315: break; 316: 317: default: 318: fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 319: return; 320: 321: } 322: doit: 323: if (bufp) { 324: fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); 325: return; 326: } 327: if (newsize > 0) { 328: switch (type) { 329: case CTLTYPE_INT: 330: intval = atoi(newval); 331: newval = (void *)&intval; 332: newsize = sizeof intval; 333: break; 334: 335: case CTLTYPE_LONG: 336: sscanf(newval, "%ld", &longval); 337: newval = (void *)&longval; 338: newsize = sizeof longval; 339: break; 340: } 341: } 342: size = BUFSIZ; 343: if (sysctl(mib, len, buf, &size, newsize ? newval : (void *)0, newsize) == -1) { 344: if (flags == 0) 345: return; 346: switch (errno) { 347: case EOPNOTSUPP: 348: fprintf(stderr, "%s: value is not available\n", string); 349: return; 350: case ENOTDIR: 351: fprintf(stderr, "%s: specification is incomplete\n", 352: string); 353: return; 354: case ENOMEM: 355: fprintf(stderr, "%s: type is unknown to this program\n", 356: string); 357: return; 358: default: 359: perror(string); 360: return; 361: } 362: } 363: if (special & CLOCK) { 364: struct clockinfo *clkp = (struct clockinfo *)buf; 365: 366: if (!nflag) 367: fprintf(stdout, "%s: ", string); 368: fprintf(stdout, 369: "hz = %d, tick = %d, profhz = %d, stathz = %d\n", 370: clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); 371: return; 372: } 373: if (special & BOOTTIME) { 374: struct timeval *btp = (struct timeval *)buf; 375: 376: if (!nflag) 377: fprintf(stdout, "%s = %s", string, 378: ctime(&btp->tv_sec)); 379: else 380: fprintf(stdout, "%d\n", btp->tv_sec); 381: return; 382: } 383: if (special & CONSDEV) { 384: dev_t dev = *(dev_t *)buf; 385: 386: if (!nflag) 387: fprintf(stdout, "%s = %s\n", string, 388: devname(dev, S_IFCHR)); 389: else 390: fprintf(stdout, "0x%x\n", dev); 391: return; 392: } 393: switch (type) { 394: case CTLTYPE_INT: 395: if (newsize == 0) { 396: if (!nflag) 397: fprintf(stdout, "%s = ", string); 398: fprintf(stdout, "%d\n", *(int *)buf); 399: } else { 400: if (!nflag) 401: fprintf(stdout, "%s: %d -> ", string, 402: *(int *)buf); 403: fprintf(stdout, "%d\n", *(int *)newval); 404: } 405: return; 406: 407: case CTLTYPE_STRING: 408: if (newsize == 0) { 409: if (!nflag) 410: fprintf(stdout, "%s = ", string); 411: fprintf(stdout, "%s\n", buf); 412: } else { 413: if (!nflag) 414: fprintf(stdout, "%s: %s -> ", string, buf); 415: fprintf(stdout, "%s\n", newval); 416: } 417: return; 418: 419: case CTLTYPE_LONG: 420: if (newsize == 0) { 421: if (!nflag) 422: fprintf(stdout, "%s = ", string); 423: fprintf(stdout, "%ld\n", *(long *)buf); 424: } else { 425: if (!nflag) 426: fprintf(stdout, "%s: %ld -> ", string, 427: *(long *)buf); 428: fprintf(stdout, "%ld\n", *(long *)newval); 429: } 430: return; 431: 432: case CTLTYPE_STRUCT: 433: fprintf(stderr, "%s: unknown structure returned\n", 434: string); 435: return; 436: 437: default: 438: case CTLTYPE_NODE: 439: fprintf(stderr, "%s: unknown type returned\n", 440: string); 441: return; 442: } 443: } 444: 445: struct ctlname tmscpname[] = TMSCP_NAMES; 446: struct list tmscplist = { tmscpname, TMSCP_MAXID }; 447: 448: struct ctlname mscpname[] = MSCP_NAMES; 449: struct list mscplist = { mscpname, MSCP_MAXID }; 450: 451: /* 452: * Handle machdep.tmscp.x 453: */ 454: sysctl_tmscp(string, bufpp, mib, flags, typep) 455: char *string; 456: char **bufpp; 457: int mib[]; 458: int flags; 459: int *typep; 460: { 461: int indx; 462: 463: if (*bufpp == NULL) { 464: listall(string, &tmscplist); 465: return (-1); 466: } 467: if ((indx = findname(string, "third", bufpp, &tmscplist)) == -1) 468: return (-1); 469: mib[2] = indx; 470: *typep = tmscpname[indx].ctl_type; 471: return (3); 472: } 473: 474: /* 475: * Handle machdep.mscp.x 476: */ 477: sysctl_mscp(string, bufpp, mib, flags, typep) 478: char *string; 479: char **bufpp; 480: int mib[]; 481: int flags; 482: int *typep; 483: { 484: int indx; 485: 486: if (*bufpp == NULL) { 487: listall(string, &mscplist); 488: return (-1); 489: } 490: if ((indx = findname(string, "third", bufpp, &mscplist)) == -1) 491: return (-1); 492: mib[2] = indx; 493: *typep = mscpname[indx].ctl_type; 494: return (3); 495: } 496: 497: /* 498: * Initialize the set of debugging names 499: */ 500: debuginit() 501: { 502: int mib[3], size, loc, i; 503: 504: if (secondlevel[CTL_DEBUG].list != 0) 505: return; 506: secondlevel[CTL_DEBUG].list = debugname; 507: mib[0] = CTL_DEBUG; 508: mib[2] = CTL_DEBUG_NAME; 509: for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 510: mib[1] = i; 511: size = BUFSIZ - loc; 512: if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 513: continue; 514: debugname[i].ctl_name = &names[loc]; 515: debugname[i].ctl_type = CTLTYPE_INT; 516: loc += size; 517: } 518: } 519: 520: struct ctlname inetname[] = CTL_IPPROTO_NAMES; 521: struct ctlname ipname[] = IPCTL_NAMES; 522: struct ctlname icmpname[] = ICMPCTL_NAMES; 523: struct ctlname udpname[] = UDPCTL_NAMES; 524: struct list inetlist = { inetname, IPPROTO_MAXID }; 525: struct list inetvars[] = { 526: { ipname, IPCTL_MAXID }, /* ip */ 527: { icmpname, ICMPCTL_MAXID }, /* icmp */ 528: { 0, 0 }, /* igmp */ 529: { 0, 0 }, /* ggmp */ 530: { 0, 0 }, 531: { 0, 0 }, 532: { 0, 0 }, /* tcp */ 533: { 0, 0 }, 534: { 0, 0 }, /* egp */ 535: { 0, 0 }, 536: { 0, 0 }, 537: { 0, 0 }, 538: { 0, 0 }, /* pup */ 539: { 0, 0 }, 540: { 0, 0 }, 541: { 0, 0 }, 542: { 0, 0 }, 543: { udpname, UDPCTL_MAXID }, /* udp */ 544: }; 545: 546: /* 547: * handle internet requests 548: */ 549: sysctl_inet(string, bufpp, mib, flags, typep) 550: char *string; 551: char **bufpp; 552: int mib[]; 553: int flags; 554: int *typep; 555: { 556: struct list *lp; 557: int indx; 558: 559: if (*bufpp == NULL) { 560: listall(string, &inetlist); 561: return (-1); 562: } 563: if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 564: return (-1); 565: mib[2] = indx; 566: if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 567: lp = &inetvars[indx]; 568: else if (!flags) 569: return (-1); 570: else { 571: fprintf(stderr, "%s: no variables defined for this protocol\n", 572: string); 573: return (-1); 574: } 575: if (*bufpp == NULL) { 576: listall(string, lp); 577: return (-1); 578: } 579: if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 580: return (-1); 581: mib[3] = indx; 582: *typep = lp->list[indx].ctl_type; 583: return (4); 584: } 585: 586: /* 587: * Scan a list of names searching for a particular name. 588: */ 589: findname(string, level, bufp, namelist) 590: char *string; 591: char *level; 592: char **bufp; 593: struct list *namelist; 594: { 595: char *name; 596: int i; 597: 598: if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 599: fprintf(stderr, "%s: incomplete specification\n", string); 600: return (-1); 601: } 602: for (i = 0; i < namelist->size; i++) 603: if (namelist->list[i].ctl_name != NULL && 604: strcmp(name, namelist->list[i].ctl_name) == 0) 605: break; 606: if (i == namelist->size) { 607: fprintf(stderr, "%s level name %s in %s is invalid\n", 608: level, name, string); 609: return (-1); 610: } 611: return (i); 612: } 613: 614: usage() 615: { 616: 617: (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 618: "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 619: "sysctl [-n] -a", "sysctl [-n] -A"); 620: exit(1); 621: }