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