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 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef lint 31 static const char copyright[] = 32 "@(#) Copyright (c) 1993\n\ 33 The Regents of the University of California. All rights reserved.\n"; 34 #endif /* not lint */ 35 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; 39 #endif 40 static const char rcsid[] = 41 "$FreeBSD$"; 42 #endif /* not lint */ 43 44 #ifdef __i386__ 45 #include <sys/reboot.h> /* used for bootdev parsing */ 46 #endif 47 #include <sys/param.h> 48 #include <sys/time.h> 49 #include <sys/resource.h> 50 #include <sys/stat.h> 51 #include <sys/sysctl.h> 52 #include <sys/vmmeter.h> 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <locale.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 63 static int aflag, bflag, dflag, eflag, hflag, Nflag, nflag, oflag, xflag; 64 65 static int oidfmt(int *, int, char *, u_int *); 66 static void parse(char *); 67 static int show_var(int *, int); 68 static int sysctl_all (int *oid, int len); 69 static int name2oid(char *, int *); 70 71 static void set_T_dev_t (char *, void **, size_t *); 72 73 static void 74 usage(void) 75 { 76 77 (void)fprintf(stderr, "%s\n%s\n", 78 "usage: sysctl [-bdehNnox] name[=value] ...", 79 " sysctl [-bdehNnox] -a"); 80 exit(1); 81 } 82 83 int 84 main(int argc, char **argv) 85 { 86 int ch; 87 88 setlocale(LC_NUMERIC, ""); 89 setbuf(stdout,0); 90 setbuf(stderr,0); 91 92 while ((ch = getopt(argc, argv, "AabdehNnowxX")) != -1) { 93 switch (ch) { 94 case 'A': 95 /* compatibility */ 96 aflag = oflag = 1; 97 break; 98 case 'a': 99 aflag = 1; 100 break; 101 case 'b': 102 bflag = 1; 103 break; 104 case 'd': 105 dflag = 1; 106 break; 107 case 'e': 108 eflag = 1; 109 break; 110 case 'h': 111 hflag = 1; 112 break; 113 case 'N': 114 Nflag = 1; 115 break; 116 case 'n': 117 nflag = 1; 118 break; 119 case 'o': 120 oflag = 1; 121 break; 122 case 'w': 123 /* compatibility */ 124 /* ignored */ 125 break; 126 case 'X': 127 /* compatibility */ 128 aflag = xflag = 1; 129 break; 130 case 'x': 131 xflag = 1; 132 break; 133 default: 134 usage(); 135 } 136 } 137 argc -= optind; 138 argv += optind; 139 140 if (Nflag && nflag) 141 usage(); 142 if (aflag && argc == 0) 143 exit(sysctl_all(0, 0)); 144 if (argc == 0) 145 usage(); 146 while (argc-- > 0) 147 parse(*argv++); 148 exit(0); 149 } 150 151 /* 152 * Parse a name into a MIB entry. 153 * Lookup and print out the MIB entry if it exists. 154 * Set a new value if requested. 155 */ 156 static void 157 parse(char *string) 158 { 159 int len, i, j; 160 void *newval = 0; 161 int intval; 162 unsigned int uintval; 163 long longval; 164 unsigned long ulongval; 165 size_t newsize = 0; 166 quad_t quadval; 167 int mib[CTL_MAXNAME]; 168 char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ]; 169 u_int kind; 170 171 bufp = buf; 172 if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) 173 errx(1, "oid too long: '%s'", string); 174 if ((cp = strchr(string, '=')) != NULL) { 175 *strchr(buf, '=') = '\0'; 176 *cp++ = '\0'; 177 while (isspace(*cp)) 178 cp++; 179 newval = cp; 180 newsize = strlen(cp); 181 } 182 len = name2oid(bufp, mib); 183 184 if (len < 0) 185 errx(1, "unknown oid '%s'", bufp); 186 187 if (oidfmt(mib, len, fmt, &kind)) 188 err(1, "couldn't find format of oid '%s'", bufp); 189 190 if (newval == NULL) { 191 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 192 if (dflag) { 193 i = show_var(mib, len); 194 if (!i && !bflag) 195 putchar('\n'); 196 } 197 sysctl_all(mib, len); 198 } else { 199 i = show_var(mib, len); 200 if (!i && !bflag) 201 putchar('\n'); 202 } 203 } else { 204 if ((kind & CTLTYPE) == CTLTYPE_NODE) 205 errx(1, "oid '%s' isn't a leaf node", bufp); 206 207 if (!(kind & CTLFLAG_WR)) { 208 if (kind & CTLFLAG_TUN) { 209 warnx("oid '%s' is a read only tunable", bufp); 210 errx(1, "Tunable values are set in /boot/loader.conf"); 211 } else { 212 errx(1, "oid '%s' is read only", bufp); 213 } 214 } 215 216 if ((kind & CTLTYPE) == CTLTYPE_INT || 217 (kind & CTLTYPE) == CTLTYPE_UINT || 218 (kind & CTLTYPE) == CTLTYPE_LONG || 219 (kind & CTLTYPE) == CTLTYPE_ULONG || 220 (kind & CTLTYPE) == CTLTYPE_QUAD) { 221 if (strlen(newval) == 0) 222 errx(1, "empty numeric value"); 223 } 224 225 switch (kind & CTLTYPE) { 226 case CTLTYPE_INT: 227 intval = (int)strtol(newval, &endptr, 0); 228 if (endptr == newval || *endptr != '\0') 229 errx(1, "invalid integer '%s'", 230 newval); 231 newval = &intval; 232 newsize = sizeof(intval); 233 break; 234 case CTLTYPE_UINT: 235 uintval = (int) strtoul(newval, &endptr, 0); 236 if (endptr == newval || *endptr != '\0') 237 errx(1, "invalid unsigned integer '%s'", 238 newval); 239 newval = &uintval; 240 newsize = sizeof uintval; 241 break; 242 case CTLTYPE_LONG: 243 longval = strtol(newval, &endptr, 0); 244 if (endptr == newval || *endptr != '\0') 245 errx(1, "invalid long integer '%s'", 246 newval); 247 newval = &longval; 248 newsize = sizeof longval; 249 break; 250 case CTLTYPE_ULONG: 251 ulongval = strtoul(newval, &endptr, 0); 252 if (endptr == newval || *endptr != '\0') 253 errx(1, "invalid unsigned long integer" 254 " '%s'", newval); 255 newval = &ulongval; 256 newsize = sizeof ulongval; 257 break; 258 case CTLTYPE_STRING: 259 break; 260 case CTLTYPE_QUAD: 261 sscanf(newval, "%qd", &quadval); 262 newval = &quadval; 263 newsize = sizeof(quadval); 264 break; 265 case CTLTYPE_OPAQUE: 266 if (strcmp(fmt, "T,dev_t") == 0) { 267 set_T_dev_t ((char*)newval, &newval, &newsize); 268 break; 269 } 270 /* FALLTHROUGH */ 271 default: 272 errx(1, "oid '%s' is type %d," 273 " cannot set that", bufp, 274 kind & CTLTYPE); 275 } 276 277 i = show_var(mib, len); 278 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 279 if (!i && !bflag) 280 putchar('\n'); 281 switch (errno) { 282 case EOPNOTSUPP: 283 errx(1, "%s: value is not available", 284 string); 285 case ENOTDIR: 286 errx(1, "%s: specification is incomplete", 287 string); 288 case ENOMEM: 289 errx(1, "%s: type is unknown to this program", 290 string); 291 default: 292 warn("%s", string); 293 return; 294 } 295 } 296 if (!bflag) 297 printf(" -> "); 298 i = nflag; 299 nflag = 1; 300 j = show_var(mib, len); 301 if (!j && !bflag) 302 putchar('\n'); 303 nflag = i; 304 } 305 } 306 307 /* These functions will dump out various interesting structures. */ 308 309 static int 310 S_clockinfo(int l2, void *p) 311 { 312 struct clockinfo *ci = (struct clockinfo*)p; 313 if (l2 != sizeof(*ci)) { 314 warnx("S_clockinfo %d != %d", l2, sizeof(*ci)); 315 return (0); 316 } 317 printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" : 318 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }", 319 ci->hz, ci->tick, ci->profhz, ci->stathz); 320 return (0); 321 } 322 323 static int 324 S_loadavg(int l2, void *p) 325 { 326 struct loadavg *tv = (struct loadavg*)p; 327 328 if (l2 != sizeof(*tv)) { 329 warnx("S_loadavg %d != %d", l2, sizeof(*tv)); 330 return (0); 331 } 332 printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }", 333 (double)tv->ldavg[0]/(double)tv->fscale, 334 (double)tv->ldavg[1]/(double)tv->fscale, 335 (double)tv->ldavg[2]/(double)tv->fscale); 336 return (0); 337 } 338 339 static int 340 S_timeval(int l2, void *p) 341 { 342 struct timeval *tv = (struct timeval*)p; 343 time_t tv_sec; 344 char *p1, *p2; 345 346 if (l2 != sizeof(*tv)) { 347 warnx("S_timeval %d != %d", l2, sizeof(*tv)); 348 return (0); 349 } 350 printf(hflag ? "{ sec = %'ld, usec = %'ld } " : 351 "{ sec = %ld, usec = %ld } ", 352 tv->tv_sec, tv->tv_usec); 353 tv_sec = tv->tv_sec; 354 p1 = strdup(ctime(&tv_sec)); 355 for (p2=p1; *p2 ; p2++) 356 if (*p2 == '\n') 357 *p2 = '\0'; 358 fputs(p1, stdout); 359 return (0); 360 } 361 362 static int 363 S_vmtotal(int l2, void *p) 364 { 365 struct vmtotal *v = (struct vmtotal *)p; 366 int pageKilo = getpagesize() / 1024; 367 368 if (l2 != sizeof(*v)) { 369 warnx("S_vmtotal %d != %d", l2, sizeof(*v)); 370 return (0); 371 } 372 373 printf( 374 "\nSystem wide totals computed every five seconds:" 375 " (values in kilobytes)\n"); 376 printf("===============================================\n"); 377 printf( 378 "Processes:\t\t(RUNQ: %hu Disk Wait: %hu Page Wait: " 379 "%hu Sleep: %hu)\n", 380 v->t_rq, v->t_dw, v->t_pw, v->t_sl); 381 printf( 382 "Virtual Memory:\t\t(Total: %luK, Active %lldK)\n", 383 (unsigned long)v->t_vm / 1024, 384 (long long)v->t_avm * pageKilo); 385 printf("Real Memory:\t\t(Total: %lldK Active %lldK)\n", 386 (long long)v->t_rm * pageKilo, (long long)v->t_arm * pageKilo); 387 printf("Shared Virtual Memory:\t(Total: %lldK Active: %lldK)\n", 388 (long long)v->t_vmshr * pageKilo, 389 (long long)v->t_avmshr * pageKilo); 390 printf("Shared Real Memory:\t(Total: %lldK Active: %lldK)\n", 391 (long long)v->t_rmshr * pageKilo, 392 (long long)v->t_armshr * pageKilo); 393 printf("Free Memory Pages:\t%lldK\n", (long long)v->t_free * pageKilo); 394 395 return (0); 396 } 397 398 static int 399 T_dev_t(int l2, void *p) 400 { 401 dev_t *d = (dev_t *)p; 402 if (l2 != sizeof(*d)) { 403 warnx("T_dev_T %d != %d", l2, sizeof(*d)); 404 return (0); 405 } 406 if ((int)(*d) != -1) { 407 if (minor(*d) > 255 || minor(*d) < 0) 408 printf("{ major = %d, minor = 0x%x }", 409 major(*d), minor(*d)); 410 else 411 printf("{ major = %d, minor = %d }", 412 major(*d), minor(*d)); 413 } 414 return (0); 415 } 416 417 static void 418 set_T_dev_t (char *path, void **val, size_t *size) 419 { 420 static struct stat statb; 421 422 if (strcmp(path, "none") && strcmp(path, "off")) { 423 int rc = stat (path, &statb); 424 if (rc) { 425 err(1, "cannot stat %s", path); 426 } 427 428 if (!S_ISCHR(statb.st_mode)) { 429 errx(1, "must specify a device special file."); 430 } 431 } else { 432 statb.st_rdev = NODEV; 433 } 434 *val = (char*) &statb.st_rdev; 435 *size = sizeof statb.st_rdev; 436 } 437 438 /* 439 * These functions uses a presently undocumented interface to the kernel 440 * to walk the tree and get the type so it can print the value. 441 * This interface is under work and consideration, and should probably 442 * be killed with a big axe by the first person who can find the time. 443 * (be aware though, that the proper interface isn't as obvious as it 444 * may seem, there are various conflicting requirements. 445 */ 446 447 static int 448 name2oid(char *name, int *oidp) 449 { 450 int oid[2]; 451 int i; 452 size_t j; 453 454 oid[0] = 0; 455 oid[1] = 3; 456 457 j = CTL_MAXNAME * sizeof(int); 458 i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 459 if (i < 0) 460 return i; 461 j /= sizeof(int); 462 return (j); 463 } 464 465 static int 466 oidfmt(int *oid, int len, char *fmt, u_int *kind) 467 { 468 int qoid[CTL_MAXNAME+2]; 469 u_char buf[BUFSIZ]; 470 int i; 471 size_t j; 472 473 qoid[0] = 0; 474 qoid[1] = 4; 475 memcpy(qoid + 2, oid, len * sizeof(int)); 476 477 j = sizeof(buf); 478 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 479 if (i) 480 err(1, "sysctl fmt %d %d %d", i, j, errno); 481 482 if (kind) 483 *kind = *(u_int *)buf; 484 485 if (fmt) 486 strcpy(fmt, (char *)(buf + sizeof(u_int))); 487 return 0; 488 } 489 490 /* 491 * This formats and outputs the value of one variable 492 * 493 * Returns zero if anything was actually output. 494 * Returns one if didn't know what to do with this. 495 * Return minus one if we had errors. 496 */ 497 498 static int 499 show_var(int *oid, int nlen) 500 { 501 u_char buf[BUFSIZ], *val, *p; 502 char name[BUFSIZ], *fmt, *sep; 503 int qoid[CTL_MAXNAME+2]; 504 int i; 505 size_t j, len; 506 u_int kind; 507 int (*func)(int, void *); 508 509 bzero(buf, BUFSIZ); 510 bzero(name, BUFSIZ); 511 qoid[0] = 0; 512 memcpy(qoid + 2, oid, nlen * sizeof(int)); 513 514 qoid[1] = 1; 515 j = sizeof(name); 516 i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 517 if (i || !j) 518 err(1, "sysctl name %d %d %d", i, j, errno); 519 520 if (Nflag) { 521 printf("%s", name); 522 return (0); 523 } 524 525 if (eflag) 526 sep = "="; 527 else 528 sep = ": "; 529 530 if (dflag) { /* just print description */ 531 qoid[1] = 5; 532 j = sizeof(buf); 533 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 534 if (!nflag) 535 printf("%s%s", name, sep); 536 printf("%s", buf); 537 return (0); 538 } 539 /* find an estimate of how much we need for this var */ 540 j = 0; 541 i = sysctl(oid, nlen, 0, &j, 0, 0); 542 j += j; /* we want to be sure :-) */ 543 544 val = alloca(j + 1); 545 len = j; 546 i = sysctl(oid, nlen, val, &len, 0, 0); 547 if (i || !len) 548 return (1); 549 550 if (bflag) { 551 fwrite(val, 1, len, stdout); 552 return (0); 553 } 554 val[len] = '\0'; 555 fmt = buf; 556 oidfmt(oid, nlen, fmt, &kind); 557 p = val; 558 switch (*fmt) { 559 case 'A': 560 if (!nflag) 561 printf("%s%s", name, sep); 562 printf("%.*s", len, p); 563 return (0); 564 565 case 'I': 566 if (!nflag) 567 printf("%s%s", name, sep); 568 fmt++; 569 val = ""; 570 while (len >= sizeof(int)) { 571 fputs(val, stdout); 572 if(*fmt == 'U') 573 printf(hflag ? "%'u" : "%u", *(unsigned int *)p); 574 else if (*fmt == 'K') { 575 if (*(int *)p < 0) 576 printf("%d", *(int *)p); 577 else 578 printf("%d.%dC", (*(int *)p - 2732) / 10, (*(int *)p - 2732) % 10); 579 } else 580 printf(hflag ? "%'d" : "%d", *(int *)p); 581 val = " "; 582 len -= sizeof(int); 583 p += sizeof(int); 584 } 585 return (0); 586 587 case 'L': 588 if (!nflag) 589 printf("%s%s", name, sep); 590 fmt++; 591 val = ""; 592 while (len >= sizeof(long)) { 593 fputs(val, stdout); 594 if(*fmt == 'U') 595 printf(hflag ? "%'lu" : "%lu", *(unsigned long *)p); 596 else if (*fmt == 'K') { 597 if (*(long *)p < 0) 598 printf("%ld", *(long *)p); 599 else 600 printf("%ld.%ldC", (*(long *)p - 2732) / 10, (*(long *)p - 2732) % 10); 601 } else 602 printf(hflag ? "%'ld" : "%ld", *(long *)p); 603 val = " "; 604 len -= sizeof(long); 605 p += sizeof(long); 606 } 607 return (0); 608 609 case 'P': 610 if (!nflag) 611 printf("%s%s", name, sep); 612 printf("%p", *(void **)p); 613 return (0); 614 615 case 'T': 616 case 'S': 617 i = 0; 618 if (strcmp(fmt, "S,clockinfo") == 0) 619 func = S_clockinfo; 620 else if (strcmp(fmt, "S,timeval") == 0) 621 func = S_timeval; 622 else if (strcmp(fmt, "S,loadavg") == 0) 623 func = S_loadavg; 624 else if (strcmp(fmt, "S,vmtotal") == 0) 625 func = S_vmtotal; 626 else if (strcmp(fmt, "T,dev_t") == 0) 627 func = T_dev_t; 628 else 629 func = NULL; 630 if (func) { 631 if (!nflag) 632 printf("%s%s", name, sep); 633 return ((*func)(len, p)); 634 } 635 /* FALLTHROUGH */ 636 default: 637 if (!oflag && !xflag) 638 return (1); 639 if (!nflag) 640 printf("%s%s", name, sep); 641 printf("Format:%s Length:%d Dump:0x", fmt, len); 642 while (len-- && (xflag || p < val + 16)) 643 printf("%02x", *p++); 644 if (!xflag && len > 16) 645 printf("..."); 646 return (0); 647 } 648 return (1); 649 } 650 651 static int 652 sysctl_all (int *oid, int len) 653 { 654 int name1[22], name2[22]; 655 int i, j; 656 size_t l1, l2; 657 658 name1[0] = 0; 659 name1[1] = 2; 660 l1 = 2; 661 if (len) { 662 memcpy(name1+2, oid, len * sizeof(int)); 663 l1 += len; 664 } else { 665 name1[2] = 1; 666 l1++; 667 } 668 for (;;) { 669 l2 = sizeof(name2); 670 j = sysctl(name1, l1, name2, &l2, 0, 0); 671 if (j < 0) { 672 if (errno == ENOENT) 673 return 0; 674 else 675 err(1, "sysctl(getnext) %d %d", j, l2); 676 } 677 678 l2 /= sizeof(int); 679 680 if (l2 < len) 681 return 0; 682 683 for (i = 0; i < len; i++) 684 if (name2[i] != oid[i]) 685 return 0; 686 687 i = show_var(name2, l2); 688 if (!i && !bflag) 689 putchar('\n'); 690 691 memcpy(name1+2, name2, l2 * sizeof(int)); 692 l1 = 2 + l2; 693 } 694 } 695