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