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