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 #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 #ifdef __amd64__ 52 #include <sys/efi.h> 53 #include <machine/metadata.h> 54 #endif 55 56 #if defined(__amd64__) || defined(__i386__) 57 #include <machine/pc/bios.h> 58 #endif 59 60 #include <assert.h> 61 #include <ctype.h> 62 #include <err.h> 63 #include <errno.h> 64 #include <inttypes.h> 65 #include <locale.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 #include <sysexits.h> 70 #include <unistd.h> 71 72 static const char *conffile; 73 74 static int aflag, bflag, Bflag, dflag, eflag, hflag, iflag; 75 static int Nflag, nflag, oflag, qflag, Tflag, Wflag, xflag; 76 77 static int oidfmt(int *, int, char *, u_int *); 78 static int parsefile(const char *); 79 static int parse(const char *, int); 80 static int show_var(int *, int); 81 static int sysctl_all(int *oid, int len); 82 static int name2oid(const char *, int *); 83 84 static int strIKtoi(const char *, char **, const char *); 85 86 static int ctl_sign[CTLTYPE+1] = { 87 [CTLTYPE_INT] = 1, 88 [CTLTYPE_LONG] = 1, 89 [CTLTYPE_S64] = 1, 90 }; 91 92 static int ctl_size[CTLTYPE+1] = { 93 [CTLTYPE_U8] = sizeof(uint8_t), 94 [CTLTYPE_U16] = sizeof(uint16_t), 95 [CTLTYPE_INT] = sizeof(int), 96 [CTLTYPE_UINT] = sizeof(u_int), 97 [CTLTYPE_LONG] = sizeof(long), 98 [CTLTYPE_ULONG] = sizeof(u_long), 99 [CTLTYPE_S64] = sizeof(int64_t), 100 [CTLTYPE_U64] = sizeof(uint64_t), 101 }; 102 103 static const char *ctl_typename[CTLTYPE+1] = { 104 [CTLTYPE_U8] = "uint8_t", 105 [CTLTYPE_U16] = "uint16_t", 106 [CTLTYPE_INT] = "integer", 107 [CTLTYPE_UINT] = "unsigned integer", 108 [CTLTYPE_LONG] = "long integer", 109 [CTLTYPE_ULONG] = "unsigned long", 110 [CTLTYPE_S64] = "int64_t", 111 [CTLTYPE_U64] = "uint64_t", 112 }; 113 114 static void 115 usage(void) 116 { 117 118 (void)fprintf(stderr, "%s\n%s\n", 119 "usage: sysctl [-bdehiNnoqTWx] [ -B <bufsize> ] [-f filename] name[=value] ...", 120 " sysctl [-bdehNnoqTWx] [ -B <bufsize> ] -a"); 121 exit(1); 122 } 123 124 int 125 main(int argc, char **argv) 126 { 127 int ch; 128 int warncount = 0; 129 130 setlocale(LC_NUMERIC, ""); 131 setbuf(stdout,0); 132 setbuf(stderr,0); 133 134 while ((ch = getopt(argc, argv, "AabB:def:hiNnoqTwWxX")) != -1) { 135 switch (ch) { 136 case 'A': 137 /* compatibility */ 138 aflag = oflag = 1; 139 break; 140 case 'a': 141 aflag = 1; 142 break; 143 case 'b': 144 bflag = 1; 145 break; 146 case 'B': 147 Bflag = strtol(optarg, NULL, 0); 148 break; 149 case 'd': 150 dflag = 1; 151 break; 152 case 'e': 153 eflag = 1; 154 break; 155 case 'f': 156 conffile = optarg; 157 break; 158 case 'h': 159 hflag = 1; 160 break; 161 case 'i': 162 iflag = 1; 163 break; 164 case 'N': 165 Nflag = 1; 166 break; 167 case 'n': 168 nflag = 1; 169 break; 170 case 'o': 171 oflag = 1; 172 break; 173 case 'q': 174 qflag = 1; 175 break; 176 case 'T': 177 Tflag = 1; 178 break; 179 case 'w': 180 /* compatibility */ 181 /* ignored */ 182 break; 183 case 'W': 184 Wflag = 1; 185 break; 186 case 'X': 187 /* compatibility */ 188 aflag = xflag = 1; 189 break; 190 case 'x': 191 xflag = 1; 192 break; 193 default: 194 usage(); 195 } 196 } 197 argc -= optind; 198 argv += optind; 199 200 if (Nflag && nflag) 201 usage(); 202 if (aflag && argc == 0) 203 exit(sysctl_all(0, 0)); 204 if (argc == 0 && conffile == NULL) 205 usage(); 206 207 warncount = 0; 208 if (conffile != NULL) 209 warncount += parsefile(conffile); 210 211 while (argc-- > 0) 212 warncount += parse(*argv++, 0); 213 214 return (warncount); 215 } 216 217 /* 218 * Parse a name into a MIB entry. 219 * Lookup and print out the MIB entry if it exists. 220 * Set a new value if requested. 221 */ 222 static int 223 parse(const char *string, int lineno) 224 { 225 int len, i, j; 226 const void *newval; 227 const char *newvalstr = NULL; 228 uint8_t u8val; 229 uint16_t u16val; 230 int intval; 231 unsigned int uintval; 232 long longval; 233 unsigned long ulongval; 234 size_t newsize = Bflag; 235 int64_t i64val; 236 uint64_t u64val; 237 int mib[CTL_MAXNAME]; 238 char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ]; 239 u_int kind; 240 241 if (lineno) 242 snprintf(line, sizeof(line), " at line %d", lineno); 243 else 244 line[0] = '\0'; 245 246 cp = buf; 247 if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) { 248 warnx("oid too long: '%s'%s", string, line); 249 return (1); 250 } 251 bufp = strsep(&cp, "=:"); 252 if (cp != NULL) { 253 /* Tflag just lists tunables, do not allow assignment */ 254 if (Tflag || Wflag) { 255 warnx("Can't set variables when using -T or -W"); 256 usage(); 257 } 258 while (isspace(*cp)) 259 cp++; 260 /* Strip a pair of " or ' if any. */ 261 switch (*cp) { 262 case '\"': 263 case '\'': 264 if (cp[strlen(cp) - 1] == *cp) 265 cp[strlen(cp) - 1] = '\0'; 266 cp++; 267 } 268 newvalstr = cp; 269 newsize = strlen(cp); 270 } 271 /* Trim spaces */ 272 cp = bufp + strlen(bufp) - 1; 273 while (cp >= bufp && isspace((int)*cp)) { 274 *cp = '\0'; 275 cp--; 276 } 277 len = name2oid(bufp, mib); 278 279 if (len < 0) { 280 if (iflag) 281 return (0); 282 if (qflag) 283 return (1); 284 else { 285 if (errno == ENOENT) { 286 warnx("unknown oid '%s'%s", bufp, line); 287 } else { 288 warn("unknown oid '%s'%s", bufp, line); 289 } 290 return (1); 291 } 292 } 293 294 if (oidfmt(mib, len, fmt, &kind)) { 295 warn("couldn't find format of oid '%s'%s", bufp, line); 296 if (iflag) 297 return (1); 298 else 299 exit(1); 300 } 301 302 if (newvalstr == NULL || dflag) { 303 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 304 if (dflag) { 305 i = show_var(mib, len); 306 if (!i && !bflag) 307 putchar('\n'); 308 } 309 sysctl_all(mib, len); 310 } else { 311 i = show_var(mib, len); 312 if (!i && !bflag) 313 putchar('\n'); 314 } 315 } else { 316 if ((kind & CTLTYPE) == CTLTYPE_NODE) { 317 warnx("oid '%s' isn't a leaf node%s", bufp, line); 318 return (1); 319 } 320 321 if (!(kind & CTLFLAG_WR)) { 322 if (kind & CTLFLAG_TUN) { 323 warnx("oid '%s' is a read only tunable%s", bufp, line); 324 warnx("Tunable values are set in /boot/loader.conf"); 325 } else 326 warnx("oid '%s' is read only%s", bufp, line); 327 return (1); 328 } 329 330 switch (kind & CTLTYPE) { 331 case CTLTYPE_U8: 332 case CTLTYPE_U16: 333 case CTLTYPE_INT: 334 case CTLTYPE_UINT: 335 case CTLTYPE_LONG: 336 case CTLTYPE_ULONG: 337 case CTLTYPE_S64: 338 case CTLTYPE_U64: 339 if (strlen(newvalstr) == 0) { 340 warnx("empty numeric value"); 341 return (1); 342 } 343 /* FALLTHROUGH */ 344 case CTLTYPE_STRING: 345 break; 346 default: 347 warnx("oid '%s' is type %d," 348 " cannot set that%s", bufp, 349 kind & CTLTYPE, line); 350 return (1); 351 } 352 353 errno = 0; 354 355 switch (kind & CTLTYPE) { 356 case CTLTYPE_U8: 357 u8val = (uint8_t)strtoul(newvalstr, &endptr, 0); 358 newval = &u8val; 359 newsize = sizeof(u8val); 360 break; 361 case CTLTYPE_U16: 362 u16val = (uint16_t)strtoul(newvalstr, &endptr, 363 0); 364 newval = &u16val; 365 newsize = sizeof(u16val); 366 break; 367 case CTLTYPE_INT: 368 if (strncmp(fmt, "IK", 2) == 0) 369 intval = strIKtoi(newvalstr, &endptr, fmt); 370 else 371 intval = (int)strtol(newvalstr, &endptr, 372 0); 373 newval = &intval; 374 newsize = sizeof(intval); 375 break; 376 case CTLTYPE_UINT: 377 uintval = (int) strtoul(newvalstr, &endptr, 0); 378 newval = &uintval; 379 newsize = sizeof(uintval); 380 break; 381 case CTLTYPE_LONG: 382 longval = strtol(newvalstr, &endptr, 0); 383 newval = &longval; 384 newsize = sizeof(longval); 385 break; 386 case CTLTYPE_ULONG: 387 ulongval = strtoul(newvalstr, &endptr, 0); 388 newval = &ulongval; 389 newsize = sizeof(ulongval); 390 break; 391 case CTLTYPE_STRING: 392 newval = newvalstr; 393 break; 394 case CTLTYPE_S64: 395 i64val = strtoimax(newvalstr, &endptr, 0); 396 newval = &i64val; 397 newsize = sizeof(i64val); 398 break; 399 case CTLTYPE_U64: 400 u64val = strtoumax(newvalstr, &endptr, 0); 401 newval = &u64val; 402 newsize = sizeof(u64val); 403 break; 404 default: 405 /* NOTREACHED */ 406 abort(); 407 } 408 409 if (errno != 0 || endptr == newvalstr || 410 (endptr != NULL && *endptr != '\0')) { 411 warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE], 412 newvalstr, line); 413 return (1); 414 } 415 416 i = show_var(mib, len); 417 if (sysctl(mib, len, 0, 0, newval, newsize) == -1) { 418 if (!i && !bflag) 419 putchar('\n'); 420 switch (errno) { 421 case EOPNOTSUPP: 422 warnx("%s: value is not available%s", 423 string, line); 424 return (1); 425 case ENOTDIR: 426 warnx("%s: specification is incomplete%s", 427 string, line); 428 return (1); 429 case ENOMEM: 430 warnx("%s: type is unknown to this program%s", 431 string, line); 432 return (1); 433 default: 434 warn("%s%s", string, line); 435 return (1); 436 } 437 } 438 if (!bflag) 439 printf(" -> "); 440 i = nflag; 441 nflag = 1; 442 j = show_var(mib, len); 443 if (!j && !bflag) 444 putchar('\n'); 445 nflag = i; 446 } 447 448 return (0); 449 } 450 451 static int 452 parsefile(const char *filename) 453 { 454 FILE *file; 455 char line[BUFSIZ], *p, *pq, *pdq; 456 int warncount = 0, lineno = 0; 457 458 file = fopen(filename, "r"); 459 if (file == NULL) 460 err(EX_NOINPUT, "%s", filename); 461 while (fgets(line, sizeof(line), file) != NULL) { 462 lineno++; 463 p = line; 464 pq = strchr(line, '\''); 465 pdq = strchr(line, '\"'); 466 /* Replace the first # with \0. */ 467 while((p = strchr(p, '#')) != NULL) { 468 if (pq != NULL && p > pq) { 469 if ((p = strchr(pq+1, '\'')) != NULL) 470 *(++p) = '\0'; 471 break; 472 } else if (pdq != NULL && p > pdq) { 473 if ((p = strchr(pdq+1, '\"')) != NULL) 474 *(++p) = '\0'; 475 break; 476 } else if (p == line || *(p-1) != '\\') { 477 *p = '\0'; 478 break; 479 } 480 p++; 481 } 482 /* Trim spaces */ 483 p = line + strlen(line) - 1; 484 while (p >= line && isspace((int)*p)) { 485 *p = '\0'; 486 p--; 487 } 488 p = line; 489 while (isspace((int)*p)) 490 p++; 491 if (*p == '\0') 492 continue; 493 else 494 warncount += parse(p, lineno); 495 } 496 fclose(file); 497 498 return (warncount); 499 } 500 501 /* These functions will dump out various interesting structures. */ 502 503 static int 504 S_clockinfo(size_t l2, void *p) 505 { 506 struct clockinfo *ci = (struct clockinfo*)p; 507 508 if (l2 != sizeof(*ci)) { 509 warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci)); 510 return (1); 511 } 512 printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" : 513 "{ hz = %d, tick = %d, profhz = %d, stathz = %d }", 514 ci->hz, ci->tick, ci->profhz, ci->stathz); 515 return (0); 516 } 517 518 static int 519 S_loadavg(size_t l2, void *p) 520 { 521 struct loadavg *tv = (struct loadavg*)p; 522 523 if (l2 != sizeof(*tv)) { 524 warnx("S_loadavg %zu != %zu", l2, sizeof(*tv)); 525 return (1); 526 } 527 printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }", 528 (double)tv->ldavg[0]/(double)tv->fscale, 529 (double)tv->ldavg[1]/(double)tv->fscale, 530 (double)tv->ldavg[2]/(double)tv->fscale); 531 return (0); 532 } 533 534 static int 535 S_timeval(size_t l2, void *p) 536 { 537 struct timeval *tv = (struct timeval*)p; 538 time_t tv_sec; 539 char *p1, *p2; 540 541 if (l2 != sizeof(*tv)) { 542 warnx("S_timeval %zu != %zu", l2, sizeof(*tv)); 543 return (1); 544 } 545 printf(hflag ? "{ sec = %'jd, usec = %'ld } " : 546 "{ sec = %jd, usec = %ld } ", 547 (intmax_t)tv->tv_sec, tv->tv_usec); 548 tv_sec = tv->tv_sec; 549 p1 = strdup(ctime(&tv_sec)); 550 for (p2=p1; *p2 ; p2++) 551 if (*p2 == '\n') 552 *p2 = '\0'; 553 fputs(p1, stdout); 554 free(p1); 555 return (0); 556 } 557 558 static int 559 S_vmtotal(size_t l2, void *p) 560 { 561 struct vmtotal *v = (struct vmtotal *)p; 562 int pageKilo = getpagesize() / 1024; 563 564 if (l2 != sizeof(*v)) { 565 warnx("S_vmtotal %zu != %zu", l2, sizeof(*v)); 566 return (1); 567 } 568 569 printf( 570 "\nSystem wide totals computed every five seconds:" 571 " (values in kilobytes)\n"); 572 printf("===============================================\n"); 573 printf( 574 "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: " 575 "%hd Sleep: %hd)\n", 576 v->t_rq, v->t_dw, v->t_pw, v->t_sl); 577 printf( 578 "Virtual Memory:\t\t(Total: %dK Active: %dK)\n", 579 v->t_vm * pageKilo, v->t_avm * pageKilo); 580 printf("Real Memory:\t\t(Total: %dK Active: %dK)\n", 581 v->t_rm * pageKilo, v->t_arm * pageKilo); 582 printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n", 583 v->t_vmshr * pageKilo, v->t_avmshr * pageKilo); 584 printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n", 585 v->t_rmshr * pageKilo, v->t_armshr * pageKilo); 586 printf("Free Memory:\t%dK", v->t_free * pageKilo); 587 588 return (0); 589 } 590 591 #ifdef __amd64__ 592 #define efi_next_descriptor(ptr, size) \ 593 ((struct efi_md *)(((uint8_t *) ptr) + size)) 594 595 static int 596 S_efi_map(size_t l2, void *p) 597 { 598 struct efi_map_header *efihdr; 599 struct efi_md *map; 600 const char *type; 601 size_t efisz; 602 int ndesc, i; 603 604 static const char *types[] = { 605 "Reserved", 606 "LoaderCode", 607 "LoaderData", 608 "BootServicesCode", 609 "BootServicesData", 610 "RuntimeServicesCode", 611 "RuntimeServicesData", 612 "ConventionalMemory", 613 "UnusableMemory", 614 "ACPIReclaimMemory", 615 "ACPIMemoryNVS", 616 "MemoryMappedIO", 617 "MemoryMappedIOPortSpace", 618 "PalCode" 619 }; 620 621 /* 622 * Memory map data provided by UEFI via the GetMemoryMap 623 * Boot Services API. 624 */ 625 if (l2 < sizeof(*efihdr)) { 626 warnx("S_efi_map length less than header"); 627 return (1); 628 } 629 efihdr = p; 630 efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; 631 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 632 633 if (efihdr->descriptor_size == 0) 634 return (0); 635 if (l2 != efisz + efihdr->memory_size) { 636 warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz + 637 efihdr->memory_size); 638 return (1); 639 } 640 ndesc = efihdr->memory_size / efihdr->descriptor_size; 641 642 printf("\n%23s %12s %12s %8s %4s", 643 "Type", "Physical", "Virtual", "#Pages", "Attr"); 644 645 for (i = 0; i < ndesc; i++, 646 map = efi_next_descriptor(map, efihdr->descriptor_size)) { 647 if (map->md_type <= EFI_MD_TYPE_PALCODE) 648 type = types[map->md_type]; 649 else 650 type = "<INVALID>"; 651 printf("\n%23s %012lx %12p %08lx ", type, map->md_phys, 652 map->md_virt, map->md_pages); 653 if (map->md_attr & EFI_MD_ATTR_UC) 654 printf("UC "); 655 if (map->md_attr & EFI_MD_ATTR_WC) 656 printf("WC "); 657 if (map->md_attr & EFI_MD_ATTR_WT) 658 printf("WT "); 659 if (map->md_attr & EFI_MD_ATTR_WB) 660 printf("WB "); 661 if (map->md_attr & EFI_MD_ATTR_UCE) 662 printf("UCE "); 663 if (map->md_attr & EFI_MD_ATTR_WP) 664 printf("WP "); 665 if (map->md_attr & EFI_MD_ATTR_RP) 666 printf("RP "); 667 if (map->md_attr & EFI_MD_ATTR_XP) 668 printf("XP "); 669 if (map->md_attr & EFI_MD_ATTR_RT) 670 printf("RUNTIME"); 671 } 672 return (0); 673 } 674 #endif 675 676 #if defined(__amd64__) || defined(__i386__) 677 static int 678 S_bios_smap_xattr(size_t l2, void *p) 679 { 680 struct bios_smap_xattr *smap, *end; 681 682 if (l2 % sizeof(*smap) != 0) { 683 warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2, 684 sizeof(*smap)); 685 return (1); 686 } 687 688 end = (struct bios_smap_xattr *)((char *)p + l2); 689 for (smap = p; smap < end; smap++) 690 printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx", 691 smap->type, smap->xattr, (uintmax_t)smap->base, 692 (uintmax_t)smap->length); 693 return (0); 694 } 695 #endif 696 697 static int 698 strIKtoi(const char *str, char **endptrp, const char *fmt) 699 { 700 int kelv; 701 float temp; 702 size_t len; 703 const char *p; 704 int prec, i; 705 706 assert(errno == 0); 707 708 len = strlen(str); 709 /* caller already checked this */ 710 assert(len > 0); 711 712 /* 713 * A format of "IK" is in deciKelvin. A format of "IK3" is in 714 * milliKelvin. The single digit following IK is log10 of the 715 * multiplying factor to convert Kelvin into the untis of this sysctl, 716 * or the dividing factor to convert the sysctl value to Kelvin. Numbers 717 * larger than 6 will run into precision issues with 32-bit integers. 718 * Characters that aren't ASCII digits after the 'K' are ignored. No 719 * localization is present because this is an interface from the kernel 720 * to this program (eg not an end-user interface), so isdigit() isn't 721 * used here. 722 */ 723 if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9') 724 prec = fmt[2] - '0'; 725 else 726 prec = 1; 727 p = &str[len - 1]; 728 if (*p == 'C' || *p == 'F' || *p == 'K') { 729 temp = strtof(str, endptrp); 730 if (*endptrp != str && *endptrp == p && errno == 0) { 731 if (*p == 'F') 732 temp = (temp - 32) * 5 / 9; 733 *endptrp = NULL; 734 if (*p != 'K') 735 temp += 273.15; 736 for (i = 0; i < prec; i++) 737 temp *= 10.0; 738 return ((int)(temp + 0.5)); 739 } 740 } else { 741 /* No unit specified -> treat it as a raw number */ 742 kelv = (int)strtol(str, endptrp, 10); 743 if (*endptrp != str && *endptrp == p && errno == 0) { 744 *endptrp = NULL; 745 return (kelv); 746 } 747 } 748 749 errno = ERANGE; 750 return (0); 751 } 752 753 /* 754 * These functions uses a presently undocumented interface to the kernel 755 * to walk the tree and get the type so it can print the value. 756 * This interface is under work and consideration, and should probably 757 * be killed with a big axe by the first person who can find the time. 758 * (be aware though, that the proper interface isn't as obvious as it 759 * may seem, there are various conflicting requirements. 760 */ 761 762 static int 763 name2oid(const char *name, int *oidp) 764 { 765 int oid[2]; 766 int i; 767 size_t j; 768 769 oid[0] = 0; 770 oid[1] = 3; 771 772 j = CTL_MAXNAME * sizeof(int); 773 i = sysctl(oid, 2, oidp, &j, name, strlen(name)); 774 if (i < 0) 775 return (i); 776 j /= sizeof(int); 777 return (j); 778 } 779 780 static int 781 oidfmt(int *oid, int len, char *fmt, u_int *kind) 782 { 783 int qoid[CTL_MAXNAME+2]; 784 u_char buf[BUFSIZ]; 785 int i; 786 size_t j; 787 788 qoid[0] = 0; 789 qoid[1] = 4; 790 memcpy(qoid + 2, oid, len * sizeof(int)); 791 792 j = sizeof(buf); 793 i = sysctl(qoid, len + 2, buf, &j, 0, 0); 794 if (i) 795 err(1, "sysctl fmt %d %zu %d", i, j, errno); 796 797 if (kind) 798 *kind = *(u_int *)buf; 799 800 if (fmt) 801 strcpy(fmt, (char *)(buf + sizeof(u_int))); 802 return (0); 803 } 804 805 /* 806 * This formats and outputs the value of one variable 807 * 808 * Returns zero if anything was actually output. 809 * Returns one if didn't know what to do with this. 810 * Return minus one if we had errors. 811 */ 812 static int 813 show_var(int *oid, int nlen) 814 { 815 u_char buf[BUFSIZ], *val, *oval, *p; 816 char name[BUFSIZ], fmt[BUFSIZ]; 817 const char *sep, *sep1; 818 int qoid[CTL_MAXNAME+2]; 819 uintmax_t umv; 820 intmax_t mv; 821 int i, hexlen, sign, ctltype; 822 size_t intlen; 823 size_t j, len; 824 u_int kind; 825 float base; 826 int (*func)(size_t, void *); 827 int prec; 828 829 /* Silence GCC. */ 830 umv = mv = intlen = 0; 831 832 bzero(buf, BUFSIZ); 833 bzero(fmt, BUFSIZ); 834 bzero(name, BUFSIZ); 835 qoid[0] = 0; 836 memcpy(qoid + 2, oid, nlen * sizeof(int)); 837 838 qoid[1] = 1; 839 j = sizeof(name); 840 i = sysctl(qoid, nlen + 2, name, &j, 0, 0); 841 if (i || !j) 842 err(1, "sysctl name %d %zu %d", i, j, errno); 843 844 oidfmt(oid, nlen, fmt, &kind); 845 /* if Wflag then only list sysctls that are writeable and not stats. */ 846 if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0)) 847 return 1; 848 849 /* if Tflag then only list sysctls that are tuneables. */ 850 if (Tflag && (kind & CTLFLAG_TUN) == 0) 851 return 1; 852 853 if (Nflag) { 854 printf("%s", name); 855 return (0); 856 } 857 858 if (eflag) 859 sep = "="; 860 else 861 sep = ": "; 862 863 if (dflag) { /* just print description */ 864 qoid[1] = 5; 865 j = sizeof(buf); 866 i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); 867 if (!nflag) 868 printf("%s%s", name, sep); 869 printf("%s", buf); 870 return (0); 871 } 872 /* find an estimate of how much we need for this var */ 873 if (Bflag) 874 j = Bflag; 875 else { 876 j = 0; 877 i = sysctl(oid, nlen, 0, &j, 0, 0); 878 j += j; /* we want to be sure :-) */ 879 } 880 881 val = oval = malloc(j + 1); 882 if (val == NULL) { 883 warnx("malloc failed"); 884 return (1); 885 } 886 ctltype = (kind & CTLTYPE); 887 len = j; 888 i = sysctl(oid, nlen, val, &len, 0, 0); 889 if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) { 890 free(oval); 891 return (1); 892 } 893 894 if (bflag) { 895 fwrite(val, 1, len, stdout); 896 free(oval); 897 return (0); 898 } 899 val[len] = '\0'; 900 p = val; 901 sign = ctl_sign[ctltype]; 902 intlen = ctl_size[ctltype]; 903 904 switch (ctltype) { 905 case CTLTYPE_STRING: 906 if (!nflag) 907 printf("%s%s", name, sep); 908 printf("%.*s", (int)len, p); 909 free(oval); 910 return (0); 911 912 case CTLTYPE_U8: 913 case CTLTYPE_U16: 914 case CTLTYPE_INT: 915 case CTLTYPE_UINT: 916 case CTLTYPE_LONG: 917 case CTLTYPE_ULONG: 918 case CTLTYPE_S64: 919 case CTLTYPE_U64: 920 if (!nflag) 921 printf("%s%s", name, sep); 922 hexlen = 2 + (intlen * CHAR_BIT + 3) / 4; 923 sep1 = ""; 924 while (len >= intlen) { 925 switch (kind & CTLTYPE) { 926 case CTLTYPE_U8: 927 umv = *(uint8_t *)p; 928 mv = *(int8_t *)p; 929 break; 930 case CTLTYPE_U16: 931 umv = *(uint16_t *)p; 932 mv = *(int16_t *)p; 933 break; 934 case CTLTYPE_INT: 935 case CTLTYPE_UINT: 936 umv = *(u_int *)p; 937 mv = *(int *)p; 938 break; 939 case CTLTYPE_LONG: 940 case CTLTYPE_ULONG: 941 umv = *(u_long *)p; 942 mv = *(long *)p; 943 break; 944 case CTLTYPE_S64: 945 case CTLTYPE_U64: 946 umv = *(uint64_t *)p; 947 mv = *(int64_t *)p; 948 break; 949 } 950 fputs(sep1, stdout); 951 if (xflag) 952 printf("%#0*jx", hexlen, umv); 953 else if (!sign) 954 printf(hflag ? "%'ju" : "%ju", umv); 955 else if (fmt[1] == 'K') { 956 if (mv < 0) 957 printf("%jd", mv); 958 else { 959 /* 960 * See strIKtoi for details on fmt. 961 */ 962 prec = 1; 963 if (fmt[2] != '\0') 964 prec = fmt[2] - '0'; 965 base = 1.0; 966 for (int i = 0; i < prec; i++) 967 base *= 10.0; 968 printf("%.*fC", prec, 969 (float)mv / base - 273.15); 970 } 971 } else 972 printf(hflag ? "%'jd" : "%jd", mv); 973 sep1 = " "; 974 len -= intlen; 975 p += intlen; 976 } 977 free(oval); 978 return (0); 979 980 case CTLTYPE_OPAQUE: 981 i = 0; 982 if (strcmp(fmt, "S,clockinfo") == 0) 983 func = S_clockinfo; 984 else if (strcmp(fmt, "S,timeval") == 0) 985 func = S_timeval; 986 else if (strcmp(fmt, "S,loadavg") == 0) 987 func = S_loadavg; 988 else if (strcmp(fmt, "S,vmtotal") == 0) 989 func = S_vmtotal; 990 #ifdef __amd64__ 991 else if (strcmp(fmt, "S,efi_map_header") == 0) 992 func = S_efi_map; 993 #endif 994 #if defined(__amd64__) || defined(__i386__) 995 else if (strcmp(fmt, "S,bios_smap_xattr") == 0) 996 func = S_bios_smap_xattr; 997 #endif 998 else 999 func = NULL; 1000 if (func) { 1001 if (!nflag) 1002 printf("%s%s", name, sep); 1003 i = (*func)(len, p); 1004 free(oval); 1005 return (i); 1006 } 1007 /* FALLTHROUGH */ 1008 default: 1009 if (!oflag && !xflag) { 1010 free(oval); 1011 return (1); 1012 } 1013 if (!nflag) 1014 printf("%s%s", name, sep); 1015 printf("Format:%s Length:%zu Dump:0x", fmt, len); 1016 while (len-- && (xflag || p < val + 16)) 1017 printf("%02x", *p++); 1018 if (!xflag && len > 16) 1019 printf("..."); 1020 free(oval); 1021 return (0); 1022 } 1023 free(oval); 1024 return (1); 1025 } 1026 1027 static int 1028 sysctl_all(int *oid, int len) 1029 { 1030 int name1[22], name2[22]; 1031 int i, j; 1032 size_t l1, l2; 1033 1034 name1[0] = 0; 1035 name1[1] = 2; 1036 l1 = 2; 1037 if (len) { 1038 memcpy(name1+2, oid, len * sizeof(int)); 1039 l1 += len; 1040 } else { 1041 name1[2] = 1; 1042 l1++; 1043 } 1044 for (;;) { 1045 l2 = sizeof(name2); 1046 j = sysctl(name1, l1, name2, &l2, 0, 0); 1047 if (j < 0) { 1048 if (errno == ENOENT) 1049 return (0); 1050 else 1051 err(1, "sysctl(getnext) %d %zu", j, l2); 1052 } 1053 1054 l2 /= sizeof(int); 1055 1056 if (len < 0 || l2 < (unsigned int)len) 1057 return (0); 1058 1059 for (i = 0; i < len; i++) 1060 if (name2[i] != oid[i]) 1061 return (0); 1062 1063 i = show_var(name2, l2); 1064 if (!i && !bflag) 1065 putchar('\n'); 1066 1067 memcpy(name1+2, name2, l2 * sizeof(int)); 1068 l1 = 2 + l2; 1069 } 1070 } 1071