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 (c) 2017, Joyent, Inc.
25 * Copyright 2024 Oxide Computer Company
26 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #include <sys/sysmacros.h>
31 #include <sys/param.h>
32 #include <sys/bitext.h>
33
34 #include <smbios.h>
35 #include <alloca.h>
36 #include <limits.h>
37 #include <unistd.h>
38 #include <strings.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <ctype.h>
45 #include <libjedec.h>
46
47 #define SMBIOS_SUCCESS 0
48 #define SMBIOS_ERROR 1
49 #define SMBIOS_USAGE 2
50
51 static const char *g_pname;
52 static int g_hdr;
53
54 static int opt_e;
55 static int opt_i = -1;
56 static int opt_O;
57 static int opt_s;
58 static int opt_t = -1;
59 static int opt_x;
60
61 static boolean_t
smbios_vergteq(smbios_version_t * v,uint_t major,uint_t minor)62 smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
63 {
64 if (v->smbv_major > major)
65 return (B_TRUE);
66 if (v->smbv_major == major &&
67 v->smbv_minor >= minor)
68 return (B_TRUE);
69 return (B_FALSE);
70 }
71
72 /*PRINTFLIKE2*/
73 static void
smbios_warn(smbios_hdl_t * shp,const char * format,...)74 smbios_warn(smbios_hdl_t *shp, const char *format, ...)
75 {
76 va_list ap;
77
78 va_start(ap, format);
79 (void) vfprintf(stderr, format, ap);
80 va_end(ap);
81
82 if (shp != NULL) {
83 (void) fprintf(stderr, ": %s",
84 smbios_errmsg(smbios_errno(shp)));
85 }
86
87 (void) fprintf(stderr, "\n");
88 }
89
90 /*PRINTFLIKE2*/
91 static void
oprintf(FILE * fp,const char * format,...)92 oprintf(FILE *fp, const char *format, ...)
93 {
94 va_list ap;
95
96 va_start(ap, format);
97 (void) vfprintf(fp, format, ap);
98 va_end(ap);
99 }
100
101 /*PRINTFLIKE3*/
102 static void
desc_printf(const char * d,FILE * fp,const char * format,...)103 desc_printf(const char *d, FILE *fp, const char *format, ...)
104 {
105 va_list ap;
106
107 va_start(ap, format);
108 (void) vfprintf(fp, format, ap);
109 va_end(ap);
110
111 if (d != NULL)
112 (void) fprintf(fp, " (%s)\n", d);
113 else
114 (void) fprintf(fp, "\n");
115 }
116
117 static void
flag_printf(FILE * fp,const char * s,uint_t flags,size_t bits,const char * (* flag_name)(uint_t),const char * (* flag_desc)(uint_t))118 flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
119 const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
120 {
121 size_t i;
122
123 oprintf(fp, " %s: 0x%x\n", s, flags);
124
125 for (i = 0; i < bits; i++) {
126 uint_t f = 1 << i;
127 const char *n;
128
129 if (!(flags & f))
130 continue;
131
132 if ((n = flag_name(f)) != NULL)
133 desc_printf(flag_desc(f), fp, "\t%s", n);
134 else
135 desc_printf(flag_desc(f), fp, "\t0x%x", f);
136 }
137 }
138
139 static void
flag64_printf(FILE * fp,const char * s,uint64_t flags,size_t bits,const char * (* flag_name)(uint64_t),const char * (* flag_desc)(uint64_t))140 flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
141 const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
142 {
143 size_t i;
144
145 oprintf(fp, " %s: 0x%llx\n", s, (u_longlong_t)flags);
146
147 for (i = 0; i < bits; i++) {
148 u_longlong_t f = 1ULL << i;
149 const char *n;
150
151 if (!(flags & f))
152 continue;
153
154 if ((n = flag_name(f)) != NULL)
155 desc_printf(flag_desc(f), fp, "\t%s", n);
156 else
157 desc_printf(flag_desc(f), fp, "\t0x%llx", f);
158 }
159 }
160
161 static void
id_printf(FILE * fp,const char * s,id_t id)162 id_printf(FILE *fp, const char *s, id_t id)
163 {
164 switch (id) {
165 case SMB_ID_NONE:
166 oprintf(fp, "%sNone\n", s);
167 break;
168 case SMB_ID_NOTSUP:
169 oprintf(fp, "%sNot Supported\n", s);
170 break;
171 default:
172 oprintf(fp, "%s%u\n", s, (uint_t)id);
173 }
174 }
175
176 static void
jedec_print(FILE * fp,const char * desc,uint_t id)177 jedec_print(FILE *fp, const char *desc, uint_t id)
178 {
179 const char *name;
180 uint_t cont, vendor;
181
182 /*
183 * SMBIOS encodes data in the way that the underlying memory standard
184 * does. In this case, the upper byte indicates the vendor that we care
185 * about while the lower byte indicates the number of continuations that
186 * are needed. libjedec indexes this based on zero (e.g. table 1 is zero
187 * continuations), which is how the spec encodes it. We add one so that
188 * we can match how the spec describes it.
189 */
190 vendor = id >> 8;
191 cont = id & 0x7f;
192 name = libjedec_vendor_string(cont, vendor);
193 if (name == NULL) {
194 oprintf(fp, " %s: Bank: 0x%x Vendor: 0x%x\n", desc, cont + 1,
195 vendor);
196 } else {
197 oprintf(fp, " %s: Bank: 0x%x Vendor: 0x%x (%s)\n", desc,
198 cont + 1, vendor, name);
199 }
200 }
201
202 /*
203 * Convert an SMBIOS encoded JEDEDC component revision into its actual form. In
204 * general, JEDEC revisions are single byte values; however, the SMBIOS fields
205 * are two bytes wide. The byte that we care about is the "first" byte which
206 * translates into the upper bits here. The revision is binary coded decimal
207 * (BCD) represented with each nibble as major.minor. The major is the upper
208 * nibble and the minor is the lower one.
209 */
210 static void
jedec_rev_print(FILE * fp,const char * desc,uint16_t raw_rev)211 jedec_rev_print(FILE *fp, const char *desc, uint16_t raw_rev)
212 {
213 uint8_t rev = (uint8_t)bitx16(raw_rev, 15, 8);
214 uint8_t maj = bitx8(rev, 7, 4);
215 uint8_t min = bitx8(rev, 3, 0);
216 oprintf(fp, " %s: %x.%x\n", desc, maj, min);
217 }
218
219 /*
220 * Print a 128-bit data as a series of 16 hex digits.
221 */
222 static void
u128_print(FILE * fp,const char * desc,const uint8_t * data)223 u128_print(FILE *fp, const char *desc, const uint8_t *data)
224 {
225 uint_t i;
226
227 oprintf(fp, "%s: ", desc);
228 for (i = 0; i < 16; i++) {
229 oprintf(fp, " %02x", data[i]);
230 }
231 oprintf(fp, "\n");
232 }
233
234 /*
235 * Print a string that came from an SMBIOS table. We do this character by
236 * character so we can potentially escape strings.
237 */
238 static void
str_print_label(FILE * fp,const char * header,const char * str,boolean_t label)239 str_print_label(FILE *fp, const char *header, const char *str, boolean_t label)
240 {
241 const char *c;
242
243 oprintf(fp, header);
244 if (label) {
245 oprintf(fp, ": ");
246 }
247
248 for (c = str; *c != '\0'; c++) {
249 if (isprint(*c)) {
250 oprintf(fp, "%c", *c);
251 } else {
252 oprintf(fp, "\\x%02x", *c);
253 }
254 }
255
256 oprintf(fp, "\n");
257 }
258
259 static void
str_print_nolabel(FILE * fp,const char * ws,const char * str)260 str_print_nolabel(FILE *fp, const char *ws, const char *str)
261 {
262 return (str_print_label(fp, ws, str, B_FALSE));
263 }
264
265 static void
str_print(FILE * fp,const char * header,const char * str)266 str_print(FILE *fp, const char *header, const char *str)
267 {
268 return (str_print_label(fp, header, str, B_TRUE));
269 }
270
271 static int
check_oem(smbios_hdl_t * shp)272 check_oem(smbios_hdl_t *shp)
273 {
274 int i;
275 int cnt;
276 int rv;
277 id_t oem_id;
278 smbios_struct_t s;
279 const char **oem_str;
280
281 rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
282 if (rv != 0) {
283 return (-1);
284 }
285
286 oem_id = s.smbstr_id;
287
288 cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
289 if (cnt > 0) {
290 oem_str = alloca(sizeof (char *) * cnt);
291 (void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
292
293 for (i = 0; i < cnt; i++) {
294 if (strncmp(oem_str[i], SMB_PRMS1,
295 strlen(SMB_PRMS1) + 1) == 0) {
296 return (0);
297 }
298 }
299 }
300
301 return (-1);
302 }
303
304 static void
print_smbios_21(smbios_21_entry_t * ep,FILE * fp)305 print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
306 {
307 int i;
308
309 oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
310 (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
311 ep->smbe_eanchor);
312
313 oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
314 oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
315 oprintf(fp, "Entry Point Version: %u.%u\n",
316 ep->smbe_major, ep->smbe_minor);
317 oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
318 oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
319
320 oprintf(fp, "Entry Point Revision Data:");
321 for (i = 0; i < sizeof (ep->smbe_format); i++)
322 oprintf(fp, " 0x%02x", ep->smbe_format[i]);
323 oprintf(fp, "\n");
324
325 oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
326 (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
327 ep->smbe_ianchor);
328
329 oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
330 oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
331 oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
332 oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
333 oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
334 }
335
336 static void
print_smbios_30(smbios_30_entry_t * ep,FILE * fp)337 print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
338 {
339 oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
340 (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
341 ep->smbe_eanchor);
342
343 oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
344 oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
345 oprintf(fp, "SMBIOS Version: %u.%u\n",
346 ep->smbe_major, ep->smbe_minor);
347 oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
348 oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
349
350 oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
351 oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
352 ep->smbe_staddr);
353 }
354
355 static void
print_smbios(smbios_hdl_t * shp,FILE * fp)356 print_smbios(smbios_hdl_t *shp, FILE *fp)
357 {
358 smbios_entry_t ep;
359
360 switch (smbios_info_smbios(shp, &ep)) {
361 case SMBIOS_ENTRY_POINT_21:
362 print_smbios_21(&ep.ep21, fp);
363 break;
364 case SMBIOS_ENTRY_POINT_30:
365 print_smbios_30(&ep.ep30, fp);
366 break;
367 }
368 }
369
370 static void
print_common(const smbios_info_t * ip,FILE * fp)371 print_common(const smbios_info_t *ip, FILE *fp)
372 {
373 if (ip->smbi_manufacturer[0] != '\0')
374 str_print(fp, " Manufacturer", ip->smbi_manufacturer);
375 if (ip->smbi_product[0] != '\0')
376 str_print(fp, " Product", ip->smbi_product);
377 if (ip->smbi_version[0] != '\0')
378 str_print(fp, " Version", ip->smbi_version);
379 if (ip->smbi_serial[0] != '\0')
380 str_print(fp, " Serial Number", ip->smbi_serial);
381 if (ip->smbi_asset[0] != '\0')
382 str_print(fp, " Asset Tag", ip->smbi_asset);
383 if (ip->smbi_location[0] != '\0')
384 str_print(fp, " Location Tag", ip->smbi_location);
385 if (ip->smbi_part[0] != '\0')
386 str_print(fp, " Part Number", ip->smbi_part);
387 }
388
389 static void
print_bios(smbios_hdl_t * shp,FILE * fp)390 print_bios(smbios_hdl_t *shp, FILE *fp)
391 {
392 smbios_bios_t b;
393
394 if (smbios_info_bios(shp, &b) == -1) {
395 smbios_warn(shp, "failed to read BIOS information");
396 return;
397 }
398
399 str_print(fp, " Vendor", b.smbb_vendor);
400 str_print(fp, " Version String", b.smbb_version);
401 str_print(fp, " Release Date", b.smbb_reldate);
402 oprintf(fp, " Address Segment: 0x%x\n", b.smbb_segment);
403 oprintf(fp, " ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
404 oprintf(fp, " Image Size: %u bytes\n", b.smbb_runsize);
405
406 flag64_printf(fp, "Characteristics",
407 b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
408 smbios_bios_flag_name, smbios_bios_flag_desc);
409
410 if (b.smbb_nxcflags > SMB_BIOSXB_1) {
411 flag_printf(fp, "Characteristics Extension Byte 1",
412 b.smbb_xcflags[SMB_BIOSXB_1],
413 sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
414 smbios_bios_xb1_name, smbios_bios_xb1_desc);
415 }
416
417 if (b.smbb_nxcflags > SMB_BIOSXB_2) {
418 flag_printf(fp, "Characteristics Extension Byte 2",
419 b.smbb_xcflags[SMB_BIOSXB_2],
420 sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
421 smbios_bios_xb2_name, smbios_bios_xb2_desc);
422 }
423
424 if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
425 oprintf(fp, " Version Number: %u.%u\n",
426 b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
427 }
428
429 /*
430 * If the major and minor versions are 0xff then that indicates that the
431 * embedded controller does not exist.
432 */
433 if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
434 b.smbb_ecfwv.smbv_major != 0xff &&
435 b.smbb_ecfwv.smbv_minor != 0xff) {
436 oprintf(fp, " Embedded Ctlr Firmware Version Number: %u.%u\n",
437 b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
438 }
439 }
440
441 static void
print_system(smbios_hdl_t * shp,FILE * fp)442 print_system(smbios_hdl_t *shp, FILE *fp)
443 {
444 smbios_system_t s;
445 uint_t i;
446
447 if (smbios_info_system(shp, &s) == -1) {
448 smbios_warn(shp, "failed to read system information");
449 return;
450 }
451
452 oprintf(fp, " UUID: ");
453 for (i = 0; i < s.smbs_uuidlen; i++) {
454 oprintf(fp, "%02x", s.smbs_uuid[i]);
455 if (i == 3 || i == 5 || i == 7 || i == 9)
456 oprintf(fp, "-");
457 }
458 oprintf(fp, "\n");
459
460 desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
461 fp, " Wake-Up Event: 0x%x", s.smbs_wakeup);
462
463 str_print(fp, " SKU Number", s.smbs_sku);
464 str_print(fp, " Family", s.smbs_family);
465 }
466
467 static void
print_bboard(smbios_hdl_t * shp,id_t id,FILE * fp)468 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
469 {
470 smbios_bboard_t b;
471 int chdl_cnt;
472
473 if (smbios_info_bboard(shp, id, &b) != 0) {
474 smbios_warn(shp, "failed to read baseboard information");
475 return;
476 }
477
478 oprintf(fp, " Chassis: %u\n", (uint_t)b.smbb_chassis);
479
480 flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
481 smbios_bboard_flag_name, smbios_bboard_flag_desc);
482
483 desc_printf(smbios_bboard_type_desc(b.smbb_type),
484 fp, " Board Type: 0x%x", b.smbb_type);
485
486 chdl_cnt = b.smbb_contn;
487 if (chdl_cnt != 0) {
488 id_t *chdl;
489 uint16_t hdl;
490 int i, n, cnt;
491
492 chdl = alloca(chdl_cnt * sizeof (id_t));
493 cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
494 if (cnt > SMB_CONT_MAX)
495 return;
496 n = MIN(chdl_cnt, cnt);
497
498 oprintf(fp, "\n");
499 for (i = 0; i < n; i++) {
500 hdl = (uint16_t)chdl[i];
501 oprintf(fp, " Contained Handle: %u\n", hdl);
502 }
503 }
504 }
505
506 static void
print_chassis(smbios_hdl_t * shp,id_t id,FILE * fp)507 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
508 {
509 smbios_chassis_t c;
510 smbios_chassis_entry_t *elts;
511 uint_t nelts, i;
512
513 if (smbios_info_chassis(shp, id, &c) != 0) {
514 smbios_warn(shp, "failed to read chassis information");
515 return;
516 }
517
518 oprintf(fp, " OEM Data: 0x%x\n", c.smbc_oemdata);
519 str_print(fp, " SKU Number",
520 c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
521 oprintf(fp, " Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
522
523 desc_printf(smbios_chassis_type_desc(c.smbc_type),
524 fp, " Chassis Type: 0x%x", c.smbc_type);
525
526 desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
527 fp, " Boot-Up State: 0x%x", c.smbc_bustate);
528
529 desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
530 fp, " Power Supply State: 0x%x", c.smbc_psstate);
531
532 desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
533 fp, " Thermal State: 0x%x", c.smbc_thstate);
534
535 oprintf(fp, " Chassis Height: %uu\n", c.smbc_uheight);
536 oprintf(fp, " Power Cords: %u\n", c.smbc_cords);
537
538 oprintf(fp, " Element Records: %u\n", c.smbc_elems);
539
540 if (c.smbc_elems == 0) {
541 return;
542 }
543
544 if (smbios_info_chassis_elts(shp, id, &nelts, &elts) != 0) {
545 smbios_warn(shp, "failed to read chassis elements");
546 return;
547 }
548
549 oprintf(fp, "\n");
550
551 for (i = 0; i < nelts; i++) {
552 switch (elts[i].smbce_type) {
553 case SMB_CELT_BBOARD:
554 desc_printf(smbios_bboard_type_desc(elts[i].smbce_elt),
555 fp, " Contained SMBIOS Base Board Type: 0x%x",
556 elts[i].smbce_elt);
557 break;
558 case SMB_CELT_SMBIOS:
559 desc_printf(smbios_type_name(elts[i].smbce_elt), fp,
560 " Contained SMBIOS structure Type: %u",
561 elts[i].smbce_elt);
562 break;
563 default:
564 oprintf(fp, " Unknown contained Type: %u/%u\n",
565 elts[i].smbce_type, elts[i].smbce_elt);
566 break;
567 }
568 oprintf(fp, " Minimum number: %u\n", elts[i].smbce_min);
569 oprintf(fp, " Maximum number: %u\n", elts[i].smbce_max);
570 }
571 }
572
573 static void
print_processor(smbios_hdl_t * shp,id_t id,FILE * fp)574 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
575 {
576 smbios_processor_t p;
577 uint_t status;
578
579 if (smbios_info_processor(shp, id, &p) != 0) {
580 smbios_warn(shp, "failed to read processor information");
581 return;
582 }
583 status = SMB_PRSTATUS_STATUS(p.smbp_status);
584
585 desc_printf(smbios_processor_family_desc(p.smbp_family),
586 fp, " Family: %u", p.smbp_family);
587
588 oprintf(fp, " CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
589
590 desc_printf(smbios_processor_type_desc(p.smbp_type),
591 fp, " Type: %u", p.smbp_type);
592
593 desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
594 fp, " Socket Upgrade: %u", p.smbp_upgrade);
595
596 oprintf(fp, " Socket Status: %s\n",
597 SMB_PRSTATUS_PRESENT(p.smbp_status) ?
598 "Populated" : "Not Populated");
599
600 desc_printf(smbios_processor_status_desc(status),
601 fp, " Processor Status: %u", status);
602
603 if (SMB_PRV_LEGACY(p.smbp_voltage)) {
604 oprintf(fp, " Supported Voltages:");
605 switch (p.smbp_voltage) {
606 case SMB_PRV_5V:
607 oprintf(fp, " 5.0V");
608 break;
609 case SMB_PRV_33V:
610 oprintf(fp, " 3.3V");
611 break;
612 case SMB_PRV_29V:
613 oprintf(fp, " 2.9V");
614 break;
615 }
616 oprintf(fp, "\n");
617 } else {
618 oprintf(fp, " Supported Voltages: %.1fV\n",
619 (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
620 }
621
622 if (p.smbp_corecount != 0) {
623 oprintf(fp, " Core Count: %u\n", p.smbp_corecount);
624 } else {
625 oprintf(fp, " Core Count: Unknown\n");
626 }
627
628 if (p.smbp_coresenabled != 0) {
629 oprintf(fp, " Cores Enabled: %u\n", p.smbp_coresenabled);
630 } else {
631 oprintf(fp, " Cores Enabled: Unknown\n");
632 }
633
634 if (p.smbp_threadcount != 0) {
635 oprintf(fp, " Thread Count: %u\n", p.smbp_threadcount);
636 } else {
637 oprintf(fp, " Thread Count: Unknown\n");
638 }
639
640 if (p.smbp_cflags) {
641 flag_printf(fp, "Processor Characteristics",
642 p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
643 smbios_processor_core_flag_name,
644 smbios_processor_core_flag_desc);
645 }
646
647 if (p.smbp_clkspeed != 0)
648 oprintf(fp, " External Clock Speed: %uMHz\n", p.smbp_clkspeed);
649 else
650 oprintf(fp, " External Clock Speed: Unknown\n");
651
652 if (p.smbp_maxspeed != 0)
653 oprintf(fp, " Maximum Speed: %uMHz\n", p.smbp_maxspeed);
654 else
655 oprintf(fp, " Maximum Speed: Unknown\n");
656
657 if (p.smbp_curspeed != 0)
658 oprintf(fp, " Current Speed: %uMHz\n", p.smbp_curspeed);
659 else
660 oprintf(fp, " Current Speed: Unknown\n");
661
662 id_printf(fp, " L1 Cache Handle: ", p.smbp_l1cache);
663 id_printf(fp, " L2 Cache Handle: ", p.smbp_l2cache);
664 id_printf(fp, " L3 Cache Handle: ", p.smbp_l3cache);
665
666 if (p.smbp_threadsenabled != 0) {
667 oprintf(fp, " Threads Enabled: %u\n", p.smbp_threadsenabled);
668 } else {
669 oprintf(fp, " Threads Enabled: Unknown\n");
670 }
671
672 /*
673 * The Socket Type string overlaps with the upgrade string. Only print
674 * something if we have a valid value.
675 */
676 if (*p.smbp_socktype != '\0') {
677 str_print(fp, " Socket Type", p.smbp_socktype);
678 }
679 }
680
681 static void
print_cache(smbios_hdl_t * shp,id_t id,FILE * fp)682 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
683 {
684 smbios_cache_t c;
685
686 if (smbios_info_cache(shp, id, &c) != 0) {
687 smbios_warn(shp, "failed to read cache information");
688 return;
689 }
690
691 oprintf(fp, " Level: %u\n", c.smba_level);
692 oprintf(fp, " Maximum Installed Size: %" PRIu64 " bytes\n",
693 c.smba_maxsize2);
694
695 if (c.smba_size2 != 0) {
696 oprintf(fp, " Installed Size: %" PRIu64 " bytes\n",
697 c.smba_size2);
698 } else {
699 oprintf(fp, " Installed Size: Not Installed\n");
700 }
701
702 if (c.smba_speed != 0)
703 oprintf(fp, " Speed: %uns\n", c.smba_speed);
704 else
705 oprintf(fp, " Speed: Unknown\n");
706
707 flag_printf(fp, "Supported SRAM Types",
708 c.smba_stype, sizeof (c.smba_stype) * NBBY,
709 smbios_cache_ctype_name, smbios_cache_ctype_desc);
710
711 desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
712 fp, " Current SRAM Type: 0x%x", c.smba_ctype);
713
714 desc_printf(smbios_cache_ecc_desc(c.smba_etype),
715 fp, " Error Correction Type: %u", c.smba_etype);
716
717 desc_printf(smbios_cache_logical_desc(c.smba_ltype),
718 fp, " Logical Cache Type: %u", c.smba_ltype);
719
720 desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
721 fp, " Associativity: %u", c.smba_assoc);
722
723 desc_printf(smbios_cache_mode_desc(c.smba_mode),
724 fp, " Mode: %u", c.smba_mode);
725
726 desc_printf(smbios_cache_loc_desc(c.smba_location),
727 fp, " Location: %u", c.smba_location);
728
729 flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
730 smbios_cache_flag_name, smbios_cache_flag_desc);
731 }
732
733 static void
print_port(smbios_hdl_t * shp,id_t id,FILE * fp)734 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
735 {
736 smbios_port_t p;
737
738 if (smbios_info_port(shp, id, &p) != 0) {
739 smbios_warn(shp, "failed to read port information");
740 return;
741 }
742
743 str_print(fp, " Internal Reference Designator", p.smbo_iref);
744 str_print(fp, " External Reference Designator", p.smbo_eref);
745
746 desc_printf(smbios_port_conn_desc(p.smbo_itype),
747 fp, " Internal Connector Type: %u", p.smbo_itype);
748
749 desc_printf(smbios_port_conn_desc(p.smbo_etype),
750 fp, " External Connector Type: %u", p.smbo_etype);
751
752 desc_printf(smbios_port_type_desc(p.smbo_ptype),
753 fp, " Port Type: %u", p.smbo_ptype);
754 }
755
756 static void
print_slot(smbios_hdl_t * shp,id_t id,FILE * fp)757 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
758 {
759 smbios_slot_t s;
760 smbios_version_t v;
761
762 if (smbios_info_slot(shp, id, &s) != 0) {
763 smbios_warn(shp, "failed to read slot information");
764 return;
765 }
766 smbios_info_smbios_version(shp, &v);
767
768 str_print(fp, " Reference Designator", s.smbl_name);
769 oprintf(fp, " Slot ID: 0x%x\n", s.smbl_id);
770
771 desc_printf(smbios_slot_type_desc(s.smbl_type),
772 fp, " Type: 0x%x", s.smbl_type);
773
774 desc_printf(smbios_slot_width_desc(s.smbl_width),
775 fp, " Width: 0x%x", s.smbl_width);
776
777 desc_printf(smbios_slot_usage_desc(s.smbl_usage),
778 fp, " Usage: 0x%x", s.smbl_usage);
779
780 desc_printf(smbios_slot_length_desc(s.smbl_length),
781 fp, " Length: 0x%x", s.smbl_length);
782
783 flag_printf(fp, "Slot Characteristics 1",
784 s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
785 smbios_slot_ch1_name, smbios_slot_ch1_desc);
786
787 flag_printf(fp, "Slot Characteristics 2",
788 s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
789 smbios_slot_ch2_name, smbios_slot_ch2_desc);
790
791 if (check_oem(shp) != 0 && !smbios_vergteq(&v, 2, 6))
792 return;
793
794 oprintf(fp, " Segment Group: %u\n", s.smbl_sg);
795 oprintf(fp, " Bus Number: %u\n", s.smbl_bus);
796 oprintf(fp, " Device/Function Number: %u/%u\n", s.smbl_df >> 3,
797 s.smbl_df & 0x7);
798
799 if (s.smbl_dbw != 0) {
800 oprintf(fp, " Data Bus Width: %d\n", s.smbl_dbw);
801 }
802
803 if (s.smbl_npeers > 0) {
804 smbios_slot_peer_t *peer;
805 uint_t i, npeers;
806
807 if (smbios_info_slot_peers(shp, id, &npeers, &peer) != 0) {
808 smbios_warn(shp, "failed to read slot peer "
809 "information");
810 return;
811 }
812
813 for (i = 0; i < npeers; i++) {
814 oprintf(fp, " Slot Peer %u:\n", i);
815 oprintf(fp, " Segment group: %u\n",
816 peer[i].smblp_group);
817 oprintf(fp, " Bus/Device/Function: %u/%u/%u\n",
818 peer[i].smblp_bus, peer[i].smblp_device,
819 peer[i].smblp_function);
820 oprintf(fp, " Electrical width: %u\n",
821 peer[i].smblp_data_width);
822 }
823
824 smbios_info_slot_peers_free(shp, npeers, peer);
825 }
826
827 if (s.smbl_info != 0) {
828 if (s.smbl_type >= SMB_SLT_PCIE &&
829 s.smbl_type <= SMB_SLT_PCIEG6P) {
830 oprintf(fp, " PCIe Generation: %d\n", s.smbl_info);
831 } else {
832 oprintf(fp, " Slot Type: 0x%x\n", s.smbl_info);
833 }
834 }
835
836 if (s.smbl_pwidth != 0) {
837 desc_printf(smbios_slot_width_desc(s.smbl_pwidth),
838 fp, " Physical Width: 0x%x", s.smbl_pwidth);
839 }
840
841 if (s.smbl_pitch != 0) {
842 oprintf(fp, " Slot Pitch: %u.%u mm\n", s.smbl_pitch / 100,
843 s.smbl_pitch % 100);
844 }
845
846 /*
847 * The slot height was introduced in SMBIOS 3.5. However, a value of
848 * zero here does not mean that it is unknown, but rather that the
849 * concept is not applicable. Therefore we cannot use a standard check
850 * against zero for this and instead use the version.
851 */
852 if (smbios_vergteq(&v, 3, 5)) {
853 desc_printf(smbios_slot_height_desc(s.smbl_height), fp,
854 " Height: 0x%x", s.smbl_height);
855 } else {
856 oprintf(fp, " Height: unknown\n");
857 }
858 }
859
860 static void
print_obdevs_ext(smbios_hdl_t * shp,id_t id,FILE * fp)861 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
862 {
863 boolean_t enabled;
864 smbios_obdev_ext_t oe;
865 const char *type;
866
867 if (smbios_info_obdevs_ext(shp, id, &oe) != 0) {
868 smbios_warn(shp, "failed to read extended on-board devices "
869 "information");
870 return;
871 }
872
873 /*
874 * Bit 7 is always whether or not the device is enabled while bits 0:6
875 * are the actual device type.
876 */
877 enabled = oe.smboe_dtype >> 7;
878 type = smbios_onboard_ext_type_desc(oe.smboe_dtype & 0x7f);
879
880 str_print(fp, " Reference Designator", oe.smboe_name);
881 oprintf(fp, " Device Enabled: %s\n", enabled == B_TRUE ? "true" :
882 "false");
883 oprintf(fp, " Device Type: %s\n", type);
884 oprintf(fp, " Device Type Instance: %u\n", oe.smboe_dti);
885 oprintf(fp, " Segment Group Number: %u\n", oe.smboe_sg);
886 oprintf(fp, " Bus Number: %u\n", oe.smboe_bus);
887 oprintf(fp, " Device/Function Number: %u\n", oe.smboe_df);
888 }
889
890 static void
print_obdevs(smbios_hdl_t * shp,id_t id,FILE * fp)891 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
892 {
893 smbios_obdev_t *argv;
894 int i, argc;
895
896 if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
897 argv = alloca(sizeof (smbios_obdev_t) * argc);
898 if (smbios_info_obdevs(shp, id, argc, argv) == -1) {
899 smbios_warn(shp, "failed to read on-board device "
900 "information");
901 return;
902 }
903 for (i = 0; i < argc; i++)
904 str_print_nolabel(fp, " ", argv[i].smbd_name);
905 }
906 }
907
908 static void
print_strtab(smbios_hdl_t * shp,id_t id,FILE * fp)909 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
910 {
911 const char **argv;
912 int i, argc;
913
914 if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
915 argv = alloca(sizeof (char *) * argc);
916 if (smbios_info_strtab(shp, id, argc, argv) == -1) {
917 smbios_warn(shp, "failed to read string table "
918 "information");
919 return;
920 }
921 for (i = 0; i < argc; i++)
922 str_print_nolabel(fp, " ", argv[i]);
923 }
924 }
925
926 static void
print_lang(smbios_hdl_t * shp,id_t id,FILE * fp)927 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
928 {
929 smbios_lang_t l;
930
931 if (smbios_info_lang(shp, &l) == -1) {
932 smbios_warn(shp, "failed to read language information");
933 return;
934 }
935
936 str_print(fp, " Current Language", l.smbla_cur);
937 oprintf(fp, " Language String Format: %u\n", l.smbla_fmt);
938 oprintf(fp, " Number of Installed Languages: %u\n", l.smbla_num);
939 oprintf(fp, " Installed Languages:\n");
940
941 print_strtab(shp, id, fp);
942 }
943
944 /*ARGSUSED*/
945 static void
print_evlog(smbios_hdl_t * shp,id_t id,FILE * fp)946 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
947 {
948 smbios_evlog_t ev;
949 uint32_t i;
950
951 if (smbios_info_eventlog(shp, &ev) == -1) {
952 smbios_warn(shp, "failed to read event log information");
953 return;
954 }
955
956 oprintf(fp, " Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
957 oprintf(fp, " Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
958 oprintf(fp, " Data Offset: %lu\n", (ulong_t)ev.smbev_data);
959
960 desc_printf(smbios_evlog_method_desc(ev.smbev_method),
961 fp, " Data Access Method: %u", ev.smbev_method);
962
963 flag_printf(fp, "Log Flags",
964 ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
965 smbios_evlog_flag_name, smbios_evlog_flag_desc);
966
967 desc_printf(smbios_evlog_format_desc(ev.smbev_format),
968 fp, " Log Header Format: %u", ev.smbev_format);
969
970 oprintf(fp, " Update Token: 0x%x\n", ev.smbev_token);
971 oprintf(fp, " Data Access Address: ");
972
973 switch (ev.smbev_method) {
974 case SMB_EVM_1x1i_1x1d:
975 case SMB_EVM_2x1i_1x1d:
976 case SMB_EVM_1x2i_1x1d:
977 oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
978 ev.smbev_addr.eva_io.evi_iaddr,
979 ev.smbev_addr.eva_io.evi_daddr);
980 break;
981 case SMB_EVM_GPNV:
982 oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
983 break;
984 default:
985 oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
986 }
987
988 oprintf(fp, " Type Descriptors:\n");
989
990 for (i = 0; i < ev.smbev_typec; i++) {
991 oprintf(fp, " %u: Log Type 0x%x, Data Type 0x%x\n", i,
992 ev.smbev_typev[i].smbevt_ltype,
993 ev.smbev_typev[i].smbevt_dtype);
994 }
995 }
996
997 static void
print_bytes(const uint8_t * data,size_t size,FILE * fp)998 print_bytes(const uint8_t *data, size_t size, FILE *fp)
999 {
1000 size_t row, rows = P2ROUNDUP(size, 16) / 16;
1001 size_t col, cols;
1002
1003 char buf[17];
1004 uint8_t x;
1005
1006 oprintf(fp, "\n offset: 0 1 2 3 4 5 6 7 8 9 a b c d e f "
1007 "0123456789abcdef\n");
1008
1009 for (row = 0; row < rows; row++) {
1010 oprintf(fp, " %#6lx: ", (ulong_t)row * 16);
1011 cols = MIN(size - row * 16, 16);
1012
1013 for (col = 0; col < cols; col++) {
1014 if (col % 4 == 0)
1015 oprintf(fp, " ");
1016 x = *data++;
1017 oprintf(fp, "%02x", x);
1018 buf[col] = x <= ' ' || x > '~' ? '.' : x;
1019 }
1020
1021 for (; col < 16; col++) {
1022 if (col % 4 == 0)
1023 oprintf(fp, " ");
1024 oprintf(fp, " ");
1025 buf[col] = ' ';
1026 }
1027
1028 buf[col] = '\0';
1029 oprintf(fp, " %s\n", buf);
1030 }
1031
1032 oprintf(fp, "\n");
1033 }
1034
1035 static void
print_memarray(smbios_hdl_t * shp,id_t id,FILE * fp)1036 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1037 {
1038 smbios_memarray_t ma;
1039
1040 if (smbios_info_memarray(shp, id, &ma) != 0) {
1041 smbios_warn(shp, "failed to read memarray information");
1042 return;
1043 }
1044
1045 desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
1046 fp, " Location: %u", ma.smbma_location);
1047
1048 desc_printf(smbios_memarray_use_desc(ma.smbma_use),
1049 fp, " Use: %u", ma.smbma_use);
1050
1051 desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
1052 fp, " ECC: %u", ma.smbma_ecc);
1053
1054 oprintf(fp, " Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
1055 id_printf(fp, " Memory Error Data: ", ma.smbma_err);
1056 oprintf(fp, " Max Capacity: %llu bytes\n",
1057 (u_longlong_t)ma.smbma_size);
1058 }
1059
1060 static void
print_memdevice(smbios_hdl_t * shp,id_t id,FILE * fp)1061 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1062 {
1063 smbios_memdevice_t md;
1064
1065 if (smbios_info_memdevice(shp, id, &md) != 0) {
1066 smbios_warn(shp, "failed to read memory device information");
1067 return;
1068 }
1069
1070 id_printf(fp, " Physical Memory Array: ", md.smbmd_array);
1071 id_printf(fp, " Memory Error Data: ", md.smbmd_error);
1072
1073 if (md.smbmd_twidth != -1u)
1074 oprintf(fp, " Total Width: %u bits\n", md.smbmd_twidth);
1075 else
1076 oprintf(fp, " Total Width: Unknown\n");
1077
1078 if (md.smbmd_dwidth != -1u)
1079 oprintf(fp, " Data Width: %u bits\n", md.smbmd_dwidth);
1080 else
1081 oprintf(fp, " Data Width: Unknown\n");
1082
1083 switch (md.smbmd_size) {
1084 case -1ull:
1085 oprintf(fp, " Size: Unknown\n");
1086 break;
1087 case 0:
1088 oprintf(fp, " Size: Not Populated\n");
1089 break;
1090 default:
1091 oprintf(fp, " Size: %llu bytes\n",
1092 (u_longlong_t)md.smbmd_size);
1093 }
1094
1095 desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
1096 fp, " Form Factor: %u", md.smbmd_form);
1097
1098 if (md.smbmd_set == 0)
1099 oprintf(fp, " Set: None\n");
1100 else if (md.smbmd_set == (uint8_t)-1u)
1101 oprintf(fp, " Set: Unknown\n");
1102 else
1103 oprintf(fp, " Set: %u\n", md.smbmd_set);
1104
1105 if (md.smbmd_rank != 0) {
1106 desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
1107 fp, " Rank: %u", md.smbmd_rank);
1108 } else {
1109 oprintf(fp, " Rank: Unknown\n");
1110 }
1111
1112 desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
1113 fp, " Memory Type: %u", md.smbmd_type);
1114
1115 flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
1116 smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
1117
1118 if (md.smbmd_extspeed != 0) {
1119 oprintf(fp, " Speed: %" PRIu64 " MT/s\n", md.smbmd_extspeed);
1120 } else {
1121 oprintf(fp, " Speed: Unknown\n");
1122 }
1123
1124 if (md.smbmd_extclkspeed != 0) {
1125 oprintf(fp, " Configured Speed: %" PRIu64 " MT/s\n",
1126 md.smbmd_extclkspeed);
1127 } else {
1128 oprintf(fp, " Configured Speed: Unknown\n");
1129 }
1130
1131 str_print(fp, " Device Locator", md.smbmd_dloc);
1132 str_print(fp, " Bank Locator", md.smbmd_bloc);
1133
1134 if (md.smbmd_minvolt != 0) {
1135 oprintf(fp, " Minimum Voltage: %.2fV\n",
1136 md.smbmd_minvolt / 1000.0);
1137 } else {
1138 oprintf(fp, " Minimum Voltage: Unknown\n");
1139 }
1140
1141 if (md.smbmd_maxvolt != 0) {
1142 oprintf(fp, " Maximum Voltage: %.2fV\n",
1143 md.smbmd_maxvolt / 1000.0);
1144 } else {
1145 oprintf(fp, " Maximum Voltage: Unknown\n");
1146 }
1147
1148 if (md.smbmd_confvolt != 0) {
1149 oprintf(fp, " Configured Voltage: %.2fV\n",
1150 md.smbmd_confvolt / 1000.0);
1151 } else {
1152 oprintf(fp, " Configured Voltage: Unknown\n");
1153 }
1154
1155 if (md.smbmd_memtech != 0) {
1156 desc_printf(smbios_memdevice_memtech_desc(md.smbmd_memtech),
1157 fp, " Memory Technology: %u", md.smbmd_memtech);
1158 }
1159
1160 if (md.smbmd_opcap_flags != 0) {
1161 flag_printf(fp, "Operating Mode Capabilities",
1162 md.smbmd_opcap_flags, sizeof (md.smbmd_opcap_flags) * NBBY,
1163 smbios_memdevice_op_capab_name,
1164 smbios_memdevice_op_capab_desc);
1165 }
1166
1167 if (md.smbmd_firmware_rev[0] != '\0') {
1168 str_print(fp, " Firmware Revision", md.smbmd_firmware_rev);
1169 }
1170
1171 if (md.smbmd_modmfg_id != SMB_MD_MFG_UNKNOWN) {
1172 jedec_print(fp, "Module Manufacturer ID", md.smbmd_modmfg_id);
1173 }
1174
1175 if (md.smbmd_modprod_id != 0) {
1176 jedec_print(fp, "Module Product ID", md.smbmd_modprod_id);
1177 }
1178
1179 if (md.smbmd_cntrlmfg_id != SMB_MD_MFG_UNKNOWN) {
1180 jedec_print(fp, "Memory Subsystem Controller Manufacturer ID",
1181 md.smbmd_cntrlmfg_id);
1182 }
1183
1184 if (md.smbmd_cntrlprod_id != 0) {
1185 jedec_print(fp, "Memory Subsystem Controller Product ID",
1186 md.smbmd_cntrlprod_id);
1187 }
1188
1189 if (md.smbmd_nvsize == UINT64_MAX) {
1190 oprintf(fp, " Non-volatile Size: Unknown\n");
1191 } else if (md.smbmd_nvsize != 0) {
1192 oprintf(fp, " Non-volatile Size: %llu bytes\n",
1193 (u_longlong_t)md.smbmd_nvsize);
1194 }
1195
1196 if (md.smbmd_volatile_size == UINT64_MAX) {
1197 oprintf(fp, " Volatile Size: Unknown\n");
1198 } else if (md.smbmd_volatile_size != 0) {
1199 oprintf(fp, " Volatile Size: %llu bytes\n",
1200 (u_longlong_t)md.smbmd_volatile_size);
1201 }
1202
1203 if (md.smbmd_cache_size == UINT64_MAX) {
1204 oprintf(fp, " Cache Size: Unknown\n");
1205 } else if (md.smbmd_cache_size != 0) {
1206 oprintf(fp, " Cache Size: %llu bytes\n",
1207 (u_longlong_t)md.smbmd_cache_size);
1208 }
1209
1210 if (md.smbmd_logical_size == UINT64_MAX) {
1211 oprintf(fp, " Logical Size: Unknown\n");
1212 } else if (md.smbmd_logical_size != 0) {
1213 oprintf(fp, " Logical Size: %llu bytes\n",
1214 (u_longlong_t)md.smbmd_logical_size);
1215 }
1216
1217 if (md.smbmd_pmic0_mfgid != SMB_MD_MFG_UNKNOWN) {
1218 jedec_print(fp, "PMIC0 Manufacturer ID", md.smbmd_pmic0_mfgid);
1219 }
1220
1221 if (md.smbmd_pmic0_rev != SMB_MD_REV_UNKNOWN) {
1222 jedec_rev_print(fp, "PMIC0 Revision", md.smbmd_pmic0_rev);
1223 }
1224
1225 if (md.smbmd_rcd_mfgid != SMB_MD_MFG_UNKNOWN) {
1226 jedec_print(fp, "RCD Manufacturer ID", md.smbmd_rcd_mfgid);
1227 }
1228
1229 if (md.smbmd_rcd_rev != SMB_MD_REV_UNKNOWN) {
1230 jedec_rev_print(fp, "RCD Revision", md.smbmd_rcd_rev);
1231 }
1232 }
1233
1234 static void
print_memarrmap(smbios_hdl_t * shp,id_t id,FILE * fp)1235 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1236 {
1237 smbios_memarrmap_t ma;
1238
1239 if (smbios_info_memarrmap(shp, id, &ma) != 0) {
1240 smbios_warn(shp, "failed to read memory array map information");
1241 return;
1242 }
1243
1244 id_printf(fp, " Physical Memory Array: ", ma.smbmam_array);
1245 oprintf(fp, " Devices per Row: %u\n", ma.smbmam_width);
1246
1247 oprintf(fp, " Physical Address: 0x%llx\n Size: %llu bytes\n",
1248 (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
1249 }
1250
1251 static void
print_memdevmap(smbios_hdl_t * shp,id_t id,FILE * fp)1252 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1253 {
1254 smbios_memdevmap_t md;
1255
1256 if (smbios_info_memdevmap(shp, id, &md) != 0) {
1257 smbios_warn(shp, "failed to read memory device map "
1258 "information");
1259 return;
1260 }
1261
1262 id_printf(fp, " Memory Device: ", md.smbmdm_device);
1263 id_printf(fp, " Memory Array Mapped Address: ", md.smbmdm_arrmap);
1264
1265 oprintf(fp, " Physical Address: 0x%llx\n Size: %llu bytes\n",
1266 (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
1267
1268 oprintf(fp, " Partition Row Position: %u\n", md.smbmdm_rpos);
1269 oprintf(fp, " Interleave Position: %u\n", md.smbmdm_ipos);
1270 oprintf(fp, " Interleave Data Depth: %u\n", md.smbmdm_idepth);
1271 }
1272
1273 static void
print_hwsec(smbios_hdl_t * shp,FILE * fp)1274 print_hwsec(smbios_hdl_t *shp, FILE *fp)
1275 {
1276 smbios_hwsec_t h;
1277
1278 if (smbios_info_hwsec(shp, &h) == -1) {
1279 smbios_warn(shp, "failed to read hwsec information");
1280 return;
1281 }
1282
1283 desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
1284 fp, " Power-On Password Status: %u", h.smbh_pwr_ps);
1285 desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
1286 fp, " Keyboard Password Status: %u", h.smbh_kbd_ps);
1287 desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
1288 fp, " Administrator Password Status: %u", h.smbh_adm_ps);
1289 desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
1290 fp, " Front Panel Reset Status: %u", h.smbh_pan_ps);
1291 }
1292
1293 static void
print_vprobe(smbios_hdl_t * shp,id_t id,FILE * fp)1294 print_vprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1295 {
1296 smbios_vprobe_t vp;
1297
1298 if (smbios_info_vprobe(shp, id, &vp) != 0) {
1299 smbios_warn(shp, "failed to read voltage probe information");
1300 return;
1301 }
1302
1303 str_print(fp, " Description", vp.smbvp_description != NULL ?
1304 vp.smbvp_description : "unknown");
1305 desc_printf(smbios_vprobe_loc_desc(vp.smbvp_location),
1306 fp, " Location: %u", vp.smbvp_location);
1307 desc_printf(smbios_vprobe_status_desc(vp.smbvp_status),
1308 fp, " Status: %u", vp.smbvp_status);
1309
1310 if (vp.smbvp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1311 oprintf(fp, " Maximum Possible Voltage: %u mV\n",
1312 vp.smbvp_maxval);
1313 } else {
1314 oprintf(fp, " Maximum Possible Voltage: unknown\n");
1315 }
1316
1317 if (vp.smbvp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1318 oprintf(fp, " Minimum Possible Voltage: %u mV\n",
1319 vp.smbvp_minval);
1320 } else {
1321 oprintf(fp, " Minimum Possible Voltage: unknown\n");
1322 }
1323
1324 if (vp.smbvp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1325 oprintf(fp, " Probe Resolution: %u.%u mV\n",
1326 vp.smbvp_resolution / 10,
1327 vp.smbvp_resolution % 10);
1328 } else {
1329 oprintf(fp, " Probe Resolution: unknown\n");
1330 }
1331
1332 if (vp.smbvp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1333 oprintf(fp, " Probe Tolerance: +/-%u mV\n",
1334 vp.smbvp_tolerance);
1335 } else {
1336 oprintf(fp, " Probe Tolerance: unknown\n");
1337 }
1338
1339 if (vp.smbvp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1340 oprintf(fp, " Probe Accuracy: +/-%u.%02u%%\n",
1341 vp.smbvp_accuracy / 100,
1342 vp.smbvp_accuracy % 100);
1343 } else {
1344 oprintf(fp, " Probe Accuracy: unknown\n");
1345 }
1346
1347 oprintf(fp, " OEM- or BIOS- defined value: 0x%x\n", vp.smbvp_oem);
1348
1349 if (vp.smbvp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1350 oprintf(fp, " Probe Nominal Value: %u mV\n", vp.smbvp_nominal);
1351 } else {
1352 oprintf(fp, " Probe Nominal Value: unknown\n");
1353 }
1354 }
1355
1356 static void
print_cooldev(smbios_hdl_t * shp,id_t id,FILE * fp)1357 print_cooldev(smbios_hdl_t *shp, id_t id, FILE *fp)
1358 {
1359 smbios_cooldev_t cd;
1360
1361 if (smbios_info_cooldev(shp, id, &cd) != 0) {
1362 smbios_warn(shp, "failed to read cooling device "
1363 "information");
1364 return;
1365 }
1366
1367 id_printf(fp, " Temperature Probe Handle: ", cd.smbcd_tprobe);
1368 desc_printf(smbios_cooldev_type_desc(cd.smbcd_type),
1369 fp, " Device Type: %u", cd.smbcd_type);
1370 desc_printf(smbios_cooldev_status_desc(cd.smbcd_status),
1371 fp, " Status: %u", cd.smbcd_status);
1372 oprintf(fp, " Cooling Unit Group: %u\n", cd.smbcd_group);
1373 oprintf(fp, " OEM- or BIOS- defined data: 0x%x\n", cd.smbcd_oem);
1374 if (cd.smbcd_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1375 oprintf(fp, " Nominal Speed: %u RPM\n", cd.smbcd_nominal);
1376 } else {
1377 oprintf(fp, " Nominal Speed: unknown\n");
1378 }
1379
1380 if (cd.smbcd_descr != NULL && cd.smbcd_descr[0] != '\0') {
1381 str_print(fp, " Description", cd.smbcd_descr);
1382 }
1383 }
1384
1385 static void
print_tprobe(smbios_hdl_t * shp,id_t id,FILE * fp)1386 print_tprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1387 {
1388 smbios_tprobe_t tp;
1389
1390 if (smbios_info_tprobe(shp, id, &tp) != 0) {
1391 smbios_warn(shp, "failed to read temperature probe "
1392 "information");
1393 return;
1394 }
1395
1396 str_print(fp, " Description", tp.smbtp_description != NULL ?
1397 tp.smbtp_description : "unknown");
1398 desc_printf(smbios_tprobe_loc_desc(tp.smbtp_location),
1399 fp, " Location: %u", tp.smbtp_location);
1400 desc_printf(smbios_tprobe_status_desc(tp.smbtp_status),
1401 fp, " Status: %u", tp.smbtp_status);
1402
1403 if (tp.smbtp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1404 oprintf(fp, " Maximum Possible Temperature: %u.%u C\n",
1405 tp.smbtp_maxval / 10, tp.smbtp_maxval % 10);
1406 } else {
1407 oprintf(fp, " Maximum Possible Temperature: unknown\n");
1408 }
1409
1410 if (tp.smbtp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1411 oprintf(fp, " Minimum Possible Temperature: %u.%u C\n",
1412 tp.smbtp_minval / 10, tp.smbtp_minval % 10);
1413 } else {
1414 oprintf(fp, " Minimum Possible Temperature: unknown\n");
1415 }
1416
1417 if (tp.smbtp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1418 oprintf(fp, " Probe Resolution: %u.%03u C\n",
1419 tp.smbtp_resolution / 1000,
1420 tp.smbtp_resolution % 1000);
1421 } else {
1422 oprintf(fp, " Probe Resolution: unknown\n");
1423 }
1424
1425 if (tp.smbtp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1426 oprintf(fp, " Probe Tolerance: +/-%u.%u C\n",
1427 tp.smbtp_tolerance / 10, tp.smbtp_tolerance % 10);
1428 } else {
1429 oprintf(fp, " Probe Tolerance: unknown\n");
1430 }
1431
1432 if (tp.smbtp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1433 oprintf(fp, " Probe Accuracy: +/-%u.%02u%%\n",
1434 tp.smbtp_accuracy / 100,
1435 tp.smbtp_accuracy % 100);
1436 } else {
1437 oprintf(fp, " Probe Accuracy: unknown\n");
1438 }
1439
1440 oprintf(fp, " OEM- or BIOS- defined value: 0x%x\n", tp.smbtp_oem);
1441
1442 if (tp.smbtp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1443 oprintf(fp, " Probe Nominal Value: %u.%u C\n",
1444 tp.smbtp_nominal / 10, tp.smbtp_nominal % 10);
1445 } else {
1446 oprintf(fp, " Probe Nominal Value: unknown\n");
1447 }
1448 }
1449
1450 static void
print_iprobe(smbios_hdl_t * shp,id_t id,FILE * fp)1451 print_iprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1452 {
1453 smbios_iprobe_t ip;
1454
1455 if (smbios_info_iprobe(shp, id, &ip) != 0) {
1456 smbios_warn(shp, "failed to read current probe information");
1457 return;
1458 }
1459
1460 str_print(fp, " Description", ip.smbip_description != NULL ?
1461 ip.smbip_description : "unknown");
1462 desc_printf(smbios_iprobe_loc_desc(ip.smbip_location),
1463 fp, " Location: %u", ip.smbip_location);
1464 desc_printf(smbios_iprobe_status_desc(ip.smbip_status),
1465 fp, " Status: %u", ip.smbip_status);
1466
1467 if (ip.smbip_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1468 oprintf(fp, " Maximum Possible Current: %u mA\n",
1469 ip.smbip_maxval);
1470 } else {
1471 oprintf(fp, " Maximum Possible Current: unknown\n");
1472 }
1473
1474 if (ip.smbip_minval != SMB_PROBE_UNKNOWN_VALUE) {
1475 oprintf(fp, " Minimum Possible Current: %u mA\n",
1476 ip.smbip_minval);
1477 } else {
1478 oprintf(fp, " Minimum Possible Current: unknown\n");
1479 }
1480
1481 if (ip.smbip_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1482 oprintf(fp, " Probe Resolution: %u.%u mA\n",
1483 ip.smbip_resolution / 10,
1484 ip.smbip_resolution % 10);
1485 } else {
1486 oprintf(fp, " Probe Resolution: unknown\n");
1487 }
1488
1489 if (ip.smbip_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1490 oprintf(fp, " Probe Tolerance: +/-%u mA\n",
1491 ip.smbip_tolerance);
1492 } else {
1493 oprintf(fp, " Probe Tolerance: unknown\n");
1494 }
1495
1496 if (ip.smbip_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1497 oprintf(fp, " Probe Accuracy: +/-%u.%02u%%\n",
1498 ip.smbip_accuracy / 100,
1499 ip.smbip_accuracy % 100);
1500 } else {
1501 oprintf(fp, " Probe Accuracy: unknown\n");
1502 }
1503
1504 oprintf(fp, " OEM- or BIOS- defined value: 0x%x\n", ip.smbip_oem);
1505
1506 if (ip.smbip_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1507 oprintf(fp, " Probe Nominal Value: %u mA\n", ip.smbip_nominal);
1508 } else {
1509 oprintf(fp, " Probe Nominal Value: unknown\n");
1510 }
1511 }
1512
1513
1514 static void
print_boot(smbios_hdl_t * shp,FILE * fp)1515 print_boot(smbios_hdl_t *shp, FILE *fp)
1516 {
1517 smbios_boot_t b;
1518
1519 if (smbios_info_boot(shp, &b) == -1) {
1520 smbios_warn(shp, "failed to read boot information");
1521 return;
1522 }
1523
1524 desc_printf(smbios_boot_desc(b.smbt_status),
1525 fp, " Boot Status Code: 0x%x", b.smbt_status);
1526
1527 if (b.smbt_size != 0) {
1528 oprintf(fp, " Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
1529 print_bytes(b.smbt_data, b.smbt_size, fp);
1530 }
1531 }
1532
1533 static void
print_ipmi(smbios_hdl_t * shp,FILE * fp)1534 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1535 {
1536 smbios_ipmi_t i;
1537
1538 if (smbios_info_ipmi(shp, &i) == -1) {
1539 smbios_warn(shp, "failed to read ipmi information");
1540 return;
1541 }
1542
1543 desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1544 fp, " Type: %u", i.smbip_type);
1545
1546 oprintf(fp, " BMC IPMI Version: %u.%u\n",
1547 i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1548
1549 oprintf(fp, " i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1550 oprintf(fp, " NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1551 oprintf(fp, " BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1552 oprintf(fp, " Interrupt Number: %u\n", i.smbip_intr);
1553 oprintf(fp, " Register Spacing: %u\n", i.smbip_regspacing);
1554
1555 flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1556 smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1557 }
1558
1559 static void
print_powersup(smbios_hdl_t * shp,id_t id,FILE * fp)1560 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1561 {
1562 smbios_powersup_t p;
1563
1564 if (smbios_info_powersup(shp, id, &p) != 0) {
1565 smbios_warn(shp, "failed to read power supply information");
1566 return;
1567 }
1568
1569 oprintf(fp, " Power Supply Group: %u\n", p.smbps_group);
1570 if (p.smbps_maxout != 0x8000) {
1571 oprintf(fp, " Maximum Output: %llu mW\n", p.smbps_maxout);
1572 } else {
1573 oprintf(fp, " Maximum Output: unknown\n");
1574 }
1575
1576 flag_printf(fp, "Characteristics", p.smbps_flags,
1577 sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1578 smbios_powersup_flag_desc);
1579
1580 desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1581 fp, " Input Voltage Range Switching: %u", p.smbps_ivrs);
1582 desc_printf(smbios_powersup_status_desc(p.smbps_status),
1583 fp, " Status: %u", p.smbps_status);
1584 desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1585 fp, " Type: %u", p.smbps_pstype);
1586
1587 if (p.smbps_vprobe != 0xffff) {
1588 oprintf(fp, " Voltage Probe Handle: %lu\n", p.smbps_vprobe);
1589 }
1590
1591 if (p.smbps_cooldev != 0xffff) {
1592 oprintf(fp, " Cooling Device Handle: %lu\n", p.smbps_cooldev);
1593 }
1594
1595 if (p.smbps_iprobe != 0xffff) {
1596 oprintf(fp, " Current Probe Handle: %lu\n", p.smbps_iprobe);
1597 }
1598 }
1599
1600 static void
print_addinfo(smbios_hdl_t * shp,id_t id,FILE * fp)1601 print_addinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1602 {
1603 uint_t nents, i;
1604
1605 if (smbios_info_addinfo_nents(shp, id, &nents) != 0) {
1606 smbios_warn(shp, "failed to read additional information");
1607 return;
1608 }
1609
1610 oprintf(fp, " Number of Additional Information Entries: %u\n", nents);
1611 for (i = 0; i < nents; i++) {
1612 smbios_addinfo_ent_t *ent;
1613
1614 oprintf(fp, " Additional Information Entry %u\n", i);
1615 if (smbios_info_addinfo_ent(shp, id, i, &ent) != 0) {
1616 smbios_warn(shp, "failed to read additional "
1617 "information entry %u", i);
1618 continue;
1619 }
1620
1621 oprintf(fp, " Referenced handle: %lu\n", ent->smbai_ref);
1622 oprintf(fp, " Handle offset: %u\n", ent->smbai_ref_off);
1623 if (ent->smbai_str != NULL) {
1624 str_print(fp, " Information String", ent->smbai_str);
1625 }
1626
1627 /*
1628 * As of SMBIOS 3.7, there are no extra data entries strictly
1629 * defined in the spec, but there may be something. If we find
1630 * something that's a standard integer size, then we'll
1631 * interpret it and print it as a hex value. In theory this is
1632 * supposed to refer back to some field, but hard to say how
1633 * this'll actually be used. The first time we encountered it
1634 * was just an additional string entry.
1635 */
1636 if (ent->smbai_dlen > 0) {
1637 oprintf(fp, " Data Length: %u\n", ent->smbai_dlen);
1638 switch (ent->smbai_dlen) {
1639 case 1:
1640 oprintf(fp, " Data: 0x%x\n",
1641 *(uint8_t *)ent->smbai_data);
1642 break;
1643 case 2:
1644 oprintf(fp, " Data: 0x%x\n",
1645 *(uint16_t *)ent->smbai_data);
1646 break;
1647 case 4:
1648 oprintf(fp, " Data: 0x%x\n",
1649 *(uint32_t *)ent->smbai_data);
1650 break;
1651 case 8:
1652 oprintf(fp, " Data: 0x%x\n",
1653 *(uint64_t *)ent->smbai_data);
1654 break;
1655 default:
1656 break;
1657 }
1658 }
1659
1660 smbios_info_addinfo_ent_free(shp, ent);
1661 }
1662 }
1663
1664
1665 static void
print_processor_info_riscv(smbios_hdl_t * shp,id_t id,FILE * fp)1666 print_processor_info_riscv(smbios_hdl_t *shp, id_t id, FILE *fp)
1667 {
1668 smbios_processor_info_riscv_t rv;
1669
1670 if (smbios_info_processor_riscv(shp, id, &rv) != 0) {
1671 smbios_warn(shp, "failed to read RISC-V specific processor "
1672 "information");
1673 return;
1674 }
1675
1676 if (rv.smbpirv_boothart != 0) {
1677 oprintf(fp, " Boot Hart\n");
1678 }
1679 u128_print(fp, " Hart ID", rv.smbpirv_hartid);
1680 u128_print(fp, " Vendor ID", rv.smbpirv_vendid);
1681 u128_print(fp, " Architecture ID", rv.smbpirv_archid);
1682 u128_print(fp, " Implementation ID", rv.smbpirv_machid);
1683 flag64_printf(fp, " ISA", rv.smbpirv_isa,
1684 sizeof (rv.smbpirv_isa) * NBBY, smbios_riscv_isa_name,
1685 smbios_riscv_isa_desc);
1686 flag_printf(fp, " Privilege Levels", rv.smbpirv_privlvl,
1687 sizeof (rv.smbpirv_privlvl) * NBBY, smbios_riscv_priv_name,
1688 smbios_riscv_priv_desc);
1689 u128_print(fp, " Machine Exception Trap Delegation",
1690 rv.smbpirv_metdi);
1691 u128_print(fp, " Machine Interrupt Trap Delegation",
1692 rv.smbpirv_mitdi);
1693 desc_printf(smbios_riscv_width_desc(rv.smbpirv_xlen),
1694 fp, " Register Width: 0x%x", rv.smbpirv_xlen);
1695 desc_printf(smbios_riscv_width_desc(rv.smbpirv_mxlen),
1696 fp, " M-Mode Register Width: 0x%x", rv.smbpirv_mxlen);
1697 desc_printf(smbios_riscv_width_desc(rv.smbpirv_sxlen),
1698 fp, " S-Mode Register Width: 0x%x", rv.smbpirv_sxlen);
1699 desc_printf(smbios_riscv_width_desc(rv.smbpirv_uxlen),
1700 fp, " U-Mode Register Width: 0x%x", rv.smbpirv_uxlen);
1701 }
1702
1703 static void
print_processor_info(smbios_hdl_t * shp,id_t id,FILE * fp)1704 print_processor_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1705 {
1706 smbios_processor_info_t p;
1707
1708 if (smbios_info_processor_info(shp, id, &p) != 0) {
1709 smbios_warn(shp, "failed to read processor additional "
1710 "information");
1711 return;
1712 }
1713
1714 id_printf(fp, " Processor Handle: ", p.smbpi_processor);
1715 desc_printf(smbios_processor_info_type_desc(p.smbpi_ptype),
1716 fp, " Processor Type: %u", p.smbpi_ptype);
1717
1718 switch (p.smbpi_ptype) {
1719 case SMB_PROCINFO_T_RV32:
1720 case SMB_PROCINFO_T_RV64:
1721 case SMB_PROCINFO_T_RV128:
1722 oprintf(fp, " RISC-V Additional Processor Information:\n");
1723 print_processor_info_riscv(shp, id, fp);
1724 break;
1725 default:
1726 break;
1727 }
1728 }
1729
1730 static void
print_battery(smbios_hdl_t * shp,id_t id,FILE * fp)1731 print_battery(smbios_hdl_t *shp, id_t id, FILE *fp)
1732 {
1733 smbios_battery_t bat;
1734
1735 if (smbios_info_battery(shp, id, &bat) != 0) {
1736 smbios_warn(shp, "failed to read battery information");
1737 return;
1738 }
1739
1740 if (bat.smbb_date != NULL) {
1741 str_print(fp, " Manufacture Date", bat.smbb_date);
1742 }
1743
1744 if (bat.smbb_serial != NULL) {
1745 str_print(fp, " Serial Number", bat.smbb_serial);
1746 }
1747
1748 if (bat.smbb_chem != SMB_BDC_UNKNOWN) {
1749 desc_printf(smbios_battery_chem_desc(bat.smbb_chem),
1750 fp, " Battery Chemistry: 0x%x", bat.smbb_chem);
1751 }
1752
1753 if (bat.smbb_cap != 0) {
1754 oprintf(fp, " Design Capacity: %u mWh\n", bat.smbb_cap);
1755 } else {
1756 oprintf(fp, " Design Capacity: unknown\n");
1757 }
1758
1759 if (bat.smbb_volt != 0) {
1760 oprintf(fp, " Design Voltage: %u mV\n", bat.smbb_volt);
1761 } else {
1762 oprintf(fp, " Design Voltage: unknown\n");
1763 }
1764
1765 str_print(fp, " SBDS Version Number", bat.smbb_version);
1766 if (bat.smbb_err != UINT8_MAX) {
1767 oprintf(fp, " Maximum Error: %u\n", bat.smbb_err);
1768 } else {
1769 oprintf(fp, " Maximum Error: unknown\n", bat.smbb_err);
1770 }
1771 oprintf(fp, " SBDS Serial Number: %04x\n", bat.smbb_ssn);
1772 oprintf(fp, " SBDS Manufacture Date: %u-%02u-%02u\n", bat.smbb_syear,
1773 bat.smbb_smonth, bat.smbb_sday);
1774 str_print(fp, " SBDS Device Chemistry", bat.smbb_schem);
1775 oprintf(fp, " OEM-specific Information: 0x%08x\n", bat.smbb_oemdata);
1776 }
1777
1778 static void
print_pointdev(smbios_hdl_t * shp,id_t id,FILE * fp)1779 print_pointdev(smbios_hdl_t *shp, id_t id, FILE *fp)
1780 {
1781 smbios_pointdev_t pd;
1782
1783 if (smbios_info_pointdev(shp, id, &pd) != 0) {
1784 smbios_warn(shp, "failed to read pointer device information");
1785 return;
1786 }
1787
1788 desc_printf(smbios_pointdev_type_desc(pd.smbpd_type),
1789 fp, " Type: %u", pd.smbpd_type);
1790 desc_printf(smbios_pointdev_iface_desc(pd.smbpd_iface),
1791 fp, " Interface: %u", pd.smbpd_iface);
1792 oprintf(fp, " Buttons: %u\n", pd.smbpd_nbuttons);
1793 }
1794
1795 static void
print_extprocessor(smbios_hdl_t * shp,id_t id,FILE * fp)1796 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1797 {
1798 int i;
1799 smbios_processor_ext_t ep;
1800
1801 if (check_oem(shp) != 0)
1802 return;
1803
1804 if (smbios_info_extprocessor(shp, id, &ep) != 0) {
1805 smbios_warn(shp, "failed to read extended processor "
1806 "information");
1807 return;
1808 }
1809
1810 oprintf(fp, " Processor: %u\n", ep.smbpe_processor);
1811 oprintf(fp, " FRU: %u\n", ep.smbpe_fru);
1812 oprintf(fp, " Initial APIC ID count: %u\n\n", ep.smbpe_n);
1813
1814 for (i = 0; i < ep.smbpe_n; i++) {
1815 oprintf(fp, " Logical Strand %u: Initial APIC ID: %u\n", i,
1816 ep.smbpe_apicid[i]);
1817 }
1818 }
1819
1820 static void
print_extport(smbios_hdl_t * shp,id_t id,FILE * fp)1821 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1822 {
1823 smbios_port_ext_t epo;
1824
1825 if (check_oem(shp) != 0)
1826 return;
1827
1828 if (smbios_info_extport(shp, id, &epo) != 0) {
1829 smbios_warn(shp, "failed to read extended port information");
1830 return;
1831 }
1832
1833 oprintf(fp, " Chassis Handle: %u\n", epo.smbporte_chassis);
1834 oprintf(fp, " Port Connector Handle: %u\n", epo.smbporte_port);
1835 oprintf(fp, " Device Type: %u\n", epo.smbporte_dtype);
1836 oprintf(fp, " Device Handle: %u\n", epo.smbporte_devhdl);
1837 oprintf(fp, " PHY: %u\n", epo.smbporte_phy);
1838 }
1839
1840 static void
print_pciexrc(smbios_hdl_t * shp,id_t id,FILE * fp)1841 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1842 {
1843 smbios_pciexrc_t pcie;
1844
1845 if (check_oem(shp) != 0)
1846 return;
1847
1848 if (smbios_info_pciexrc(shp, id, &pcie) != 0) {
1849 smbios_warn(shp, "failed to read pciexrc information");
1850 return;
1851 }
1852
1853 oprintf(fp, " Component ID: %u\n", pcie.smbpcie_bb);
1854 oprintf(fp, " BDF: 0x%x\n", pcie.smbpcie_bdf);
1855 }
1856
1857 static void
print_extmemarray(smbios_hdl_t * shp,id_t id,FILE * fp)1858 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1859 {
1860 smbios_memarray_ext_t em;
1861
1862 if (check_oem(shp) != 0)
1863 return;
1864
1865 if (smbios_info_extmemarray(shp, id, &em) != 0) {
1866 smbios_warn(shp, "failed to read extmemarray information");
1867 return;
1868 }
1869
1870 oprintf(fp, " Physical Memory Array Handle: %u\n", em.smbmae_ma);
1871 oprintf(fp, " Component Parent Handle: %u\n", em.smbmae_comp);
1872 oprintf(fp, " BDF: 0x%x\n", em.smbmae_bdf);
1873 }
1874
1875 static void
print_extmemdevice(smbios_hdl_t * shp,id_t id,FILE * fp)1876 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1877 {
1878 uint_t i, ncs;
1879 uint8_t *cs;
1880 smbios_memdevice_ext_t emd;
1881
1882 if (check_oem(shp) != 0)
1883 return;
1884
1885 if (smbios_info_extmemdevice(shp, id, &emd) != 0) {
1886 smbios_warn(shp, "failed to read extmemdevice information");
1887 return;
1888 }
1889
1890 oprintf(fp, " Memory Device Handle: %u\n", emd.smbmdeve_md);
1891 oprintf(fp, " DRAM Channel: %u\n", emd.smbmdeve_drch);
1892 oprintf(fp, " Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1893
1894 if (emd.smbmdeve_ncs == 0)
1895 return;
1896
1897 if (smbios_info_extmemdevice_cs(shp, id, &ncs, &cs) != 0) {
1898 smbios_warn(shp, "failed to read extmemdevice cs information");
1899 return;
1900 }
1901
1902 for (i = 0; i < ncs; i++) {
1903 oprintf(fp, " Chip Select: %u\n", cs[i]);
1904 }
1905 smbios_info_extmemdevice_cs_free(shp, ncs, cs);
1906 }
1907
1908 static void
print_strprop_info(smbios_hdl_t * shp,id_t id,FILE * fp)1909 print_strprop_info(smbios_hdl_t *shp, id_t id, FILE *fp)
1910 {
1911 smbios_strprop_t prop;
1912
1913 if (smbios_info_strprop(shp, id, &prop) != 0) {
1914 smbios_warn(shp, "failed to read string property information");
1915 return;
1916 }
1917
1918 desc_printf(smbios_strprop_id_desc(prop.smbsp_prop_id), fp,
1919 " Property ID: %u", prop.smbsp_prop_id);
1920 if (prop.smbsp_prop_val != NULL) {
1921 str_print(fp, " Property Value", prop.smbsp_prop_val);
1922 }
1923 id_printf(fp, " Parent Handle: ", prop.smbsp_parent);
1924 }
1925
1926 static void
print_fwinfo(smbios_hdl_t * shp,id_t id,FILE * fp)1927 print_fwinfo(smbios_hdl_t *shp, id_t id, FILE *fp)
1928 {
1929 smbios_fwinfo_t fw;
1930 smbios_fwinfo_comp_t *comps;
1931 uint_t ncomps, i;
1932
1933 if (smbios_info_fwinfo(shp, id, &fw) != 0) {
1934 smbios_warn(shp, "failed to read firmware inventory");
1935 return;
1936 }
1937
1938 str_print(fp, " Component Name", fw.smbfw_name);
1939 str_print(fp, " ID", fw.smbfw_id);
1940 str_print(fp, " Release Date", fw.smbfw_reldate);
1941 str_print(fp, " Lowest Supported Version", fw.smbfw_lsv);
1942 desc_printf(smbios_fwinfo_vers_desc(fw.smbfw_vers_fmt), fp,
1943 " Version Format: %u", fw.smbfw_vers_fmt);
1944 desc_printf(smbios_fwinfo_id_desc(fw.smbfw_id_fmt), fp,
1945 " ID Format: %u", fw.smbfw_id_fmt);
1946 if (fw.smbfw_imgsz != UINT64_MAX) {
1947 oprintf(fp, " Image Size: %" PRIu64 "\n", fw.smbfw_imgsz);
1948 } else {
1949 oprintf(fp, " Image Size: unknown\n");
1950 }
1951
1952 flag_printf(fp, "Characteristics", fw.smbfw_chars,
1953 sizeof (fw.smbfw_chars) * NBBY, smbios_fwinfo_ch_name,
1954 smbios_fwinfo_ch_desc);
1955
1956 desc_printf(smbios_fwinfo_state_desc(fw.smbfw_state), fp, " State: %u",
1957 fw.smbfw_state);
1958 oprintf(fp, " Number of Associated Components: %u\n",
1959 fw.smbfw_ncomps);
1960
1961 if (fw.smbfw_ncomps == 0)
1962 return;
1963
1964 if (smbios_info_fwinfo_comps(shp, id, &ncomps, &comps) == -1) {
1965 smbios_warn(shp, "failed to read firmware inventory "
1966 "components");
1967 return;
1968 }
1969
1970 oprintf(fp, "\n Component Handles:\n");
1971 for (i = 0; i < ncomps; i++) {
1972 oprintf(fp, " %ld\n", comps[i]);
1973 }
1974 }
1975
1976 static int
print_struct(smbios_hdl_t * shp,const smbios_struct_t * sp,void * fp)1977 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1978 {
1979 smbios_info_t info;
1980 int hex = opt_x;
1981 const char *s;
1982
1983 if (opt_t != -1 && opt_t != sp->smbstr_type)
1984 return (0); /* skip struct if type doesn't match -t */
1985
1986 if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1987 sp->smbstr_type == SMB_TYPE_MEMMOD))
1988 return (0); /* skip struct if type is obsolete */
1989
1990 if (g_hdr++ == 0 || !opt_s)
1991 oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
1992
1993 oprintf(fp, "%-5u %-4lu",
1994 (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
1995
1996 if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
1997 oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
1998 else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
1999 sp->smbstr_type < SMB_TYPE_OEM_HI)
2000 oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
2001 sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
2002 else
2003 oprintf(fp, " %u", sp->smbstr_type);
2004
2005 if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
2006 oprintf(fp, " (%s)\n", s);
2007 else
2008 oprintf(fp, "\n");
2009
2010 if (opt_s)
2011 return (0); /* only print header line if -s specified */
2012
2013 if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
2014 oprintf(fp, "\n");
2015 print_common(&info, fp);
2016 }
2017
2018 switch (sp->smbstr_type) {
2019 case SMB_TYPE_BIOS:
2020 oprintf(fp, "\n");
2021 print_bios(shp, fp);
2022 break;
2023 case SMB_TYPE_SYSTEM:
2024 oprintf(fp, "\n");
2025 print_system(shp, fp);
2026 break;
2027 case SMB_TYPE_BASEBOARD:
2028 oprintf(fp, "\n");
2029 print_bboard(shp, sp->smbstr_id, fp);
2030 break;
2031 case SMB_TYPE_CHASSIS:
2032 oprintf(fp, "\n");
2033 print_chassis(shp, sp->smbstr_id, fp);
2034 break;
2035 case SMB_TYPE_PROCESSOR:
2036 oprintf(fp, "\n");
2037 print_processor(shp, sp->smbstr_id, fp);
2038 break;
2039 case SMB_TYPE_CACHE:
2040 oprintf(fp, "\n");
2041 print_cache(shp, sp->smbstr_id, fp);
2042 break;
2043 case SMB_TYPE_PORT:
2044 oprintf(fp, "\n");
2045 print_port(shp, sp->smbstr_id, fp);
2046 break;
2047 case SMB_TYPE_SLOT:
2048 oprintf(fp, "\n");
2049 print_slot(shp, sp->smbstr_id, fp);
2050 break;
2051 case SMB_TYPE_OBDEVS:
2052 oprintf(fp, "\n");
2053 print_obdevs(shp, sp->smbstr_id, fp);
2054 break;
2055 case SMB_TYPE_OEMSTR:
2056 case SMB_TYPE_SYSCONFSTR:
2057 oprintf(fp, "\n");
2058 print_strtab(shp, sp->smbstr_id, fp);
2059 break;
2060 case SMB_TYPE_LANG:
2061 oprintf(fp, "\n");
2062 print_lang(shp, sp->smbstr_id, fp);
2063 break;
2064 case SMB_TYPE_EVENTLOG:
2065 oprintf(fp, "\n");
2066 print_evlog(shp, sp->smbstr_id, fp);
2067 break;
2068 case SMB_TYPE_MEMARRAY:
2069 oprintf(fp, "\n");
2070 print_memarray(shp, sp->smbstr_id, fp);
2071 break;
2072 case SMB_TYPE_MEMDEVICE:
2073 oprintf(fp, "\n");
2074 print_memdevice(shp, sp->smbstr_id, fp);
2075 break;
2076 case SMB_TYPE_MEMARRAYMAP:
2077 oprintf(fp, "\n");
2078 print_memarrmap(shp, sp->smbstr_id, fp);
2079 break;
2080 case SMB_TYPE_MEMDEVICEMAP:
2081 oprintf(fp, "\n");
2082 print_memdevmap(shp, sp->smbstr_id, fp);
2083 break;
2084 case SMB_TYPE_BATTERY:
2085 oprintf(fp, "\n");
2086 print_battery(shp, sp->smbstr_id, fp);
2087 break;
2088 case SMB_TYPE_POINTDEV:
2089 oprintf(fp, "\n");
2090 print_pointdev(shp, sp->smbstr_id, fp);
2091 break;
2092 case SMB_TYPE_SECURITY:
2093 oprintf(fp, "\n");
2094 print_hwsec(shp, fp);
2095 break;
2096 case SMB_TYPE_VPROBE:
2097 oprintf(fp, "\n");
2098 print_vprobe(shp, sp->smbstr_id, fp);
2099 break;
2100 case SMB_TYPE_COOLDEV:
2101 oprintf(fp, "\n");
2102 print_cooldev(shp, sp->smbstr_id, fp);
2103 break;
2104 case SMB_TYPE_TPROBE:
2105 oprintf(fp, "\n");
2106 print_tprobe(shp, sp->smbstr_id, fp);
2107 break;
2108 case SMB_TYPE_IPROBE:
2109 oprintf(fp, "\n");
2110 print_iprobe(shp, sp->smbstr_id, fp);
2111 break;
2112 case SMB_TYPE_BOOT:
2113 oprintf(fp, "\n");
2114 print_boot(shp, fp);
2115 break;
2116 case SMB_TYPE_IPMIDEV:
2117 oprintf(fp, "\n");
2118 print_ipmi(shp, fp);
2119 break;
2120 case SMB_TYPE_POWERSUP:
2121 oprintf(fp, "\n");
2122 print_powersup(shp, sp->smbstr_id, fp);
2123 break;
2124 case SMB_TYPE_ADDINFO:
2125 oprintf(fp, "\n");
2126 print_addinfo(shp, sp->smbstr_id, fp);
2127 break;
2128 case SMB_TYPE_OBDEVEXT:
2129 oprintf(fp, "\n");
2130 print_obdevs_ext(shp, sp->smbstr_id, fp);
2131 break;
2132 case SMB_TYPE_PROCESSOR_INFO:
2133 oprintf(fp, "\n");
2134 print_processor_info(shp, sp->smbstr_id, fp);
2135 break;
2136 case SMB_TYPE_STRPROP:
2137 oprintf(fp, "\n");
2138 print_strprop_info(shp, sp->smbstr_id, fp);
2139 break;
2140 case SMB_TYPE_FWINFO:
2141 oprintf(fp, "\n");
2142 print_fwinfo(shp, sp->smbstr_id, fp);
2143 break;
2144 case SUN_OEM_EXT_PROCESSOR:
2145 oprintf(fp, "\n");
2146 print_extprocessor(shp, sp->smbstr_id, fp);
2147 break;
2148 case SUN_OEM_EXT_PORT:
2149 oprintf(fp, "\n");
2150 print_extport(shp, sp->smbstr_id, fp);
2151 break;
2152 case SUN_OEM_PCIEXRC:
2153 oprintf(fp, "\n");
2154 print_pciexrc(shp, sp->smbstr_id, fp);
2155 break;
2156 case SUN_OEM_EXT_MEMARRAY:
2157 oprintf(fp, "\n");
2158 print_extmemarray(shp, sp->smbstr_id, fp);
2159 break;
2160 case SUN_OEM_EXT_MEMDEVICE:
2161 oprintf(fp, "\n");
2162 print_extmemdevice(shp, sp->smbstr_id, fp);
2163 break;
2164 default:
2165 hex++;
2166 }
2167
2168 if (hex)
2169 print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
2170 else
2171 oprintf(fp, "\n");
2172
2173 return (0);
2174 }
2175
2176 static uint16_t
getu16(const char * name,const char * s)2177 getu16(const char *name, const char *s)
2178 {
2179 u_longlong_t val;
2180 char *p;
2181
2182 errno = 0;
2183 val = strtoull(s, &p, 0);
2184
2185 if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
2186 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2187 g_pname, name, s);
2188 exit(SMBIOS_USAGE);
2189 }
2190
2191 return ((uint16_t)val);
2192 }
2193
2194 static uint16_t
getstype(const char * name,const char * s)2195 getstype(const char *name, const char *s)
2196 {
2197 const char *ts;
2198 uint16_t t;
2199
2200 for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
2201 if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
2202 return (t);
2203 }
2204
2205 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
2206 g_pname, name, s);
2207
2208 exit(SMBIOS_USAGE);
2209 /*NOTREACHED*/
2210 }
2211
2212 static int
usage(FILE * fp)2213 usage(FILE *fp)
2214 {
2215 (void) fprintf(fp, "Usage: %s "
2216 "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
2217
2218 (void) fprintf(fp,
2219 "\t-B disable header validation for broken BIOSes\n"
2220 "\t-e display SMBIOS entry point information\n"
2221 "\t-i display only the specified structure\n"
2222 "\t-O display obsolete structure types\n"
2223 "\t-s display only a summary of structure identifiers and types\n"
2224 "\t-t display only the specified structure type\n"
2225 "\t-w write the raw data to the specified file\n"
2226 "\t-x display raw data for structures\n");
2227
2228 return (SMBIOS_USAGE);
2229 }
2230
2231 int
main(int argc,char * argv[])2232 main(int argc, char *argv[])
2233 {
2234 const char *ifile = NULL;
2235 const char *ofile = NULL;
2236 int oflags = 0;
2237
2238 smbios_hdl_t *shp;
2239 smbios_struct_t s;
2240 int err, fd, c;
2241 char *p;
2242
2243 if ((p = strrchr(argv[0], '/')) == NULL)
2244 g_pname = argv[0];
2245 else
2246 g_pname = p + 1;
2247
2248 while (optind < argc) {
2249 while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
2250 switch (c) {
2251 case 'B':
2252 oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
2253 break;
2254 case 'e':
2255 opt_e++;
2256 break;
2257 case 'i':
2258 opt_i = getu16("struct ID", optarg);
2259 break;
2260 case 'O':
2261 opt_O++;
2262 break;
2263 case 's':
2264 opt_s++;
2265 break;
2266 case 't':
2267 if (isdigit(optarg[0]))
2268 opt_t = getu16("struct type", optarg);
2269 else
2270 opt_t = getstype("struct type", optarg);
2271 break;
2272 case 'w':
2273 ofile = optarg;
2274 break;
2275 case 'x':
2276 opt_x++;
2277 break;
2278 case 'Z':
2279 oflags |= SMB_O_ZIDS; /* undocumented */
2280 break;
2281 default:
2282 return (usage(stderr));
2283 }
2284 }
2285
2286 if (optind < argc) {
2287 if (ifile != NULL) {
2288 (void) fprintf(stderr, "%s: illegal "
2289 "argument -- %s\n", g_pname, argv[optind]);
2290 return (SMBIOS_USAGE);
2291 }
2292 ifile = argv[optind++];
2293 }
2294 }
2295
2296 if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
2297 (void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
2298 g_pname, smbios_errmsg(err));
2299 return (SMBIOS_ERROR);
2300 }
2301
2302 if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
2303 smbios_truncated(shp))
2304 (void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
2305 g_pname);
2306
2307 if (ofile != NULL) {
2308 if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
2309 (void) fprintf(stderr, "%s: failed to open %s: %s\n",
2310 g_pname, ofile, strerror(errno));
2311 err = SMBIOS_ERROR;
2312 } else if (smbios_write(shp, fd) != 0) {
2313 (void) fprintf(stderr, "%s: failed to write %s: %s\n",
2314 g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
2315 err = SMBIOS_ERROR;
2316 }
2317 smbios_close(shp);
2318 return (err);
2319 }
2320
2321 if (opt_e) {
2322 print_smbios(shp, stdout);
2323 smbios_close(shp);
2324 return (SMBIOS_SUCCESS);
2325 }
2326
2327 if (opt_O && (opt_i != -1 || opt_t != -1))
2328 opt_O++; /* -i or -t imply displaying obsolete records */
2329
2330 if (opt_i != -1)
2331 err = smbios_lookup_id(shp, opt_i, &s);
2332 else
2333 err = smbios_iter(shp, print_struct, stdout);
2334
2335 if (err != 0) {
2336 (void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
2337 g_pname, smbios_errmsg(smbios_errno(shp)));
2338 smbios_close(shp);
2339 return (SMBIOS_ERROR);
2340 }
2341
2342 if (opt_i != -1)
2343 (void) print_struct(shp, &s, stdout);
2344
2345 smbios_close(shp);
2346 return (SMBIOS_SUCCESS);
2347 }
2348