1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 OmniTI Computer Consulting, Inc.  All rights reserved.
  24  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 #include <sys/sysmacros.h>
  29 #include <sys/param.h>
  30 
  31 #include <smbios.h>
  32 #include <alloca.h>
  33 #include <limits.h>
  34 #include <unistd.h>
  35 #include <strings.h>
  36 #include <stdlib.h>
  37 #include <stdarg.h>
  38 #include <stdio.h>
  39 #include <fcntl.h>
  40 #include <errno.h>
  41 #include <ctype.h>
  42 
  43 #define SMBIOS_SUCCESS  0
  44 #define SMBIOS_ERROR    1
  45 #define SMBIOS_USAGE    2
  46 
  47 static const char *g_pname;
  48 static int g_hdr;
  49 
  50 static int opt_e;
  51 static int opt_i = -1;
  52 static int opt_O;
  53 static int opt_s;
  54 static int opt_t = -1;
  55 static int opt_x;
  56 
  57 /*PRINTFLIKE2*/
  58 static void
  59 oprintf(FILE *fp, const char *format, ...)
  60 {
  61         va_list ap;
  62 
  63         va_start(ap, format);
  64         (void) vfprintf(fp, format, ap);
  65         va_end(ap);
  66 }
  67 
  68 /*PRINTFLIKE3*/
  69 static void
  70 desc_printf(const char *d, FILE *fp, const char *format, ...)
  71 {
  72         va_list ap;
  73 
  74         va_start(ap, format);
  75         (void) vfprintf(fp, format, ap);
  76         va_end(ap);
  77 
  78         if (d != NULL)
  79                 (void) fprintf(fp, " (%s)\n", d);
  80         else
  81                 (void) fprintf(fp, "\n");
  82 }
  83 
  84 static void
  85 flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
  86     const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
  87 {
  88         size_t i;
  89 
  90         oprintf(fp, "  %s: 0x%x\n", s, flags);
  91 
  92         for (i = 0; i < bits; i++) {
  93                 uint_t f = 1 << i;
  94                 const char *n;
  95 
  96                 if (!(flags & f))
  97                         continue;
  98 
  99                 if ((n = flag_name(f)) != NULL)
 100                         desc_printf(flag_desc(f), fp, "\t%s", n);
 101                 else
 102                         desc_printf(flag_desc(f), fp, "\t0x%x", f);
 103         }
 104 }
 105 
 106 static void
 107 flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
 108     const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
 109 {
 110         size_t i;
 111 
 112         oprintf(fp, "  %s: 0x%llx\n", s, (u_longlong_t)flags);
 113 
 114         for (i = 0; i < bits; i++) {
 115                 u_longlong_t f = 1ULL << i;
 116                 const char *n;
 117 
 118                 if (!(flags & f))
 119                         continue;
 120 
 121                 if ((n = flag_name(f)) != NULL)
 122                         desc_printf(flag_desc(f), fp, "\t%s", n);
 123                 else
 124                         desc_printf(flag_desc(f), fp, "\t0x%llx", f);
 125         }
 126 }
 127 
 128 static void
 129 id_printf(FILE *fp, const char *s, id_t id)
 130 {
 131         switch (id) {
 132         case SMB_ID_NONE:
 133                 oprintf(fp, "%sNone\n", s);
 134                 break;
 135         case SMB_ID_NOTSUP:
 136                 oprintf(fp, "%sNot Supported\n", s);
 137                 break;
 138         default:
 139                 oprintf(fp, "%s%u\n", s, (uint_t)id);
 140         }
 141 }
 142 
 143 static int
 144 check_oem(smbios_hdl_t *shp)
 145 {
 146         int i;
 147         int cnt;
 148         int rv;
 149         id_t oem_id;
 150         smbios_struct_t s;
 151         const char **oem_str;
 152 
 153         rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
 154         if (rv != 0) {
 155                 return (-1);
 156         }
 157 
 158         oem_id = s.smbstr_id;
 159 
 160         cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
 161         if (cnt > 0) {
 162                 oem_str =  alloca(sizeof (char *) * cnt);
 163                 (void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
 164 
 165                 for (i = 0; i < cnt; i++) {
 166                         if (strncmp(oem_str[i], SMB_PRMS1,
 167                             strlen(SMB_PRMS1) + 1) == 0) {
 168                                 return (0);
 169                         }
 170                 }
 171         }
 172 
 173         return (-1);
 174 }
 175 
 176 static void
 177 print_smbios(smbios_hdl_t *shp, FILE *fp)
 178 {
 179         smbios_entry_t ep;
 180         int i;
 181 
 182         smbios_info_smbios(shp, &ep);
 183 
 184         oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
 185             (int)sizeof (ep.smbe_eanchor), (int)sizeof (ep.smbe_eanchor),
 186             ep.smbe_eanchor);
 187 
 188         oprintf(fp, "Entry Point Checksum: 0x%x\n", ep.smbe_ecksum);
 189         oprintf(fp, "Entry Point Length: %u\n", ep.smbe_elen);
 190         oprintf(fp, "Entry Point Version: %u.%u\n",
 191             ep.smbe_major, ep.smbe_minor);
 192         oprintf(fp, "Max Structure Size: %u\n", ep.smbe_maxssize);
 193         oprintf(fp, "Entry Point Revision: 0x%x\n", ep.smbe_revision);
 194 
 195         oprintf(fp, "Entry Point Revision Data:");
 196         for (i = 0; i < sizeof (ep.smbe_format); i++)
 197                 oprintf(fp, " 0x%02x", ep.smbe_format[i]);
 198         oprintf(fp, "\n");
 199 
 200         oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
 201             (int)sizeof (ep.smbe_ianchor), (int)sizeof (ep.smbe_ianchor),
 202             ep.smbe_ianchor);
 203 
 204         oprintf(fp, "Intermediate Checksum: 0x%x\n", ep.smbe_icksum);
 205         oprintf(fp, "Structure Table Length: %u\n", ep.smbe_stlen);
 206         oprintf(fp, "Structure Table Address: 0x%x\n", ep.smbe_staddr);
 207         oprintf(fp, "Structure Table Entries: %u\n", ep.smbe_stnum);
 208         oprintf(fp, "DMI BCD Revision: 0x%x\n", ep.smbe_bcdrev);
 209 }
 210 
 211 static void
 212 print_common(const smbios_info_t *ip, FILE *fp)
 213 {
 214         if (ip->smbi_manufacturer[0] != '\0')
 215                 oprintf(fp, "  Manufacturer: %s\n", ip->smbi_manufacturer);
 216         if (ip->smbi_product[0] != '\0')
 217                 oprintf(fp, "  Product: %s\n", ip->smbi_product);
 218         if (ip->smbi_version[0] != '\0')
 219                 oprintf(fp, "  Version: %s\n", ip->smbi_version);
 220         if (ip->smbi_serial[0] != '\0')
 221                 oprintf(fp, "  Serial Number: %s\n", ip->smbi_serial);
 222         if (ip->smbi_asset[0] != '\0')
 223                 oprintf(fp, "  Asset Tag: %s\n", ip->smbi_asset);
 224         if (ip->smbi_location[0] != '\0')
 225                 oprintf(fp, "  Location Tag: %s\n", ip->smbi_location);
 226         if (ip->smbi_part[0] != '\0')
 227                 oprintf(fp, "  Part Number: %s\n", ip->smbi_part);
 228 }
 229 
 230 static void
 231 print_bios(smbios_hdl_t *shp, FILE *fp)
 232 {
 233         smbios_bios_t b;
 234 
 235         (void) smbios_info_bios(shp, &b);
 236 
 237         oprintf(fp, "  Vendor: %s\n", b.smbb_vendor);
 238         oprintf(fp, "  Version String: %s\n", b.smbb_version);
 239         oprintf(fp, "  Release Date: %s\n", b.smbb_reldate);
 240         oprintf(fp, "  Address Segment: 0x%x\n", b.smbb_segment);
 241         oprintf(fp, "  ROM Size: %u bytes\n", b.smbb_romsize);
 242         oprintf(fp, "  Image Size: %u bytes\n", b.smbb_runsize);
 243 
 244         flag64_printf(fp, "Characteristics",
 245             b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
 246             smbios_bios_flag_name, smbios_bios_flag_desc);
 247 
 248         if (b.smbb_nxcflags > SMB_BIOSXB_1) {
 249                 flag_printf(fp, "Characteristics Extension Byte 1",
 250                     b.smbb_xcflags[SMB_BIOSXB_1],
 251                     sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
 252                     smbios_bios_xb1_name, smbios_bios_xb1_desc);
 253         }
 254 
 255         if (b.smbb_nxcflags > SMB_BIOSXB_2) {
 256                 flag_printf(fp, "Characteristics Extension Byte 2",
 257                     b.smbb_xcflags[SMB_BIOSXB_2],
 258                     sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
 259                     smbios_bios_xb2_name, smbios_bios_xb2_desc);
 260         }
 261 
 262         if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
 263                 oprintf(fp, "  Version Number: %u.%u\n",
 264                     b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
 265         }
 266 
 267         if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN) {
 268                 oprintf(fp, "  Embedded Ctlr Firmware Version Number: %u.%u\n",
 269                     b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
 270         }
 271 }
 272 
 273 static void
 274 print_system(smbios_hdl_t *shp, FILE *fp)
 275 {
 276         smbios_system_t s;
 277         uint_t i;
 278 
 279         (void) smbios_info_system(shp, &s);
 280 
 281         oprintf(fp, "  UUID: ");
 282         for (i = 0; i < s.smbs_uuidlen; i++) {
 283                 oprintf(fp, "%02x", s.smbs_uuid[i]);
 284                 if (i == 3 || i == 5 || i == 7 || i == 9)
 285                         oprintf(fp, "-");
 286         }
 287         oprintf(fp, "\n");
 288 
 289         desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
 290             fp, "  Wake-Up Event: 0x%x", s.smbs_wakeup);
 291 
 292         oprintf(fp, "  SKU Number: %s\n", s.smbs_sku);
 293         oprintf(fp, "  Family: %s\n", s.smbs_family);
 294 }
 295 
 296 static void
 297 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
 298 {
 299         smbios_bboard_t b;
 300         int chdl_cnt;
 301 
 302         (void) smbios_info_bboard(shp, id, &b);
 303 
 304         oprintf(fp, "  Chassis: %u\n", (uint_t)b.smbb_chassis);
 305 
 306         flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
 307             smbios_bboard_flag_name, smbios_bboard_flag_desc);
 308 
 309         desc_printf(smbios_bboard_type_desc(b.smbb_type),
 310             fp, "  Board Type: 0x%x", b.smbb_type);
 311 
 312         chdl_cnt = b.smbb_contn;
 313         if (chdl_cnt != 0) {
 314                 id_t *chdl;
 315                 uint16_t hdl;
 316                 int i, n, cnt;
 317 
 318                 chdl = alloca(chdl_cnt * sizeof (id_t));
 319                 cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
 320                 if (cnt > SMB_CONT_MAX)
 321                         return;
 322                 n = MIN(chdl_cnt, cnt);
 323 
 324                 oprintf(fp, "\n");
 325                 for (i = 0; i < n; i++) {
 326                         hdl = (uint16_t)chdl[i];
 327                         oprintf(fp, "  Contained Handle: %u\n", hdl);
 328                 }
 329         }
 330 }
 331 
 332 static void
 333 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
 334 {
 335         smbios_chassis_t c;
 336         int elem_cnt;
 337 
 338         (void) smbios_info_chassis(shp, id, &c);
 339 
 340         oprintf(fp, "  OEM Data: 0x%x\n", c.smbc_oemdata);
 341         oprintf(fp, "  SKU number: %s\n",
 342             c.smbc_sku == NULL ? "<unknown>" : c.smbc_sku);
 343         oprintf(fp, "  Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
 344 
 345         desc_printf(smbios_chassis_type_desc(c.smbc_type),
 346             fp, "  Chassis Type: 0x%x", c.smbc_type);
 347 
 348         desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
 349             fp, "  Boot-Up State: 0x%x", c.smbc_bustate);
 350 
 351         desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
 352             fp, "  Power Supply State: 0x%x", c.smbc_psstate);
 353 
 354         desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
 355             fp, "  Thermal State: 0x%x", c.smbc_thstate);
 356 
 357         oprintf(fp, "  Chassis Height: %uu\n", c.smbc_uheight);
 358         oprintf(fp, "  Power Cords: %u\n", c.smbc_cords);
 359 
 360         elem_cnt = c.smbc_elems;
 361         oprintf(fp, "  Element Records: %u\n", elem_cnt);
 362 
 363         if (elem_cnt > 0) {
 364                 id_t *elems;
 365                 uint8_t type;
 366                 int i, n, cnt;
 367 
 368                 elems = alloca(c.smbc_elems * sizeof (id_t));
 369                 cnt = smbios_info_contains(shp, id, elem_cnt, elems);
 370                 if (cnt > SMB_CONT_MAX)
 371                         return;
 372                 n = MIN(elem_cnt, cnt);
 373 
 374                 oprintf(fp, "\n");
 375                 for (i = 0; i < n; i++) {
 376                         type = (uint8_t)elems[i];
 377                         if (type & 0x80) {
 378                                 /* SMBIOS structrure Type */
 379                                 desc_printf(smbios_type_name(type & 0x7f), fp,
 380                                     "  Contained SMBIOS structure Type: %u",
 381                                     type & 0x80);
 382                         } else {
 383                                 /* SMBIOS Base Board Type */
 384                                 desc_printf(smbios_bboard_type_desc(type), fp,
 385                                     "  Contained SMBIOS Base Board Type: 0x%x",
 386                                     type);
 387                         }
 388                 }
 389         }
 390 }
 391 
 392 static void
 393 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
 394 {
 395         smbios_processor_t p;
 396         uint_t status;
 397 
 398         (void) smbios_info_processor(shp, id, &p);
 399         status = SMB_PRSTATUS_STATUS(p.smbp_status);
 400 
 401         desc_printf(smbios_processor_family_desc(p.smbp_family),
 402             fp, "  Family: %u", p.smbp_family);
 403 
 404         if (p.smbp_family2 != 0)
 405                 desc_printf(smbios_processor_family_desc(p.smbp_family2),
 406                     fp, "  Family Ext: %u", p.smbp_family2);
 407 
 408         oprintf(fp, "  CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
 409 
 410         desc_printf(smbios_processor_type_desc(p.smbp_type),
 411             fp, "  Type: %u", p.smbp_type);
 412 
 413         desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
 414             fp, "  Socket Upgrade: %u", p.smbp_upgrade);
 415 
 416         oprintf(fp, "  Socket Status: %s\n",
 417             SMB_PRSTATUS_PRESENT(p.smbp_status) ?
 418             "Populated" : "Not Populated");
 419 
 420         desc_printf(smbios_processor_status_desc(status),
 421             fp, "  Processor Status: %u", status);
 422 
 423         if (SMB_PRV_LEGACY(p.smbp_voltage)) {
 424                 oprintf(fp, "  Supported Voltages:");
 425                 switch (p.smbp_voltage) {
 426                 case SMB_PRV_5V:
 427                         oprintf(fp, " 5.0V");
 428                         break;
 429                 case SMB_PRV_33V:
 430                         oprintf(fp, " 3.3V");
 431                         break;
 432                 case SMB_PRV_29V:
 433                         oprintf(fp, " 2.9V");
 434                         break;
 435                 }
 436                 oprintf(fp, "\n");
 437         } else {
 438                 oprintf(fp, "  Supported Voltages: %.1fV\n",
 439                     (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
 440         }
 441 
 442         if (p.smbp_corecount != 0)
 443                 oprintf(fp, "  Core Count: %u\n", p.smbp_corecount);
 444         else
 445                 oprintf(fp, "  Core Count: Unknown\n");
 446 
 447         if (p.smbp_coresenabled != 0)
 448                 oprintf(fp, "  Cores Enabled: %u\n", p.smbp_coresenabled);
 449         else
 450                 oprintf(fp, "  Cores Enabled: Unknown\n");
 451 
 452         if (p.smbp_threadcount != 0)
 453                 oprintf(fp, "  Thread Count: %u\n", p.smbp_threadcount);
 454         else
 455                 oprintf(fp, "  Thread Count: Unknown\n");
 456 
 457         if (p.smbp_cflags) {
 458                 flag_printf(fp, "Processor Characteristics",
 459                     p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
 460                     smbios_processor_core_flag_name,
 461                     smbios_processor_core_flag_desc);
 462         }
 463 
 464         if (p.smbp_clkspeed != 0)
 465                 oprintf(fp, "  External Clock Speed: %uMHz\n", p.smbp_clkspeed);
 466         else
 467                 oprintf(fp, "  External Clock Speed: Unknown\n");
 468 
 469         if (p.smbp_maxspeed != 0)
 470                 oprintf(fp, "  Maximum Speed: %uMHz\n", p.smbp_maxspeed);
 471         else
 472                 oprintf(fp, "  Maximum Speed: Unknown\n");
 473 
 474         if (p.smbp_curspeed != 0)
 475                 oprintf(fp, "  Current Speed: %uMHz\n", p.smbp_curspeed);
 476         else
 477                 oprintf(fp, "  Current Speed: Unknown\n");
 478 
 479         id_printf(fp, "  L1 Cache: ", p.smbp_l1cache);
 480         id_printf(fp, "  L2 Cache: ", p.smbp_l2cache);
 481         id_printf(fp, "  L3 Cache: ", p.smbp_l3cache);
 482 }
 483 
 484 static void
 485 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
 486 {
 487         smbios_cache_t c;
 488 
 489         (void) smbios_info_cache(shp, id, &c);
 490 
 491         oprintf(fp, "  Level: %u\n", c.smba_level);
 492         oprintf(fp, "  Maximum Installed Size: %u bytes\n", c.smba_maxsize);
 493 
 494         if (c.smba_size != 0)
 495                 oprintf(fp, "  Installed Size: %u bytes\n", c.smba_size);
 496         else
 497                 oprintf(fp, "  Installed Size: Not Installed\n");
 498 
 499         if (c.smba_speed != 0)
 500                 oprintf(fp, "  Speed: %uns\n", c.smba_speed);
 501         else
 502                 oprintf(fp, "  Speed: Unknown\n");
 503 
 504         flag_printf(fp, "Supported SRAM Types",
 505             c.smba_stype, sizeof (c.smba_stype) * NBBY,
 506             smbios_cache_ctype_name, smbios_cache_ctype_desc);
 507 
 508         desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
 509             fp, "  Current SRAM Type: 0x%x", c.smba_ctype);
 510 
 511         desc_printf(smbios_cache_ecc_desc(c.smba_etype),
 512             fp, "  Error Correction Type: %u", c.smba_etype);
 513 
 514         desc_printf(smbios_cache_logical_desc(c.smba_ltype),
 515             fp, "  Logical Cache Type: %u", c.smba_ltype);
 516 
 517         desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
 518             fp, "  Associativity: %u", c.smba_assoc);
 519 
 520         desc_printf(smbios_cache_mode_desc(c.smba_mode),
 521             fp, "  Mode: %u", c.smba_mode);
 522 
 523         desc_printf(smbios_cache_loc_desc(c.smba_location),
 524             fp, "  Location: %u", c.smba_location);
 525 
 526         flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
 527             smbios_cache_flag_name, smbios_cache_flag_desc);
 528 }
 529 
 530 static void
 531 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
 532 {
 533         smbios_port_t p;
 534 
 535         (void) smbios_info_port(shp, id, &p);
 536 
 537         oprintf(fp, "  Internal Reference Designator: %s\n", p.smbo_iref);
 538         oprintf(fp, "  External Reference Designator: %s\n", p.smbo_eref);
 539 
 540         desc_printf(smbios_port_conn_desc(p.smbo_itype),
 541             fp, "  Internal Connector Type: %u", p.smbo_itype);
 542 
 543         desc_printf(smbios_port_conn_desc(p.smbo_etype),
 544             fp, "  External Connector Type: %u", p.smbo_etype);
 545 
 546         desc_printf(smbios_port_type_desc(p.smbo_ptype),
 547             fp, "  Port Type: %u", p.smbo_ptype);
 548 }
 549 
 550 static void
 551 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
 552 {
 553         smbios_slot_t s;
 554         smbios_entry_t e;
 555 
 556         (void) smbios_info_slot(shp, id, &s);
 557         (void) smbios_info_smbios(shp, &e);
 558 
 559         oprintf(fp, "  Reference Designator: %s\n", s.smbl_name);
 560         oprintf(fp, "  Slot ID: 0x%x\n", s.smbl_id);
 561 
 562         desc_printf(smbios_slot_type_desc(s.smbl_type),
 563             fp, "  Type: 0x%x", s.smbl_type);
 564 
 565         desc_printf(smbios_slot_width_desc(s.smbl_width),
 566             fp, "  Width: 0x%x", s.smbl_width);
 567 
 568         desc_printf(smbios_slot_usage_desc(s.smbl_usage),
 569             fp, "  Usage: 0x%x", s.smbl_usage);
 570 
 571         desc_printf(smbios_slot_length_desc(s.smbl_length),
 572             fp, "  Length: 0x%x", s.smbl_length);
 573 
 574         flag_printf(fp, "Slot Characteristics 1",
 575             s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
 576             smbios_slot_ch1_name, smbios_slot_ch1_desc);
 577 
 578         flag_printf(fp, "Slot Characteristics 2",
 579             s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
 580             smbios_slot_ch2_name, smbios_slot_ch2_desc);
 581 
 582         if (check_oem(shp) != 0 && (e.smbe_major < 2 || e.smbe_minor < 6))
 583                 return;
 584 
 585         oprintf(fp, "  Segment Group: %u\n", s.smbl_sg);
 586         oprintf(fp, "  Bus Number: %u\n", s.smbl_bus);
 587         oprintf(fp, "  Device/Function Number: %u\n", s.smbl_df);
 588 }
 589 
 590 static void
 591 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
 592 {
 593         smbios_obdev_ext_t oe;
 594 
 595         (void) smbios_info_obdevs_ext(shp, id, &oe);
 596 
 597         oprintf(fp, "  Reference Designator: %s\n", oe.smboe_name);
 598         oprintf(fp, "  Device Type: %u\n", oe.smboe_dtype);
 599         oprintf(fp, "  Device Type Instance: %u\n", oe.smboe_dti);
 600         oprintf(fp, "  Segment Group Number: %u\n", oe.smboe_sg);
 601         oprintf(fp, "  Bus Number: %u\n", oe.smboe_bus);
 602         oprintf(fp, "  Device/Function Number: %u\n", oe.smboe_df);
 603 }
 604 
 605 static void
 606 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
 607 {
 608         smbios_obdev_t *argv;
 609         int i, argc;
 610 
 611         if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
 612                 argv = alloca(sizeof (smbios_obdev_t) * argc);
 613                 (void) smbios_info_obdevs(shp, id, argc, argv);
 614                 for (i = 0; i < argc; i++)
 615                         oprintf(fp, "  %s\n", argv[i].smbd_name);
 616         }
 617 }
 618 
 619 static void
 620 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
 621 {
 622         const char **argv;
 623         int i, argc;
 624 
 625         if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
 626                 argv = alloca(sizeof (char *) * argc);
 627                 (void) smbios_info_strtab(shp, id, argc, argv);
 628                 for (i = 0; i < argc; i++)
 629                         oprintf(fp, "  %s\n", argv[i]);
 630         }
 631 }
 632 
 633 static void
 634 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
 635 {
 636         smbios_lang_t l;
 637 
 638         (void) smbios_info_lang(shp, &l);
 639 
 640         oprintf(fp, "  Current Language: %s\n", l.smbla_cur);
 641         oprintf(fp, "  Language String Format: %u\n", l.smbla_fmt);
 642         oprintf(fp, "  Number of Installed Languages: %u\n", l.smbla_num);
 643         oprintf(fp, "  Installed Languages:\n");
 644 
 645         print_strtab(shp, id, fp);
 646 }
 647 
 648 /*ARGSUSED*/
 649 static void
 650 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
 651 {
 652         smbios_evlog_t ev;
 653         uint32_t i;
 654 
 655         (void) smbios_info_eventlog(shp, &ev);
 656 
 657         oprintf(fp, "  Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
 658         oprintf(fp, "  Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
 659         oprintf(fp, "  Data Offset: %lu\n", (ulong_t)ev.smbev_data);
 660 
 661         desc_printf(smbios_evlog_method_desc(ev.smbev_method),
 662             fp, "  Data Access Method: %u", ev.smbev_method);
 663 
 664         flag_printf(fp, "Log Flags",
 665             ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
 666             smbios_evlog_flag_name, smbios_evlog_flag_desc);
 667 
 668         desc_printf(smbios_evlog_format_desc(ev.smbev_format),
 669             fp, "  Log Header Format: %u", ev.smbev_format);
 670 
 671         oprintf(fp, "  Update Token: 0x%x\n", ev.smbev_token);
 672         oprintf(fp, "  Data Access Address: ");
 673 
 674         switch (ev.smbev_method) {
 675         case SMB_EVM_1x1i_1x1d:
 676         case SMB_EVM_2x1i_1x1d:
 677         case SMB_EVM_1x2i_1x1d:
 678                 oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
 679                     ev.smbev_addr.eva_io.evi_iaddr,
 680                     ev.smbev_addr.eva_io.evi_daddr);
 681                 break;
 682         case SMB_EVM_GPNV:
 683                 oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
 684                 break;
 685         default:
 686                 oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
 687         }
 688 
 689         oprintf(fp, "  Type Descriptors:\n");
 690 
 691         for (i = 0; i < ev.smbev_typec; i++) {
 692                 oprintf(fp, "  %u: Log Type 0x%x, Data Type 0x%x\n", i,
 693                     ev.smbev_typev[i].smbevt_ltype,
 694                     ev.smbev_typev[i].smbevt_dtype);
 695         }
 696 }
 697 
 698 static void
 699 print_bytes(const uint8_t *data, size_t size, FILE *fp)
 700 {
 701         size_t row, rows = P2ROUNDUP(size, 16) / 16;
 702         size_t col, cols;
 703 
 704         char buf[17];
 705         uint8_t x;
 706 
 707         oprintf(fp, "\n  offset:   0 1 2 3  4 5 6 7  8 9 a b  c d e f  "
 708             "0123456789abcdef\n");
 709 
 710         for (row = 0; row < rows; row++) {
 711                 oprintf(fp, "    %#4lx: ", (ulong_t)row * 16);
 712                 cols = MIN(size - row * 16, 16);
 713 
 714                 for (col = 0; col < cols; col++) {
 715                         if (col % 4 == 0)
 716                                 oprintf(fp, " ");
 717                         x = *data++;
 718                         oprintf(fp, "%02x", x);
 719                         buf[col] = x <= ' ' || x > '~' ? '.' : x;
 720                 }
 721 
 722                 for (; col < 16; col++) {
 723                         if (col % 4 == 0)
 724                                 oprintf(fp, " ");
 725                         oprintf(fp, "  ");
 726                         buf[col] = ' ';
 727                 }
 728 
 729                 buf[col] = '\0';
 730                 oprintf(fp, "  %s\n", buf);
 731         }
 732 
 733         oprintf(fp, "\n");
 734 }
 735 
 736 static void
 737 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
 738 {
 739         smbios_memarray_t ma;
 740 
 741         (void) smbios_info_memarray(shp, id, &ma);
 742 
 743         desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
 744             fp, "  Location: %u", ma.smbma_location);
 745 
 746         desc_printf(smbios_memarray_use_desc(ma.smbma_use),
 747             fp, "  Use: %u", ma.smbma_use);
 748 
 749         desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
 750             fp, "  ECC: %u", ma.smbma_ecc);
 751 
 752         oprintf(fp, "  Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
 753         id_printf(fp, "  Memory Error Data: ", ma.smbma_err);
 754         oprintf(fp, "  Max Capacity: %llu bytes\n",
 755             (u_longlong_t)ma.smbma_size);
 756 }
 757 
 758 static void
 759 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
 760 {
 761         smbios_memdevice_t md;
 762 
 763         (void) smbios_info_memdevice(shp, id, &md);
 764 
 765         id_printf(fp, "  Physical Memory Array: ", md.smbmd_array);
 766         id_printf(fp, "  Memory Error Data: ", md.smbmd_error);
 767 
 768         if (md.smbmd_twidth != -1u)
 769                 oprintf(fp, "  Total Width: %u bits\n", md.smbmd_twidth);
 770         else
 771                 oprintf(fp, "  Total Width: Unknown\n");
 772 
 773         if (md.smbmd_dwidth != -1u)
 774                 oprintf(fp, "  Data Width: %u bits\n", md.smbmd_dwidth);
 775         else
 776                 oprintf(fp, "  Data Width: Unknown\n");
 777 
 778         switch (md.smbmd_size) {
 779         case -1ull:
 780                 oprintf(fp, "  Size: Unknown\n");
 781                 break;
 782         case 0:
 783                 oprintf(fp, "  Size: Not Populated\n");
 784                 break;
 785         default:
 786                 oprintf(fp, "  Size: %llu bytes\n",
 787                     (u_longlong_t)md.smbmd_size);
 788         }
 789 
 790         desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
 791             fp, "  Form Factor: %u", md.smbmd_form);
 792 
 793         if (md.smbmd_set == 0)
 794                 oprintf(fp, "  Set: None\n");
 795         else if (md.smbmd_set == (uint8_t)-1u)
 796                 oprintf(fp, "  Set: Unknown\n");
 797         else
 798                 oprintf(fp, "  Set: %u\n", md.smbmd_set);
 799 
 800         if (md.smbmd_rank != 0) {
 801                 desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
 802                     fp, "  Rank: %u", md.smbmd_rank);
 803         } else {
 804                 oprintf(fp, "  Rank: Unknown\n");
 805         }
 806 
 807         desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
 808             fp, "  Memory Type: %u", md.smbmd_type);
 809 
 810         flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
 811             smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
 812 
 813         if (md.smbmd_speed != 0)
 814                 oprintf(fp, "  Speed: %u MHz\n", md.smbmd_speed);
 815         else
 816                 oprintf(fp, "  Speed: Unknown\n");
 817 
 818         if (md.smbmd_clkspeed != 0)
 819                 oprintf(fp, "  Configured Speed: %u MHz\n", md.smbmd_clkspeed);
 820         else
 821                 oprintf(fp, "  Configured Speed: Unknown\n");
 822 
 823         oprintf(fp, "  Device Locator: %s\n", md.smbmd_dloc);
 824         oprintf(fp, "  Bank Locator: %s\n", md.smbmd_bloc);
 825 
 826         if (md.smbmd_minvolt != 0) {
 827                 oprintf(fp, "  Minimum Voltage: %.2fV\n",
 828                     md.smbmd_minvolt / 1000.0);
 829         } else {
 830                 oprintf(fp, "  Minimum Voltage: Unknown\n");
 831         }
 832 
 833         if (md.smbmd_maxvolt != 0) {
 834                 oprintf(fp, "  Maximum Voltage: %.2fV\n",
 835                     md.smbmd_maxvolt / 1000.0);
 836         } else {
 837                 oprintf(fp, "  Maximum Voltage: Unknown\n");
 838         }
 839 
 840         if (md.smbmd_confvolt != 0) {
 841                 oprintf(fp, "  Configured Voltage: %.2fV\n",
 842                     md.smbmd_confvolt / 1000.0);
 843         } else {
 844                 oprintf(fp, "  Configured Voltage: Unknown\n");
 845         }
 846 }
 847 
 848 static void
 849 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
 850 {
 851         smbios_memarrmap_t ma;
 852 
 853         (void) smbios_info_memarrmap(shp, id, &ma);
 854 
 855         id_printf(fp, "  Physical Memory Array: ", ma.smbmam_array);
 856         oprintf(fp, "  Devices per Row: %u\n", ma.smbmam_width);
 857 
 858         oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
 859             (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
 860 }
 861 
 862 static void
 863 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
 864 {
 865         smbios_memdevmap_t md;
 866 
 867         (void) smbios_info_memdevmap(shp, id, &md);
 868 
 869         id_printf(fp, "  Memory Device: ", md.smbmdm_device);
 870         id_printf(fp, "  Memory Array Mapped Address: ", md.smbmdm_arrmap);
 871 
 872         oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
 873             (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
 874 
 875         oprintf(fp, "  Partition Row Position: %u\n", md.smbmdm_rpos);
 876         oprintf(fp, "  Interleave Position: %u\n", md.smbmdm_ipos);
 877         oprintf(fp, "  Interleave Data Depth: %u\n", md.smbmdm_idepth);
 878 }
 879 
 880 static void
 881 print_hwsec(smbios_hdl_t *shp, FILE *fp)
 882 {
 883         smbios_hwsec_t h;
 884 
 885         (void) smbios_info_hwsec(shp, &h);
 886 
 887         desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
 888             fp, "  Power-On Password Status: %u", h.smbh_pwr_ps);
 889         desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
 890             fp, "  Keyboard Password Status: %u", h.smbh_kbd_ps);
 891         desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
 892             fp, "  Administrator Password Status: %u", h.smbh_adm_ps);
 893         desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
 894             fp, "  Front Panel Reset Status: %u", h.smbh_pan_ps);
 895 }
 896 
 897 static void
 898 print_boot(smbios_hdl_t *shp, FILE *fp)
 899 {
 900         smbios_boot_t b;
 901 
 902         (void) smbios_info_boot(shp, &b);
 903 
 904         desc_printf(smbios_boot_desc(b.smbt_status),
 905             fp, "  Boot Status Code: 0x%x", b.smbt_status);
 906 
 907         if (b.smbt_size != 0) {
 908                 oprintf(fp, "  Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
 909                 print_bytes(b.smbt_data, b.smbt_size, fp);
 910         }
 911 }
 912 
 913 static void
 914 print_ipmi(smbios_hdl_t *shp, FILE *fp)
 915 {
 916         smbios_ipmi_t i;
 917 
 918         (void) smbios_info_ipmi(shp, &i);
 919 
 920         desc_printf(smbios_ipmi_type_desc(i.smbip_type),
 921             fp, "  Type: %u", i.smbip_type);
 922 
 923         oprintf(fp, "  BMC IPMI Version: %u.%u\n",
 924             i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
 925 
 926         oprintf(fp, "  i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
 927         oprintf(fp, "  NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
 928         oprintf(fp, "  BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
 929         oprintf(fp, "  Interrupt Number: %u\n", i.smbip_intr);
 930         oprintf(fp, "  Register Spacing: %u\n", i.smbip_regspacing);
 931 
 932         flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
 933             smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
 934 }
 935 
 936 static void
 937 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
 938 {
 939         int i;
 940         smbios_processor_ext_t ep;
 941 
 942         if (check_oem(shp) != 0)
 943                 return;
 944 
 945         (void) smbios_info_extprocessor(shp, id, &ep);
 946 
 947         oprintf(fp, "  Processor: %u\n", ep.smbpe_processor);
 948         oprintf(fp, "  FRU: %u\n", ep.smbpe_fru);
 949         oprintf(fp, "  Initial APIC ID count: %u\n\n", ep.smbpe_n);
 950 
 951         for (i = 0; i < ep.smbpe_n; i++) {
 952                 oprintf(fp, "  Logical Strand %u: Initial APIC ID: %u\n", i,
 953                     ep.smbpe_apicid[i]);
 954         }
 955 }
 956 
 957 static void
 958 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
 959 {
 960         smbios_port_ext_t epo;
 961 
 962         if (check_oem(shp) != 0)
 963                 return;
 964 
 965         (void) smbios_info_extport(shp, id, &epo);
 966 
 967         oprintf(fp, "  Chassis Handle: %u\n", epo.smbporte_chassis);
 968         oprintf(fp, "  Port Connector Handle: %u\n", epo.smbporte_port);
 969         oprintf(fp, "  Device Type: %u\n", epo.smbporte_dtype);
 970         oprintf(fp, "  Device Handle: %u\n", epo.smbporte_devhdl);
 971         oprintf(fp, "  PHY: %u\n", epo.smbporte_phy);
 972 }
 973 
 974 static void
 975 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
 976 {
 977         smbios_pciexrc_t pcie;
 978 
 979         if (check_oem(shp) != 0)
 980                 return;
 981 
 982         (void) smbios_info_pciexrc(shp, id, &pcie);
 983 
 984         oprintf(fp, "  Component ID: %u\n", pcie.smbpcie_bb);
 985         oprintf(fp, "  BDF: 0x%x\n", pcie.smbpcie_bdf);
 986 }
 987 
 988 static void
 989 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
 990 {
 991         smbios_memarray_ext_t em;
 992 
 993         if (check_oem(shp) != 0)
 994                 return;
 995 
 996         (void) smbios_info_extmemarray(shp, id, &em);
 997 
 998         oprintf(fp, "  Physical Memory Array Handle: %u\n", em.smbmae_ma);
 999         oprintf(fp, "  Component Parent Handle: %u\n", em.smbmae_comp);
1000         oprintf(fp, "  BDF: 0x%x\n", em.smbmae_bdf);
1001 }
1002 
1003 static void
1004 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1005 {
1006         int i;
1007         smbios_memdevice_ext_t emd;
1008 
1009         if (check_oem(shp) != 0)
1010                 return;
1011 
1012         (void) smbios_info_extmemdevice(shp, id, &emd);
1013 
1014         oprintf(fp, "  Memory Device Handle: %u\n", emd.smbmdeve_md);
1015         oprintf(fp, "  DRAM Channel: %u\n", emd.smbmdeve_drch);
1016         oprintf(fp, "  Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1017 
1018         for (i = 0; i < emd.smbmdeve_ncs; i++) {
1019                 oprintf(fp, "  Chip Select: %u\n", emd.smbmdeve_cs[i]);
1020         }
1021 }
1022 
1023 static int
1024 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1025 {
1026         smbios_info_t info;
1027         int hex = opt_x;
1028         const char *s;
1029 
1030         if (opt_t != -1 && opt_t != sp->smbstr_type)
1031                 return (0); /* skip struct if type doesn't match -t */
1032 
1033         if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1034             sp->smbstr_type == SMB_TYPE_MEMMOD))
1035                 return (0); /* skip struct if type is obsolete */
1036 
1037         if (g_hdr++ == 0 || !opt_s)
1038                 oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
1039 
1040         oprintf(fp, "%-5u %-4lu",
1041             (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
1042 
1043         if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
1044                 oprintf(fp, " (%u) %s", sp->smbstr_type, s);
1045         else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
1046             sp->smbstr_type < SMB_TYPE_OEM_HI)
1047                 oprintf(fp, " (%u) %s+%u", sp->smbstr_type, "SMB_TYPE_OEM_LO",
1048                     sp->smbstr_type - SMB_TYPE_OEM_LO);
1049         else
1050                 oprintf(fp, " %u", sp->smbstr_type);
1051 
1052         if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
1053                 oprintf(fp, " (%s)\n", s);
1054         else
1055                 oprintf(fp, "\n");
1056 
1057         if (opt_s)
1058                 return (0); /* only print header line if -s specified */
1059 
1060         if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
1061                 oprintf(fp, "\n");
1062                 print_common(&info, fp);
1063         }
1064 
1065         switch (sp->smbstr_type) {
1066         case SMB_TYPE_BIOS:
1067                 oprintf(fp, "\n");
1068                 print_bios(shp, fp);
1069                 break;
1070         case SMB_TYPE_SYSTEM:
1071                 oprintf(fp, "\n");
1072                 print_system(shp, fp);
1073                 break;
1074         case SMB_TYPE_BASEBOARD:
1075                 oprintf(fp, "\n");
1076                 print_bboard(shp, sp->smbstr_id, fp);
1077                 break;
1078         case SMB_TYPE_CHASSIS:
1079                 oprintf(fp, "\n");
1080                 print_chassis(shp, sp->smbstr_id, fp);
1081                 break;
1082         case SMB_TYPE_PROCESSOR:
1083                 oprintf(fp, "\n");
1084                 print_processor(shp, sp->smbstr_id, fp);
1085                 break;
1086         case SMB_TYPE_CACHE:
1087                 oprintf(fp, "\n");
1088                 print_cache(shp, sp->smbstr_id, fp);
1089                 break;
1090         case SMB_TYPE_PORT:
1091                 oprintf(fp, "\n");
1092                 print_port(shp, sp->smbstr_id, fp);
1093                 break;
1094         case SMB_TYPE_SLOT:
1095                 oprintf(fp, "\n");
1096                 print_slot(shp, sp->smbstr_id, fp);
1097                 break;
1098         case SMB_TYPE_OBDEVS:
1099                 oprintf(fp, "\n");
1100                 print_obdevs(shp, sp->smbstr_id, fp);
1101                 break;
1102         case SMB_TYPE_OEMSTR:
1103         case SMB_TYPE_SYSCONFSTR:
1104                 oprintf(fp, "\n");
1105                 print_strtab(shp, sp->smbstr_id, fp);
1106                 break;
1107         case SMB_TYPE_LANG:
1108                 oprintf(fp, "\n");
1109                 print_lang(shp, sp->smbstr_id, fp);
1110                 break;
1111         case SMB_TYPE_EVENTLOG:
1112                 oprintf(fp, "\n");
1113                 print_evlog(shp, sp->smbstr_id, fp);
1114                 break;
1115         case SMB_TYPE_MEMARRAY:
1116                 oprintf(fp, "\n");
1117                 print_memarray(shp, sp->smbstr_id, fp);
1118                 break;
1119         case SMB_TYPE_MEMDEVICE:
1120                 oprintf(fp, "\n");
1121                 print_memdevice(shp, sp->smbstr_id, fp);
1122                 break;
1123         case SMB_TYPE_MEMARRAYMAP:
1124                 oprintf(fp, "\n");
1125                 print_memarrmap(shp, sp->smbstr_id, fp);
1126                 break;
1127         case SMB_TYPE_MEMDEVICEMAP:
1128                 oprintf(fp, "\n");
1129                 print_memdevmap(shp, sp->smbstr_id, fp);
1130                 break;
1131         case SMB_TYPE_SECURITY:
1132                 oprintf(fp, "\n");
1133                 print_hwsec(shp, fp);
1134                 break;
1135         case SMB_TYPE_BOOT:
1136                 oprintf(fp, "\n");
1137                 print_boot(shp, fp);
1138                 break;
1139         case SMB_TYPE_IPMIDEV:
1140                 oprintf(fp, "\n");
1141                 print_ipmi(shp, fp);
1142                 break;
1143         case SMB_TYPE_OBDEVEXT:
1144                 oprintf(fp, "\n");
1145                 print_obdevs_ext(shp, sp->smbstr_id, fp);
1146                 break;
1147         case SUN_OEM_EXT_PROCESSOR:
1148                 oprintf(fp, "\n");
1149                 print_extprocessor(shp, sp->smbstr_id, fp);
1150                 break;
1151         case SUN_OEM_EXT_PORT:
1152                 oprintf(fp, "\n");
1153                 print_extport(shp, sp->smbstr_id, fp);
1154                 break;
1155         case SUN_OEM_PCIEXRC:
1156                 oprintf(fp, "\n");
1157                 print_pciexrc(shp, sp->smbstr_id, fp);
1158                 break;
1159         case SUN_OEM_EXT_MEMARRAY:
1160                 oprintf(fp, "\n");
1161                 print_extmemarray(shp, sp->smbstr_id, fp);
1162                 break;
1163         case SUN_OEM_EXT_MEMDEVICE:
1164                 oprintf(fp, "\n");
1165                 print_extmemdevice(shp, sp->smbstr_id, fp);
1166                 break;
1167         default:
1168                 hex++;
1169         }
1170 
1171         if (hex)
1172                 print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
1173         else
1174                 oprintf(fp, "\n");
1175 
1176         return (0);
1177 }
1178 
1179 static uint16_t
1180 getu16(const char *name, const char *s)
1181 {
1182         u_longlong_t val;
1183         char *p;
1184 
1185         errno = 0;
1186         val = strtoull(s, &p, 0);
1187 
1188         if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
1189                 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
1190                     g_pname, name, s);
1191                 exit(SMBIOS_USAGE);
1192         }
1193 
1194         return ((uint16_t)val);
1195 }
1196 
1197 static uint16_t
1198 getstype(const char *name, const char *s)
1199 {
1200         const char *ts;
1201         uint16_t t;
1202 
1203         for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
1204                 if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
1205                         return (t);
1206         }
1207 
1208         (void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
1209             g_pname, name, s);
1210 
1211         exit(SMBIOS_USAGE);
1212         /*NOTREACHED*/
1213 }
1214 
1215 static int
1216 usage(FILE *fp)
1217 {
1218         (void) fprintf(fp, "Usage: %s "
1219             "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
1220 
1221         (void) fprintf(fp,
1222             "\t-B disable header validation for broken BIOSes\n"
1223             "\t-e display SMBIOS entry point information\n"
1224             "\t-i display only the specified structure\n"
1225             "\t-O display obsolete structure types\n"
1226             "\t-s display only a summary of structure identifiers and types\n"
1227             "\t-t display only the specified structure type\n"
1228             "\t-w write the raw data to the specified file\n"
1229             "\t-x display raw data for structures\n");
1230 
1231         return (SMBIOS_USAGE);
1232 }
1233 
1234 int
1235 main(int argc, char *argv[])
1236 {
1237         const char *ifile = NULL;
1238         const char *ofile = NULL;
1239         int oflags = 0;
1240 
1241         smbios_hdl_t *shp;
1242         smbios_struct_t s;
1243         int err, fd, c;
1244         char *p;
1245 
1246         if ((p = strrchr(argv[0], '/')) == NULL)
1247                 g_pname = argv[0];
1248         else
1249                 g_pname = p + 1;
1250 
1251         while (optind < argc) {
1252                 while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
1253                         switch (c) {
1254                         case 'B':
1255                                 oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
1256                                 break;
1257                         case 'e':
1258                                 opt_e++;
1259                                 break;
1260                         case 'i':
1261                                 opt_i = getu16("struct ID", optarg);
1262                                 break;
1263                         case 'O':
1264                                 opt_O++;
1265                                 break;
1266                         case 's':
1267                                 opt_s++;
1268                                 break;
1269                         case 't':
1270                                 if (isdigit(optarg[0]))
1271                                         opt_t = getu16("struct type", optarg);
1272                                 else
1273                                         opt_t = getstype("struct type", optarg);
1274                                 break;
1275                         case 'w':
1276                                 ofile = optarg;
1277                                 break;
1278                         case 'x':
1279                                 opt_x++;
1280                                 break;
1281                         case 'Z':
1282                                 oflags |= SMB_O_ZIDS; /* undocumented */
1283                                 break;
1284                         default:
1285                                 return (usage(stderr));
1286                         }
1287                 }
1288 
1289                 if (optind < argc) {
1290                         if (ifile != NULL) {
1291                                 (void) fprintf(stderr, "%s: illegal "
1292                                     "argument -- %s\n", g_pname, argv[optind]);
1293                                 return (SMBIOS_USAGE);
1294                         }
1295                         ifile = argv[optind++];
1296                 }
1297         }
1298 
1299         if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
1300                 (void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
1301                     g_pname, smbios_errmsg(err));
1302                 return (SMBIOS_ERROR);
1303         }
1304 
1305         if (ofile != NULL) {
1306                 if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
1307                         (void) fprintf(stderr, "%s: failed to open %s: %s\n",
1308                             g_pname, ofile, strerror(errno));
1309                         err = SMBIOS_ERROR;
1310                 } else if (smbios_write(shp, fd) != 0) {
1311                         (void) fprintf(stderr, "%s: failed to write %s: %s\n",
1312                             g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
1313                         err = SMBIOS_ERROR;
1314                 }
1315                 smbios_close(shp);
1316                 return (err);
1317         }
1318 
1319         if (opt_e) {
1320                 print_smbios(shp, stdout);
1321                 smbios_close(shp);
1322                 return (SMBIOS_SUCCESS);
1323         }
1324 
1325         if (opt_O && (opt_i != -1 || opt_t != -1))
1326                 opt_O++; /* -i or -t imply displaying obsolete records */
1327 
1328         if (opt_i != -1)
1329                 err = smbios_lookup_id(shp, opt_i, &s);
1330         else
1331                 err = smbios_iter(shp, print_struct, stdout);
1332 
1333         if (err != 0) {
1334                 (void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
1335                     g_pname, smbios_errmsg(smbios_errno(shp)));
1336                 smbios_close(shp);
1337                 return (SMBIOS_ERROR);
1338         }
1339 
1340         if (opt_i != -1)
1341                 (void) print_struct(shp, &s, stdout);
1342 
1343         smbios_close(shp);
1344         return (SMBIOS_SUCCESS);
1345 }