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