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