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