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