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