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