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