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