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 #include <sys/param.h> 45 #include <sys/time.h> 46 #include <sys/resource.h> 47 #include <sys/stat.h> 48 #include <sys/sysctl.h> 49 #include <sys/vmmeter.h> 50 51 #include <ctype.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <inttypes.h> 55 #include <locale.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 static int aflag, bflag, dflag, eflag, hflag, iflag; 62 static int Nflag, nflag, oflag, qflag, xflag, warncount; 63 64 static int oidfmt(int *, int, char *, u_int *); 65 static void parse(char *); 66 static int show_var(int *, int); 67 static int sysctl_all(int *oid, int len); 68 static int name2oid(char *, int *); 69 70 static int set_IK(const char *, int *); 71 72 static void 73 usage(void) 74 { 75 76 (void)fprintf(stderr, "%s\n%s\n", 77 "usage: sysctl [-bdehiNnoqx] name[=value] ...", 78 " sysctl [-bdehNnoqx] -a"); 79 exit(1); 80 } 81 82 int 83 main(int argc, char **argv) 84 { 85 int ch; 86 87 setlocale(LC_NUMERIC, ""); 88 setbuf(stdout,0); 89 setbuf(stderr,0); 90 91 while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) { 92 switch (ch) { 93 case 'A': 94 /* compatibility */ 95 aflag = oflag = 1; 96 break; 97 case 'a': 98 aflag = 1; 99 break; 100 case 'b': 101 bflag = 1; 102 break; 103 case 'd': 104 dflag = 1; 105 break; 106 case 'e': 107 eflag = 1; 108 break; 109 case 'h': 110 hflag = 1; 111 break; 112 case 'i': 113 iflag = 1; 114 break; 115 case 'N': 116 Nflag = 1; 117 break; 118 case 'n': 119 nflag = 1; 120 break; 121 case 'o': 122 oflag = 1; 123 break; 124 case 'q': 125 qflag = 1; 126 break; 127 case 'w': 128 /* compatibility */ 129 /* ignored */ 130 break; 131 case 'X': 132 /* compatibility */ 133 aflag = xflag = 1; 134 break; 135 case 'x': 136 xflag = 1; 137 break; 138 default: 139 usage(); 140 } 141 } 142 argc -= optind; 143 argv += optind; 144 145 if (Nflag && nflag) 146 usage(); 147 if (aflag && argc == 0) 148 exit(sysctl_all(0, 0)); 149 if (argc == 0) 150 usage(); 151 152 warncount = 0; 153 while (argc-- > 0) 154 parse(*argv++); 155 exit(warncount); 156 } 157 158 /* 159 * Parse a name into a MIB entry. 160 * Lookup and print out the MIB entry if it exists. 161 * Set a new value if requested. 162 */ 163 static void 164 parse(char *string) 165 { 166 int len, i, j; 167 void *newval = 0; 168 int intval; 169 unsigned int uintval; 170 long longval; 171 unsigned long ulongval; 172 size_t newsize = 0; 173 int64_t i64val; 174 uint64_t u64val; 175 int mib[CTL_MAXNAME]; 176 char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ]; 177 u_int kind; 178 179 bufp = buf; 180 if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) 181 errx(1, "oid too long: '%s'", string); 182 if ((cp = strchr(string, '=')) != NULL) { 183 *strchr(buf, '=') = '\0'; 184 *cp++ = '\0'; 185 while (isspace(*cp)) 186 cp++; 187 newval = cp; 188 newsize = strlen(cp); 189 } 190 len = name2oid(bufp, mib); 191 192 if (len < 0) { 193 if (iflag) 194 return; 195 if (qflag) 196 exit(1); 197 else 198 errx(1, "unknown oid '%s'", bufp); 199 } 200 201 if (oidfmt(mib, len, fmt, &kind)) 202 err(1, "couldn't find format of oid '%s'", bufp); 203 204 if (newval == NULL || dflag) { 205 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 206 if (dflag) { 207 i = show_var(mib, len); 208 if (!i && !bflag) 209 putchar('\n'); 210 } 211 sysctl_all(mib, len); 212 } else { 213 i = show_var(mib, len); 214 if (!i && !bflag) 215 putchar('\n'); 216 } 217 } else { 218 if ((kind & CTLTYPE) == CTLTYPE_NODE) 219 errx(1, "oid '%s' isn't a leaf node", bufp); 220 221 if (!(kind & CTLFLAG_WR)) { 222 if (kind & CTLFLAG_TUN) { 223 warnx("oid '%s' is a read only tunable", bufp); 224 errx(1, "Tunable values are set in /boot/loader.conf"); 225 } else { 226 errx(1, "oid '%s' is read only", bufp); 227 } 228 } 229 230 if ((kind & CTLTYPE) == CTLTYPE_INT || 231 (kind & CTLTYPE) == CTLTYPE_UINT || 232 (kind & CTLTYPE) == CTLTYPE_LONG || 233 (kind & CTLTYPE) == CTLTYPE_ULONG || 234 (kind & CTLTYPE) == CTLTYPE_S64 || 235 (kind & CTLTYPE) == CTLTYPE_U64) { 236 if (strlen(newval) == 0) 237 errx(1, "empty numeric value"); 238 } 239 240 switch (kind & CTLTYPE) { 241 case CTLTYPE_INT: 242 if (strcmp(fmt, "IK") == 0) { 243 if (!set_IK(newval, &intval)) 244 errx(1, "invalid value '%s'", 245 (char *)newval); 246 } else { 247 intval = (int)strtol(newval, &endptr, 248 0); 249 if (endptr == newval || *endptr != '\0') 250 errx(1, "invalid integer '%s'", 251 (char *)newval); 252 } 253 newval = &intval; 254 newsize = sizeof(intval); 255 break; 256 case CTLTYPE_UINT: 257 uintval = (int) strtoul(newval, &endptr, 0); 258 if (endptr == newval || *endptr != '\0') 259 errx(1, "invalid unsigned integer '%s'", 260 (char *)newval); 261 newval = &uintval; 262 newsize = sizeof(uintval); 263 break; 264 case CTLTYPE_LONG: 265 longval = strtol(newval, &endptr, 0); 266 if (endptr == newval || *endptr != '\0') 267 errx(1, "invalid long integer '%s'", 268 (char *)newval); 269 newval = &longval; 270 newsize = sizeof(longval); 271 break; 272 case CTLTYPE_ULONG: 273 ulongval = strtoul(newval, &endptr, 0); 274 if (endptr == newval || *endptr != '\0') 275 errx(1, "invalid unsigned long integer" 276 " '%s'", (char *)newval); 277 newval = &ulongval; 278 newsize = sizeof(ulongval); 279 break; 280 case CTLTYPE_STRING: 281 break; 282 case CTLTYPE_S64: 283 i64val = strtoimax(newval, &endptr, 0); 284 if (endptr == newval || *endptr != '\0') 285 errx(1, "invalid int64_t '%s'", 286 (char *)newval); 287 newval = &i64val; 288 newsize = sizeof(i64val); 289 break; 290 case CTLTYPE_U64: 291 u64val = strtoumax(newval, &endptr, 0); 292 if (endptr == newval || *endptr != '\0') 293 errx(1, "invalid uint64_t '%s'", 294 (char *)newval); 295 newval = &u64val; 296 newsize = sizeof(u64val); 297 break; 298 case CTLTYPE_OPAQUE: 299 /* FALLTHROUGH */ 300 default: 301 errx(1, "oid '%s' is type %d," 302 " cannot set that", bufp, 303 kind & CTLTYPE); 304 } 305 306 i = show_var(mib, len); 307 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 308 if (!i && !bflag) 309 putchar('\n'); 310 switch (errno) { 311 case EOPNOTSUPP: 312 errx(1, "%s: value is not available", 313 string); 314 case ENOTDIR: 315 errx(1, "%s: specification is incomplete", 316 string); 317 case ENOMEM: 318 errx(1, "%s: type is unknown to this program", 319 string); 320 default: 321 warn("%s", string); 322 warncount++; 323 return; 324 } 325 } 326 if (!bflag) 327 printf(" -> "); 328 i = nflag; 329 nflag = 1; 330 j = show_var(mib, len); 331 if (!j && !bflag) 332 putchar('\n'); 333 nflag = i; 334 } 335 } 336 337 /* These functions will dump out various interesting structures. */ 338 339 static int 340 S_clockinfo(int l2, void *p) 341 { 342 struct clockinfo *ci = (struct clockinfo*)p; 343 344 if (l2 != sizeof(*ci)) { 345 warnx("S_clockinfo %d != %zu", l2, sizeof(*ci)); 346 return (1); 347 } 348 printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" : 349 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }", 350 ci->hz, ci->tick, ci->profhz, ci->stathz); 351 return (0); 352 } 353 354 static int 355 S_loadavg(int l2, void *p) 356 { 357 struct loadavg *tv = (struct loadavg*)p; 358 359 if (l2 != sizeof(*tv)) { 360 warnx("S_loadavg %d != %zu", l2, sizeof(*tv)); 361 return (1); 362 } 363 printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }", 364 (double)tv->ldavg[0]/(double)tv->fscale, 365 (double)tv->ldavg[1]/(double)tv->fscale, 366 (double)tv->ldavg[2]/(double)tv->fscale); 367 return (0); 368 } 369 370 static int 371 S_timeval(int l2, void *p) 372 { 373 struct timeval *tv = (struct timeval*)p; 374 time_t tv_sec; 375 char *p1, *p2; 376 377 if (l2 != sizeof(*tv)) { 378 warnx("S_timeval %d != %zu", l2, sizeof(*tv)); 379 return (1); 380 } 381 printf(hflag ? "{ sec = %'jd, usec = %'ld } " : 382 "{ sec = %jd, usec = %ld } ", 383 (intmax_t)tv->tv_sec, tv->tv_usec); 384 tv_sec = tv->tv_sec; 385 p1 = strdup(ctime(&tv_sec)); 386 for (p2=p1; *p2 ; p2++) 387 if (*p2 == '\n') 388 *p2 = '\0'; 389 fputs(p1, stdout); 390 free(p1); 391 return (0); 392 } 393 394 static int 395 S_vmtotal(int l2, void *p) 396 { 397 struct vmtotal *v = (struct vmtotal *)p; 398 int pageKilo = getpagesize() / 1024; 399 400 if (l2 != sizeof(*v)) { 401 warnx("S_vmtotal %d != %zu", l2, sizeof(*v)); 402 return (1); 403 } 404 405 printf( 406 "\nSystem wide totals computed every five seconds:" 407 " (values in kilobytes)\n"); 408 printf("===============================================\n"); 409 printf( 410 "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: " 411 "%hd Sleep: %hd)\n", 412 v->t_rq, v->t_dw, v->t_pw, v->t_sl); 413 printf( 414 "Virtual Memory:\t\t(Total: %dK Active: %dK)\n", 415 v->t_vm * pageKilo, v->t_avm * pageKilo); 416 printf("Real Memory:\t\t(Total: %dK Active: %dK)\n", 417 v->t_rm * pageKilo, v->t_arm * pageKilo); 418 printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n", 419 v->t_vmshr * pageKilo, v->t_avmshr * pageKilo); 420 printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n", 421 v->t_rmshr * pageKilo, v->t_armshr * pageKilo); 422 printf("Free Memory Pages:\t%dK\n", v->t_free * pageKilo); 423 424 return (0); 425 } 426 427 static int 428 set_IK(const char *str, int *val) 429 { 430 float temp; 431 int len, kelv; 432 const char *p; 433 char *endptr; 434 435 if ((len = strlen(str)) == 0) 436 return (0); 437 p = &str[len - 1]; 438 if (*p == 'C' || *p == 'F') { 439 temp = strtof(str, &endptr); 440 if (endptr == str || endptr != p) 441 return (0); 442 if (*p == 'F') 443 temp = (temp - 32) * 5 / 9; 444 kelv = temp * 10 + 2732; 445 } else { 446 kelv = (int)strtol(str, &endptr, 10); 447 if (endptr == str || *endptr != '\0') 448 return (0); 449 } 450 *val = kelv; 451 return (1); 452 } 453 454 /* 455 * These functions uses a presently undocumented interface to the kernel 456 * to walk the tree and get the type so it can print the value. 457 * This interface is under work and consideration, and should probably 458 * be killed with a big axe by the first person who can find the time. 459 * (be aware though, that the proper interface isn't as obvious as it 460 * may seem, there are various conflicting requirements. 461 */ 462 463 static int 464 name2oid(char *name, int *oidp) 465 { 466 int oid[2]; 467 int i; 468 size_t j; 469 470 oid[0] = 0; 471 oid[1] = 3; 472 473 j = CTL_MAXNAME * sizeof(int); 474 i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 475 if (i < 0) 476 return (i); 477 j /= sizeof(int); 478 return (j); 479 } 480 481 static int 482 oidfmt(int *oid, int len, char *fmt, u_int *kind) 483 { 484 int qoid[CTL_MAXNAME+2]; 485 u_char buf[BUFSIZ]; 486 int i; 487 size_t j; 488 489 qoid[0] = 0; 490 qoid[1] = 4; 491 memcpy(qoid + 2, oid, len * sizeof(int)); 492 493 j = sizeof(buf); 494 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 495 if (i) 496 err(1, "sysctl fmt %d %zu %d", i, j, errno); 497 498 if (kind) 499 *kind = *(u_int *)buf; 500 501 if (fmt) 502 strcpy(fmt, (char *)(buf + sizeof(u_int))); 503 return (0); 504 } 505 506 static int ctl_sign[CTLTYPE+1] = { 507 [CTLTYPE_INT] = 1, 508 [CTLTYPE_LONG] = 1, 509 [CTLTYPE_S64] = 1, 510 }; 511 512 static int ctl_size[CTLTYPE+1] = { 513 [CTLTYPE_INT] = sizeof(int), 514 [CTLTYPE_UINT] = sizeof(u_int), 515 [CTLTYPE_LONG] = sizeof(long), 516 [CTLTYPE_ULONG] = sizeof(u_long), 517 [CTLTYPE_S64] = sizeof(int64_t), 518 [CTLTYPE_U64] = sizeof(int64_t), 519 }; 520 521 /* 522 * This formats and outputs the value of one variable 523 * 524 * Returns zero if anything was actually output. 525 * Returns one if didn't know what to do with this. 526 * Return minus one if we had errors. 527 */ 528 static int 529 show_var(int *oid, int nlen) 530 { 531 u_char buf[BUFSIZ], *val, *oval, *p; 532 char name[BUFSIZ], *fmt; 533 const char *sep, *sep1; 534 int qoid[CTL_MAXNAME+2]; 535 uintmax_t umv; 536 intmax_t mv; 537 int i, hexlen, sign, ctltype; 538 size_t intlen; 539 size_t j, len; 540 u_int kind; 541 int (*func)(int, void *); 542 543 /* Silence GCC. */ 544 umv = mv = intlen = 0; 545 546 bzero(buf, BUFSIZ); 547 bzero(name, BUFSIZ); 548 qoid[0] = 0; 549 memcpy(qoid + 2, oid, nlen * sizeof(int)); 550 551 qoid[1] = 1; 552 j = sizeof(name); 553 i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 554 if (i || !j) 555 err(1, "sysctl name %d %zu %d", i, j, errno); 556 557 if (Nflag) { 558 printf("%s", name); 559 return (0); 560 } 561 562 if (eflag) 563 sep = "="; 564 else 565 sep = ": "; 566 567 if (dflag) { /* just print description */ 568 qoid[1] = 5; 569 j = sizeof(buf); 570 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 571 if (!nflag) 572 printf("%s%s", name, sep); 573 printf("%s", buf); 574 return (0); 575 } 576 /* find an estimate of how much we need for this var */ 577 j = 0; 578 i = sysctl(oid, nlen, 0, &j, 0, 0); 579 j += j; /* we want to be sure :-) */ 580 581 val = oval = malloc(j + 1); 582 if (val == NULL) { 583 warnx("malloc failed"); 584 return (1); 585 } 586 len = j; 587 i = sysctl(oid, nlen, val, &len, 0, 0); 588 if (i || !len) { 589 free(oval); 590 return (1); 591 } 592 593 if (bflag) { 594 fwrite(val, 1, len, stdout); 595 free(oval); 596 return (0); 597 } 598 val[len] = '\0'; 599 fmt = buf; 600 oidfmt(oid, nlen, fmt, &kind); 601 p = val; 602 ctltype = (kind & CTLTYPE); 603 sign = ctl_sign[ctltype]; 604 intlen = ctl_size[ctltype]; 605 606 switch (ctltype) { 607 case CTLTYPE_STRING: 608 if (!nflag) 609 printf("%s%s", name, sep); 610 printf("%.*s", (int)len, p); 611 free(oval); 612 return (0); 613 614 case CTLTYPE_INT: 615 case CTLTYPE_UINT: 616 case CTLTYPE_LONG: 617 case CTLTYPE_ULONG: 618 case CTLTYPE_S64: 619 case CTLTYPE_U64: 620 if (!nflag) 621 printf("%s%s", name, sep); 622 hexlen = 2 + (intlen * CHAR_BIT + 3) / 4; 623 sep1 = ""; 624 while (len >= intlen) { 625 switch (kind & CTLTYPE) { 626 case CTLTYPE_INT: 627 case CTLTYPE_UINT: 628 umv = *(u_int *)p; 629 mv = *(int *)p; 630 break; 631 case CTLTYPE_LONG: 632 case CTLTYPE_ULONG: 633 umv = *(u_long *)p; 634 mv = *(long *)p; 635 break; 636 case CTLTYPE_S64: 637 case CTLTYPE_U64: 638 umv = *(uint64_t *)p; 639 mv = *(int64_t *)p; 640 break; 641 } 642 fputs(sep1, stdout); 643 if (xflag) 644 printf("%#0*jx", hexlen, umv); 645 else if (!sign) 646 printf(hflag ? "%'ju" : "%ju", umv); 647 else if (fmt[1] == 'K') { 648 if (mv < 0) 649 printf("%jd", mv); 650 else 651 printf("%.1fC", (mv - 2732.0) / 10); 652 } else 653 printf(hflag ? "%'jd" : "%jd", mv); 654 sep1 = " "; 655 len -= intlen; 656 p += intlen; 657 } 658 free(oval); 659 return (0); 660 661 case CTLTYPE_OPAQUE: 662 i = 0; 663 if (strcmp(fmt, "S,clockinfo") == 0) 664 func = S_clockinfo; 665 else if (strcmp(fmt, "S,timeval") == 0) 666 func = S_timeval; 667 else if (strcmp(fmt, "S,loadavg") == 0) 668 func = S_loadavg; 669 else if (strcmp(fmt, "S,vmtotal") == 0) 670 func = S_vmtotal; 671 else 672 func = NULL; 673 if (func) { 674 if (!nflag) 675 printf("%s%s", name, sep); 676 i = (*func)(len, p); 677 free(oval); 678 return (i); 679 } 680 /* FALLTHROUGH */ 681 default: 682 if (!oflag && !xflag) { 683 free(oval); 684 return (1); 685 } 686 if (!nflag) 687 printf("%s%s", name, sep); 688 printf("Format:%s Length:%zu Dump:0x", fmt, len); 689 while (len-- && (xflag || p < val + 16)) 690 printf("%02x", *p++); 691 if (!xflag && len > 16) 692 printf("..."); 693 free(oval); 694 return (0); 695 } 696 free(oval); 697 return (1); 698 } 699 700 static int 701 sysctl_all(int *oid, int len) 702 { 703 int name1[22], name2[22]; 704 int i, j; 705 size_t l1, l2; 706 707 name1[0] = 0; 708 name1[1] = 2; 709 l1 = 2; 710 if (len) { 711 memcpy(name1+2, oid, len * sizeof(int)); 712 l1 += len; 713 } else { 714 name1[2] = 1; 715 l1++; 716 } 717 for (;;) { 718 l2 = sizeof(name2); 719 j = sysctl(name1, l1, name2, &l2, 0, 0); 720 if (j < 0) { 721 if (errno == ENOENT) 722 return (0); 723 else 724 err(1, "sysctl(getnext) %d %zu", j, l2); 725 } 726 727 l2 /= sizeof(int); 728 729 if (len < 0 || l2 < (unsigned int)len) 730 return (0); 731 732 for (i = 0; i < len; i++) 733 if (name2[i] != oid[i]) 734 return (0); 735 736 i = show_var(name2, l2); 737 if (!i && !bflag) 738 putchar('\n'); 739 740 memcpy(name1+2, name2, l2 * sizeof(int)); 741 l1 = 2 + l2; 742 } 743 } 744