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