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