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 #ifndef lint 35 static char copyright[] = 36 "@(#) Copyright (c) 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "From: @(#)sysctl.c 8.1 (Berkeley) 6/6/93"; */ 42 static const char rcsid[] = 43 "$Id: sysctl.c,v 1.5 1995/05/12 19:10:56 wollman Exp $"; 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/gmon.h> 48 #include <sys/stat.h> 49 #include <sys/sysctl.h> 50 #include <sys/socket.h> 51 #include <vm/vm_param.h> 52 #include <machine/cpu.h> 53 54 #include <netinet/in.h> 55 #include <netinet/in_systm.h> 56 #include <netinet/ip.h> 57 #include <netinet/ip_icmp.h> 58 #include <netinet/icmp_var.h> 59 #include <netinet/ip_var.h> 60 #include <netinet/udp.h> 61 #include <netinet/udp_var.h> 62 #include <netinet/tcp.h> 63 #include <netinet/tcp_seq.h> 64 #include <netinet/tcp_timer.h> 65 #include <netinet/tcp_var.h> 66 #include <netinet/igmp_var.h> 67 68 #include <errno.h> 69 #include <stdio.h> 70 #include <stdlib.h> 71 #include <string.h> 72 73 struct ctlname topname[] = CTL_NAMES; 74 struct ctlname kernname[] = CTL_KERN_NAMES; 75 struct ctlname vmname[] = CTL_VM_NAMES; 76 struct ctlname netname[] = CTL_NET_NAMES; 77 struct ctlname hwname[] = CTL_HW_NAMES; 78 struct ctlname username[] = CTL_USER_NAMES; 79 struct ctlname debugname[CTL_DEBUG_MAXID]; 80 #ifdef CTL_MACHDEP_NAMES 81 struct ctlname machdepname[] = CTL_MACHDEP_NAMES; 82 #endif 83 char names[BUFSIZ]; 84 85 struct list { 86 struct ctlname *list; 87 int size; 88 }; 89 struct list toplist = { topname, CTL_MAXID }; 90 struct list secondlevel[] = { 91 { 0, 0 }, /* CTL_UNSPEC */ 92 { kernname, KERN_MAXID }, /* CTL_KERN */ 93 { vmname, VM_MAXID }, /* CTL_VM */ 94 { 0, 0 }, /* CTL_FS */ 95 { netname, NET_MAXID }, /* CTL_NET */ 96 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 97 { hwname, HW_MAXID }, /* CTL_HW */ 98 #ifdef CTL_MACHDEP_NAMES 99 { machdepname, CPU_MAXID }, /* CTL_MACHDEP */ 100 #else 101 { 0, 0 }, /* CTL_MACHDEP */ 102 #endif 103 { username, USER_MAXID }, /* CTL_USER_NAMES */ 104 }; 105 106 int Aflag, aflag, nflag, wflag; 107 108 /* 109 * Variables requiring special processing. 110 */ 111 #define CLOCK 0x00000001 112 #define BOOTTIME 0x00000002 113 #define CONSDEV 0x00000004 114 #define DUMPDEV 0x00000008 115 116 int 117 main(argc, argv) 118 int argc; 119 char *argv[]; 120 { 121 extern char *optarg; 122 extern int optind; 123 int ch, lvl1; 124 125 while ((ch = getopt(argc, argv, "Aanw")) != EOF) { 126 switch (ch) { 127 128 case 'A': 129 Aflag = 1; 130 break; 131 132 case 'a': 133 aflag = 1; 134 break; 135 136 case 'n': 137 nflag = 1; 138 break; 139 140 case 'w': 141 wflag = 1; 142 break; 143 144 default: 145 usage(); 146 } 147 } 148 argc -= optind; 149 argv += optind; 150 151 if (Aflag || aflag) { 152 debuginit(); 153 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++) 154 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]); 155 exit(0); 156 } 157 if (argc == 0) 158 usage(); 159 while (argc-- > 0) 160 parse(*argv, 1); 161 exit(0); 162 } 163 164 /* 165 * List all variables known to the system. 166 */ 167 listall(prefix, lp) 168 char *prefix; 169 struct list *lp; 170 { 171 int lvl2; 172 char *cp, name[BUFSIZ]; 173 174 if (lp->list == 0) 175 return; 176 strcpy(name, prefix); 177 cp = &name[strlen(name)]; 178 *cp++ = '.'; 179 for (lvl2 = 0; lvl2 < lp->size; lvl2++) { 180 if (lp->list[lvl2].ctl_name == 0) 181 continue; 182 strcpy(cp, lp->list[lvl2].ctl_name); 183 parse(name, Aflag); 184 } 185 } 186 187 /* 188 * Parse a name into a MIB entry. 189 * Lookup and print out the MIB entry if it exists. 190 * Set a new value if requested. 191 */ 192 parse(string, flags) 193 char *string; 194 int flags; 195 { 196 int indx, type, state, size, len; 197 int special = 0; 198 void *newval = 0; 199 int intval, newsize = 0; 200 quad_t quadval; 201 struct list *lp; 202 int mib[CTL_MAXNAME]; 203 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ]; 204 205 bufp = buf; 206 snprintf(buf, BUFSIZ, "%s", string); 207 if ((cp = strchr(string, '=')) != NULL) { 208 if (!wflag) { 209 fprintf(stderr, "Must specify -w to set variables\n"); 210 exit(2); 211 } 212 *strchr(buf, '=') = '\0'; 213 *cp++ = '\0'; 214 while (isspace(*cp)) 215 cp++; 216 newval = cp; 217 newsize = strlen(cp); 218 } 219 if ((indx = findname(string, "top", &bufp, &toplist)) == -1) 220 return; 221 mib[0] = indx; 222 if (indx == CTL_DEBUG) 223 debuginit(); 224 lp = &secondlevel[indx]; 225 if (lp->list == 0) { 226 fprintf(stderr, "%s: class is not implemented\n", 227 topname[indx]); 228 return; 229 } 230 if (bufp == NULL) { 231 listall(topname[indx].ctl_name, lp); 232 return; 233 } 234 if ((indx = findname(string, "second", &bufp, lp)) == -1) 235 return; 236 mib[1] = indx; 237 type = lp->list[indx].ctl_type; 238 len = 2; 239 switch (mib[0]) { 240 241 case CTL_KERN: 242 switch (mib[1]) { 243 case KERN_PROF: 244 mib[2] = GPROF_STATE; 245 size = sizeof state; 246 if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) { 247 if (flags == 0) 248 return; 249 if (!nflag) 250 fprintf(stdout, "%s: ", string); 251 fprintf(stderr, 252 "kernel is not compiled for profiling\n"); 253 return; 254 } 255 if (!nflag) 256 fprintf(stdout, "%s: %s\n", string, 257 state == GMON_PROF_OFF ? "off" : "running"); 258 return; 259 case KERN_VNODE: 260 case KERN_FILE: 261 if (flags == 0) 262 return; 263 fprintf(stderr, 264 "Use pstat to view %s information\n", string); 265 return; 266 case KERN_PROC: 267 if (flags == 0) 268 return; 269 fprintf(stderr, 270 "Use ps to view %s information\n", string); 271 return; 272 case KERN_CLOCKRATE: 273 special |= CLOCK; 274 break; 275 case KERN_BOOTTIME: 276 special |= BOOTTIME; 277 break; 278 case KERN_DUMPDEV: 279 special |= DUMPDEV; 280 break; 281 } 282 break; 283 284 case CTL_HW: 285 break; 286 287 case CTL_VM: 288 if (mib[1] == VM_LOADAVG) { 289 double loads[3]; 290 291 getloadavg(loads, 3); 292 if (!nflag) 293 fprintf(stdout, "%s: ", string); 294 fprintf(stdout, "%.2f %.2f %.2f\n", 295 loads[0], loads[1], loads[2]); 296 return; 297 } 298 if (flags == 0) 299 return; 300 fprintf(stderr, 301 "Use vmstat or systat to view %s information\n", string); 302 return; 303 304 case CTL_NET: 305 if (mib[1] == PF_INET) { 306 len = sysctl_inet(string, &bufp, mib, flags, &type, 307 &special); 308 if (len >= 0) 309 break; 310 return; 311 } 312 if (flags == 0) 313 return; 314 fprintf(stderr, "Use netstat to view %s information\n", string); 315 return; 316 317 case CTL_DEBUG: 318 mib[2] = CTL_DEBUG_VALUE; 319 len = 3; 320 break; 321 322 case CTL_MACHDEP: 323 #ifdef CPU_CONSDEV 324 if (mib[1] == CPU_CONSDEV) 325 special |= CONSDEV; 326 #endif 327 break; 328 329 case CTL_FS: 330 case CTL_USER: 331 break; 332 333 default: 334 fprintf(stderr, "Illegal top level value: %d\n", mib[0]); 335 return; 336 337 } 338 if (bufp) { 339 fprintf(stderr, "name %s in %s is unknown\n", *bufp, string); 340 return; 341 } 342 if (newsize > 0) { 343 switch (type) { 344 case CTLTYPE_INT: 345 intval = atoi(newval); 346 newval = &intval; 347 newsize = sizeof intval; 348 break; 349 350 case CTLTYPE_QUAD: 351 sscanf(newval, "%qd", &quadval); 352 newval = &quadval; 353 newsize = sizeof quadval; 354 break; 355 } 356 } 357 size = BUFSIZ; 358 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) { 359 if (flags == 0) 360 return; 361 switch (errno) { 362 case EOPNOTSUPP: 363 fprintf(stderr, "%s: value is not available\n", string); 364 return; 365 case ENOTDIR: 366 fprintf(stderr, "%s: specification is incomplete\n", 367 string); 368 return; 369 case ENOMEM: 370 fprintf(stderr, "%s: type is unknown to this program\n", 371 string); 372 return; 373 default: 374 perror(string); 375 return; 376 } 377 } 378 if (special & CLOCK) { 379 struct clockinfo *clkp = (struct clockinfo *)buf; 380 381 if (!nflag) 382 fprintf(stdout, "%s: ", string); 383 fprintf(stdout, 384 "hz = %d, tick = %d, profhz = %d, stathz = %d\n", 385 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz); 386 return; 387 } 388 if (special & BOOTTIME) { 389 struct timeval *btp = (struct timeval *)buf; 390 391 if (!nflag) 392 fprintf(stdout, "%s = %s", string, 393 ctime(&btp->tv_sec)); 394 else 395 fprintf(stdout, "%d\n", btp->tv_sec); 396 return; 397 } 398 if (special & (CONSDEV | DUMPDEV)) { 399 dev_t dev = *(dev_t *)buf; 400 401 if ((special & DUMPDEV) && dev == NODEV && !nflag) { 402 printf("%s = disabled\n", string); 403 return; 404 } 405 if (!nflag) 406 fprintf(stdout, "%s = %s\n", string, 407 devname(dev, 408 (special & CONSDEV) ? S_IFCHR : S_IFBLK)); 409 else 410 fprintf(stdout, "0x%x\n", dev); 411 return; 412 } 413 switch (type) { 414 case CTLTYPE_INT: 415 if (newsize == 0) { 416 if (!nflag) 417 fprintf(stdout, "%s = ", string); 418 fprintf(stdout, "%d\n", *(int *)buf); 419 } else { 420 if (!nflag) 421 fprintf(stdout, "%s: %d -> ", string, 422 *(int *)buf); 423 fprintf(stdout, "%d\n", *(int *)newval); 424 } 425 return; 426 427 case CTLTYPE_STRING: 428 if (newsize == 0) { 429 if (!nflag) 430 fprintf(stdout, "%s = ", string); 431 fprintf(stdout, "%s\n", buf); 432 } else { 433 if (!nflag) 434 fprintf(stdout, "%s: %s -> ", string, buf); 435 fprintf(stdout, "%s\n", newval); 436 } 437 return; 438 439 case CTLTYPE_QUAD: 440 if (newsize == 0) { 441 if (!nflag) 442 fprintf(stdout, "%s = ", string); 443 fprintf(stdout, "%qd\n", *(quad_t *)buf); 444 } else { 445 if (!nflag) 446 fprintf(stdout, "%s: %qd -> ", string, 447 *(quad_t *)buf); 448 fprintf(stdout, "%qd\n", *(quad_t *)newval); 449 } 450 return; 451 452 case CTLTYPE_STRUCT: 453 fprintf(stderr, "%s: unknown structure returned\n", 454 string); 455 return; 456 457 default: 458 case CTLTYPE_NODE: 459 fprintf(stderr, "%s: unknown type returned\n", 460 string); 461 return; 462 } 463 } 464 465 /* 466 * Initialize the set of debugging names 467 */ 468 debuginit() 469 { 470 int mib[3], size, loc, i; 471 472 if (secondlevel[CTL_DEBUG].list != 0) 473 return; 474 secondlevel[CTL_DEBUG].list = debugname; 475 mib[0] = CTL_DEBUG; 476 mib[2] = CTL_DEBUG_NAME; 477 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) { 478 mib[1] = i; 479 size = BUFSIZ - loc; 480 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1) 481 continue; 482 debugname[i].ctl_name = &names[loc]; 483 debugname[i].ctl_type = CTLTYPE_INT; 484 loc += size; 485 } 486 } 487 488 struct ctlname inetname[] = CTL_IPPROTO_NAMES; 489 struct ctlname ipname[] = IPCTL_NAMES; 490 struct ctlname icmpname[] = ICMPCTL_NAMES; 491 struct ctlname udpname[] = UDPCTL_NAMES; 492 struct ctlname tcpname[] = TCPCTL_NAMES; 493 struct ctlname igmpname[] = IGMPCTL_NAMES; 494 struct list inetlist = { inetname, IPPROTO_MAXID }; 495 struct list inetvars[] = { 496 { ipname, IPCTL_MAXID }, /* ip */ 497 { icmpname, ICMPCTL_MAXID }, /* icmp */ 498 { igmpname, IGMPCTL_MAXID }, /* igmp */ 499 { 0, 0 }, /* ggp */ 500 { 0, 0 }, /* ipencap */ 501 { 0, 0 }, 502 { tcpname, TCPCTL_MAXID }, /* tcp */ 503 { 0, 0 }, 504 { 0, 0 }, /* egp */ 505 { 0, 0 }, 506 { 0, 0 }, 507 { 0, 0 }, 508 { 0, 0 }, /* pup */ 509 { 0, 0 }, 510 { 0, 0 }, 511 { 0, 0 }, 512 { 0, 0 }, 513 { udpname, UDPCTL_MAXID }, /* udp */ 514 }; 515 516 /* 517 * handle internet requests 518 */ 519 int 520 sysctl_inet(string, bufpp, mib, flags, typep, specialp) 521 char *string; 522 char **bufpp; 523 int mib[]; 524 int flags; 525 int *typep; 526 int *specialp; 527 { 528 struct list *lp; 529 int indx; 530 531 if (*bufpp == NULL) { 532 listall(string, &inetlist); 533 return (-1); 534 } 535 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1) 536 return (-1); 537 mib[2] = indx; 538 if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL) 539 lp = &inetvars[indx]; 540 else if (!flags) 541 return (-1); 542 else { 543 fprintf(stderr, "%s: no variables defined for this protocol\n", 544 string); 545 return (-1); 546 } 547 if (*bufpp == NULL) { 548 listall(string, lp); 549 return (-1); 550 } 551 if ((indx = findname(string, "fourth", bufpp, lp)) == -1) 552 return (-1); 553 mib[3] = indx; 554 *typep = lp->list[indx].ctl_type; 555 return (4); 556 } 557 558 /* 559 * Scan a list of names searching for a particular name. 560 */ 561 findname(string, level, bufp, namelist) 562 char *string; 563 char *level; 564 char **bufp; 565 struct list *namelist; 566 { 567 char *name; 568 int i; 569 570 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) { 571 fprintf(stderr, "%s: incomplete specification\n", string); 572 return (-1); 573 } 574 for (i = 0; i < namelist->size; i++) 575 if (namelist->list[i].ctl_name != NULL && 576 strcmp(name, namelist->list[i].ctl_name) == 0) 577 break; 578 if (i == namelist->size) { 579 fprintf(stderr, "%s level name %s in %s is invalid\n", 580 level, name, string); 581 return (-1); 582 } 583 return (i); 584 } 585 586 usage() 587 { 588 589 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n", 590 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...", 591 "sysctl [-n] -a", "sysctl [-n] -A"); 592 exit(1); 593 } 594