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