xref: /illumos-gate/usr/src/cmd/smbios/smbios.c (revision 1566bc34)
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 2010 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include <sys/sysmacros.h>
30 #include <sys/param.h>
31 
32 #include <smbios.h>
33 #include <alloca.h>
34 #include <limits.h>
35 #include <unistd.h>
36 #include <strings.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <ctype.h>
43 #include <libjedec.h>
44 
45 #define	SMBIOS_SUCCESS	0
46 #define	SMBIOS_ERROR	1
47 #define	SMBIOS_USAGE	2
48 
49 static const char *g_pname;
50 static int g_hdr;
51 
52 static int opt_e;
53 static int opt_i = -1;
54 static int opt_O;
55 static int opt_s;
56 static int opt_t = -1;
57 static int opt_x;
58 
59 static boolean_t
60 smbios_vergteq(smbios_version_t *v, uint_t major, uint_t minor)
61 {
62 	if (v->smbv_major > major)
63 		return (B_TRUE);
64 	if (v->smbv_major == major &&
65 	    v->smbv_minor >= minor)
66 		return (B_TRUE);
67 	return (B_FALSE);
68 }
69 
70 /*PRINTFLIKE2*/
71 static void
72 smbios_warn(smbios_hdl_t *shp, const char *format, ...)
73 {
74 	va_list ap;
75 
76 	va_start(ap, format);
77 	(void) vfprintf(stderr, format, ap);
78 	va_end(ap);
79 
80 	if (shp != NULL) {
81 		(void) fprintf(stderr, ": %s",
82 		    smbios_errmsg(smbios_errno(shp)));
83 	}
84 
85 	(void) fprintf(stderr, "\n");
86 }
87 
88 /*PRINTFLIKE2*/
89 static void
90 oprintf(FILE *fp, const char *format, ...)
91 {
92 	va_list ap;
93 
94 	va_start(ap, format);
95 	(void) vfprintf(fp, format, ap);
96 	va_end(ap);
97 }
98 
99 /*PRINTFLIKE3*/
100 static void
101 desc_printf(const char *d, FILE *fp, const char *format, ...)
102 {
103 	va_list ap;
104 
105 	va_start(ap, format);
106 	(void) vfprintf(fp, format, ap);
107 	va_end(ap);
108 
109 	if (d != NULL)
110 		(void) fprintf(fp, " (%s)\n", d);
111 	else
112 		(void) fprintf(fp, "\n");
113 }
114 
115 static void
116 flag_printf(FILE *fp, const char *s, uint_t flags, size_t bits,
117     const char *(*flag_name)(uint_t), const char *(*flag_desc)(uint_t))
118 {
119 	size_t i;
120 
121 	oprintf(fp, "  %s: 0x%x\n", s, flags);
122 
123 	for (i = 0; i < bits; i++) {
124 		uint_t f = 1 << i;
125 		const char *n;
126 
127 		if (!(flags & f))
128 			continue;
129 
130 		if ((n = flag_name(f)) != NULL)
131 			desc_printf(flag_desc(f), fp, "\t%s", n);
132 		else
133 			desc_printf(flag_desc(f), fp, "\t0x%x", f);
134 	}
135 }
136 
137 static void
138 flag64_printf(FILE *fp, const char *s, uint64_t flags, size_t bits,
139     const char *(*flag_name)(uint64_t), const char *(*flag_desc)(uint64_t))
140 {
141 	size_t i;
142 
143 	oprintf(fp, "  %s: 0x%llx\n", s, (u_longlong_t)flags);
144 
145 	for (i = 0; i < bits; i++) {
146 		u_longlong_t f = 1ULL << i;
147 		const char *n;
148 
149 		if (!(flags & f))
150 			continue;
151 
152 		if ((n = flag_name(f)) != NULL)
153 			desc_printf(flag_desc(f), fp, "\t%s", n);
154 		else
155 			desc_printf(flag_desc(f), fp, "\t0x%llx", f);
156 	}
157 }
158 
159 static void
160 id_printf(FILE *fp, const char *s, id_t id)
161 {
162 	switch (id) {
163 	case SMB_ID_NONE:
164 		oprintf(fp, "%sNone\n", s);
165 		break;
166 	case SMB_ID_NOTSUP:
167 		oprintf(fp, "%sNot Supported\n", s);
168 		break;
169 	default:
170 		oprintf(fp, "%s%u\n", s, (uint_t)id);
171 	}
172 }
173 
174 static void
175 jedec_print(FILE *fp, const char *desc, uint_t id)
176 {
177 	const char *name;
178 	uint_t cont, vendor;
179 
180 	vendor = id & 0xff;
181 	cont = (id >> 8) & 0xff;
182 	name = libjedec_vendor_string(cont, vendor);
183 	if (name == NULL) {
184 		oprintf(fp, "  %s: 0x%x\n", desc, id);
185 	} else {
186 		oprintf(fp, "  %s: 0x%x (%s)\n", desc, id, name);
187 	}
188 }
189 
190 static int
191 check_oem(smbios_hdl_t *shp)
192 {
193 	int i;
194 	int cnt;
195 	int rv;
196 	id_t oem_id;
197 	smbios_struct_t s;
198 	const char **oem_str;
199 
200 	rv = smbios_lookup_type(shp, SMB_TYPE_OEMSTR, &s);
201 	if (rv != 0) {
202 		return (-1);
203 	}
204 
205 	oem_id = s.smbstr_id;
206 
207 	cnt = smbios_info_strtab(shp, oem_id, 0, NULL);
208 	if (cnt > 0) {
209 		oem_str =  alloca(sizeof (char *) * cnt);
210 		(void) smbios_info_strtab(shp, oem_id, cnt, oem_str);
211 
212 		for (i = 0; i < cnt; i++) {
213 			if (strncmp(oem_str[i], SMB_PRMS1,
214 			    strlen(SMB_PRMS1) + 1) == 0) {
215 				return (0);
216 			}
217 		}
218 	}
219 
220 	return (-1);
221 }
222 
223 static void
224 print_smbios_21(smbios_21_entry_t *ep, FILE *fp)
225 {
226 	int i;
227 
228 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
229 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
230 	    ep->smbe_eanchor);
231 
232 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
233 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
234 	oprintf(fp, "Entry Point Version: %u.%u\n",
235 	    ep->smbe_major, ep->smbe_minor);
236 	oprintf(fp, "Max Structure Size: %u\n", ep->smbe_maxssize);
237 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
238 
239 	oprintf(fp, "Entry Point Revision Data:");
240 	for (i = 0; i < sizeof (ep->smbe_format); i++)
241 		oprintf(fp, " 0x%02x", ep->smbe_format[i]);
242 	oprintf(fp, "\n");
243 
244 	oprintf(fp, "Intermediate Anchor Tag: %*.*s\n",
245 	    (int)sizeof (ep->smbe_ianchor), (int)sizeof (ep->smbe_ianchor),
246 	    ep->smbe_ianchor);
247 
248 	oprintf(fp, "Intermediate Checksum: 0x%x\n", ep->smbe_icksum);
249 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
250 	oprintf(fp, "Structure Table Address: 0x%x\n", ep->smbe_staddr);
251 	oprintf(fp, "Structure Table Entries: %u\n", ep->smbe_stnum);
252 	oprintf(fp, "DMI BCD Revision: 0x%x\n", ep->smbe_bcdrev);
253 }
254 
255 static void
256 print_smbios_30(smbios_30_entry_t *ep, FILE *fp)
257 {
258 	oprintf(fp, "Entry Point Anchor Tag: %*.*s\n",
259 	    (int)sizeof (ep->smbe_eanchor), (int)sizeof (ep->smbe_eanchor),
260 	    ep->smbe_eanchor);
261 
262 	oprintf(fp, "Entry Point Checksum: 0x%x\n", ep->smbe_ecksum);
263 	oprintf(fp, "Entry Point Length: %u\n", ep->smbe_elen);
264 	oprintf(fp, "SMBIOS Version: %u.%u\n",
265 	    ep->smbe_major, ep->smbe_minor);
266 	oprintf(fp, "SMBIOS DocRev: 0x%x\n", ep->smbe_docrev);
267 	oprintf(fp, "Entry Point Revision: 0x%x\n", ep->smbe_revision);
268 
269 	oprintf(fp, "Structure Table Length: %u\n", ep->smbe_stlen);
270 	oprintf(fp, "Structure Table Address: 0x%" PRIx64 "\n",
271 	    ep->smbe_staddr);
272 }
273 
274 static void
275 print_smbios(smbios_hdl_t *shp, FILE *fp)
276 {
277 	smbios_entry_t ep;
278 
279 	switch (smbios_info_smbios(shp, &ep)) {
280 	case SMBIOS_ENTRY_POINT_21:
281 		print_smbios_21(&ep.ep21, fp);
282 		break;
283 	case SMBIOS_ENTRY_POINT_30:
284 		print_smbios_30(&ep.ep30, fp);
285 		break;
286 	}
287 }
288 
289 static void
290 print_common(const smbios_info_t *ip, FILE *fp)
291 {
292 	if (ip->smbi_manufacturer[0] != '\0')
293 		oprintf(fp, "  Manufacturer: %s\n", ip->smbi_manufacturer);
294 	if (ip->smbi_product[0] != '\0')
295 		oprintf(fp, "  Product: %s\n", ip->smbi_product);
296 	if (ip->smbi_version[0] != '\0')
297 		oprintf(fp, "  Version: %s\n", ip->smbi_version);
298 	if (ip->smbi_serial[0] != '\0')
299 		oprintf(fp, "  Serial Number: %s\n", ip->smbi_serial);
300 	if (ip->smbi_asset[0] != '\0')
301 		oprintf(fp, "  Asset Tag: %s\n", ip->smbi_asset);
302 	if (ip->smbi_location[0] != '\0')
303 		oprintf(fp, "  Location Tag: %s\n", ip->smbi_location);
304 	if (ip->smbi_part[0] != '\0')
305 		oprintf(fp, "  Part Number: %s\n", ip->smbi_part);
306 }
307 
308 static void
309 print_bios(smbios_hdl_t *shp, FILE *fp)
310 {
311 	smbios_bios_t b;
312 
313 	(void) smbios_info_bios(shp, &b);
314 
315 	oprintf(fp, "  Vendor: %s\n", b.smbb_vendor);
316 	oprintf(fp, "  Version String: %s\n", b.smbb_version);
317 	oprintf(fp, "  Release Date: %s\n", b.smbb_reldate);
318 	oprintf(fp, "  Address Segment: 0x%x\n", b.smbb_segment);
319 	oprintf(fp, "  ROM Size: %" PRIu64 " bytes\n", b.smbb_extromsize);
320 	oprintf(fp, "  Image Size: %u bytes\n", b.smbb_runsize);
321 
322 	flag64_printf(fp, "Characteristics",
323 	    b.smbb_cflags, sizeof (b.smbb_cflags) * NBBY,
324 	    smbios_bios_flag_name, smbios_bios_flag_desc);
325 
326 	if (b.smbb_nxcflags > SMB_BIOSXB_1) {
327 		flag_printf(fp, "Characteristics Extension Byte 1",
328 		    b.smbb_xcflags[SMB_BIOSXB_1],
329 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_1]) * NBBY,
330 		    smbios_bios_xb1_name, smbios_bios_xb1_desc);
331 	}
332 
333 	if (b.smbb_nxcflags > SMB_BIOSXB_2) {
334 		flag_printf(fp, "Characteristics Extension Byte 2",
335 		    b.smbb_xcflags[SMB_BIOSXB_2],
336 		    sizeof (b.smbb_xcflags[SMB_BIOSXB_2]) * NBBY,
337 		    smbios_bios_xb2_name, smbios_bios_xb2_desc);
338 	}
339 
340 	if (b.smbb_nxcflags > SMB_BIOSXB_BIOS_MIN) {
341 		oprintf(fp, "  Version Number: %u.%u\n",
342 		    b.smbb_biosv.smbv_major, b.smbb_biosv.smbv_minor);
343 	}
344 
345 	/*
346 	 * If the major and minor versions are 0xff then that indicates that the
347 	 * embedded controller does not exist.
348 	 */
349 	if (b.smbb_nxcflags > SMB_BIOSXB_ECFW_MIN &&
350 	    b.smbb_ecfwv.smbv_major != 0xff &&
351 	    b.smbb_ecfwv.smbv_minor != 0xff) {
352 		oprintf(fp, "  Embedded Ctlr Firmware Version Number: %u.%u\n",
353 		    b.smbb_ecfwv.smbv_major, b.smbb_ecfwv.smbv_minor);
354 	}
355 }
356 
357 static void
358 print_system(smbios_hdl_t *shp, FILE *fp)
359 {
360 	smbios_system_t s;
361 	uint_t i;
362 
363 	(void) smbios_info_system(shp, &s);
364 
365 	oprintf(fp, "  UUID: ");
366 	for (i = 0; i < s.smbs_uuidlen; i++) {
367 		oprintf(fp, "%02x", s.smbs_uuid[i]);
368 		if (i == 3 || i == 5 || i == 7 || i == 9)
369 			oprintf(fp, "-");
370 	}
371 	oprintf(fp, "\n");
372 
373 	desc_printf(smbios_system_wakeup_desc(s.smbs_wakeup),
374 	    fp, "  Wake-Up Event: 0x%x", s.smbs_wakeup);
375 
376 	oprintf(fp, "  SKU Number: %s\n", s.smbs_sku);
377 	oprintf(fp, "  Family: %s\n", s.smbs_family);
378 }
379 
380 static void
381 print_bboard(smbios_hdl_t *shp, id_t id, FILE *fp)
382 {
383 	smbios_bboard_t b;
384 	int chdl_cnt;
385 
386 	(void) smbios_info_bboard(shp, id, &b);
387 
388 	oprintf(fp, "  Chassis: %u\n", (uint_t)b.smbb_chassis);
389 
390 	flag_printf(fp, "Flags", b.smbb_flags, sizeof (b.smbb_flags) * NBBY,
391 	    smbios_bboard_flag_name, smbios_bboard_flag_desc);
392 
393 	desc_printf(smbios_bboard_type_desc(b.smbb_type),
394 	    fp, "  Board Type: 0x%x", b.smbb_type);
395 
396 	chdl_cnt = b.smbb_contn;
397 	if (chdl_cnt != 0) {
398 		id_t *chdl;
399 		uint16_t hdl;
400 		int i, n, cnt;
401 
402 		chdl = alloca(chdl_cnt * sizeof (id_t));
403 		cnt = smbios_info_contains(shp, id, chdl_cnt, chdl);
404 		if (cnt > SMB_CONT_MAX)
405 			return;
406 		n = MIN(chdl_cnt, cnt);
407 
408 		oprintf(fp, "\n");
409 		for (i = 0; i < n; i++) {
410 			hdl = (uint16_t)chdl[i];
411 			oprintf(fp, "  Contained Handle: %u\n", hdl);
412 		}
413 	}
414 }
415 
416 static void
417 print_chassis(smbios_hdl_t *shp, id_t id, FILE *fp)
418 {
419 	smbios_chassis_t c;
420 	int elem_cnt;
421 
422 	(void) smbios_info_chassis(shp, id, &c);
423 
424 	oprintf(fp, "  OEM Data: 0x%x\n", c.smbc_oemdata);
425 	oprintf(fp, "  SKU number: %s\n",
426 	    c.smbc_sku[0] == '\0' ? "<unknown>" : c.smbc_sku);
427 	oprintf(fp, "  Lock Present: %s\n", c.smbc_lock ? "Y" : "N");
428 
429 	desc_printf(smbios_chassis_type_desc(c.smbc_type),
430 	    fp, "  Chassis Type: 0x%x", c.smbc_type);
431 
432 	desc_printf(smbios_chassis_state_desc(c.smbc_bustate),
433 	    fp, "  Boot-Up State: 0x%x", c.smbc_bustate);
434 
435 	desc_printf(smbios_chassis_state_desc(c.smbc_psstate),
436 	    fp, "  Power Supply State: 0x%x", c.smbc_psstate);
437 
438 	desc_printf(smbios_chassis_state_desc(c.smbc_thstate),
439 	    fp, "  Thermal State: 0x%x", c.smbc_thstate);
440 
441 	oprintf(fp, "  Chassis Height: %uu\n", c.smbc_uheight);
442 	oprintf(fp, "  Power Cords: %u\n", c.smbc_cords);
443 
444 	elem_cnt = c.smbc_elems;
445 	oprintf(fp, "  Element Records: %u\n", elem_cnt);
446 
447 	if (elem_cnt > 0) {
448 		id_t *elems;
449 		uint8_t type;
450 		int i, n, cnt;
451 
452 		elems = alloca(c.smbc_elems * sizeof (id_t));
453 		cnt = smbios_info_contains(shp, id, elem_cnt, elems);
454 		if (cnt > SMB_CONT_MAX)
455 			return;
456 		n = MIN(elem_cnt, cnt);
457 
458 		oprintf(fp, "\n");
459 		for (i = 0; i < n; i++) {
460 			type = (uint8_t)elems[i];
461 			if (type & 0x80) {
462 				/* SMBIOS structrure Type */
463 				desc_printf(smbios_type_name(type & 0x7f), fp,
464 				    "  Contained SMBIOS structure Type: %u",
465 				    type & 0x80);
466 			} else {
467 				/* SMBIOS Base Board Type */
468 				desc_printf(smbios_bboard_type_desc(type), fp,
469 				    "  Contained SMBIOS Base Board Type: 0x%x",
470 				    type);
471 			}
472 		}
473 	}
474 }
475 
476 static void
477 print_processor(smbios_hdl_t *shp, id_t id, FILE *fp)
478 {
479 	smbios_processor_t p;
480 	uint_t status;
481 
482 	(void) smbios_info_processor(shp, id, &p);
483 	status = SMB_PRSTATUS_STATUS(p.smbp_status);
484 
485 	desc_printf(smbios_processor_family_desc(p.smbp_family),
486 	    fp, "  Family: %u", p.smbp_family);
487 
488 	if (p.smbp_family2 != 0)
489 		desc_printf(smbios_processor_family_desc(p.smbp_family2),
490 		    fp, "  Family Ext: %u", p.smbp_family2);
491 
492 	oprintf(fp, "  CPUID: 0x%llx\n", (u_longlong_t)p.smbp_cpuid);
493 
494 	desc_printf(smbios_processor_type_desc(p.smbp_type),
495 	    fp, "  Type: %u", p.smbp_type);
496 
497 	desc_printf(smbios_processor_upgrade_desc(p.smbp_upgrade),
498 	    fp, "  Socket Upgrade: %u", p.smbp_upgrade);
499 
500 	oprintf(fp, "  Socket Status: %s\n",
501 	    SMB_PRSTATUS_PRESENT(p.smbp_status) ?
502 	    "Populated" : "Not Populated");
503 
504 	desc_printf(smbios_processor_status_desc(status),
505 	    fp, "  Processor Status: %u", status);
506 
507 	if (SMB_PRV_LEGACY(p.smbp_voltage)) {
508 		oprintf(fp, "  Supported Voltages:");
509 		switch (p.smbp_voltage) {
510 		case SMB_PRV_5V:
511 			oprintf(fp, " 5.0V");
512 			break;
513 		case SMB_PRV_33V:
514 			oprintf(fp, " 3.3V");
515 			break;
516 		case SMB_PRV_29V:
517 			oprintf(fp, " 2.9V");
518 			break;
519 		}
520 		oprintf(fp, "\n");
521 	} else {
522 		oprintf(fp, "  Supported Voltages: %.1fV\n",
523 		    (float)SMB_PRV_VOLTAGE(p.smbp_voltage) / 10);
524 	}
525 
526 	if (p.smbp_corecount != 0) {
527 		if (p.smbp_corecount != 0xff || p.smbp_corecount2 == 0)
528 			oprintf(fp, "  Core Count: %u\n", p.smbp_corecount);
529 		else
530 			oprintf(fp, "  Core Count: %u\n", p.smbp_corecount2);
531 	} else {
532 		oprintf(fp, "  Core Count: Unknown\n");
533 	}
534 
535 	if (p.smbp_coresenabled != 0) {
536 		if (p.smbp_coresenabled != 0xff || p.smbp_coresenabled2 == 0) {
537 			oprintf(fp, "  Cores Enabled: %u\n",
538 			    p.smbp_coresenabled);
539 		} else {
540 			oprintf(fp, "  Cores Enabled: %u\n",
541 			    p.smbp_coresenabled2);
542 		}
543 	} else {
544 		oprintf(fp, "  Cores Enabled: Unknown\n");
545 	}
546 
547 	if (p.smbp_threadcount != 0) {
548 		if (p.smbp_threadcount != 0xff || p.smbp_threadcount2 == 0) {
549 			oprintf(fp, "  Thread Count: %u\n",
550 			    p.smbp_threadcount);
551 		} else {
552 			oprintf(fp, "  Thread Count: %u\n",
553 			    p.smbp_threadcount2);
554 		}
555 	} else {
556 		oprintf(fp, "  Thread Count: Unknown\n");
557 	}
558 
559 	if (p.smbp_cflags) {
560 		flag_printf(fp, "Processor Characteristics",
561 		    p.smbp_cflags, sizeof (p.smbp_cflags) * NBBY,
562 		    smbios_processor_core_flag_name,
563 		    smbios_processor_core_flag_desc);
564 	}
565 
566 	if (p.smbp_clkspeed != 0)
567 		oprintf(fp, "  External Clock Speed: %uMHz\n", p.smbp_clkspeed);
568 	else
569 		oprintf(fp, "  External Clock Speed: Unknown\n");
570 
571 	if (p.smbp_maxspeed != 0)
572 		oprintf(fp, "  Maximum Speed: %uMHz\n", p.smbp_maxspeed);
573 	else
574 		oprintf(fp, "  Maximum Speed: Unknown\n");
575 
576 	if (p.smbp_curspeed != 0)
577 		oprintf(fp, "  Current Speed: %uMHz\n", p.smbp_curspeed);
578 	else
579 		oprintf(fp, "  Current Speed: Unknown\n");
580 
581 	id_printf(fp, "  L1 Cache Handle: ", p.smbp_l1cache);
582 	id_printf(fp, "  L2 Cache Handle: ", p.smbp_l2cache);
583 	id_printf(fp, "  L3 Cache Handle: ", p.smbp_l3cache);
584 }
585 
586 static void
587 print_cache(smbios_hdl_t *shp, id_t id, FILE *fp)
588 {
589 	smbios_cache_t c;
590 
591 	(void) smbios_info_cache(shp, id, &c);
592 
593 	oprintf(fp, "  Level: %u\n", c.smba_level);
594 	oprintf(fp, "  Maximum Installed Size: %" PRIu64 " bytes\n",
595 	    c.smba_maxsize2);
596 
597 	if (c.smba_size2 != 0) {
598 		oprintf(fp, "  Installed Size: %" PRIu64 " bytes\n",
599 		    c.smba_size2);
600 	} else {
601 		oprintf(fp, "  Installed Size: Not Installed\n");
602 	}
603 
604 	if (c.smba_speed != 0)
605 		oprintf(fp, "  Speed: %uns\n", c.smba_speed);
606 	else
607 		oprintf(fp, "  Speed: Unknown\n");
608 
609 	flag_printf(fp, "Supported SRAM Types",
610 	    c.smba_stype, sizeof (c.smba_stype) * NBBY,
611 	    smbios_cache_ctype_name, smbios_cache_ctype_desc);
612 
613 	desc_printf(smbios_cache_ctype_desc(c.smba_ctype),
614 	    fp, "  Current SRAM Type: 0x%x", c.smba_ctype);
615 
616 	desc_printf(smbios_cache_ecc_desc(c.smba_etype),
617 	    fp, "  Error Correction Type: %u", c.smba_etype);
618 
619 	desc_printf(smbios_cache_logical_desc(c.smba_ltype),
620 	    fp, "  Logical Cache Type: %u", c.smba_ltype);
621 
622 	desc_printf(smbios_cache_assoc_desc(c.smba_assoc),
623 	    fp, "  Associativity: %u", c.smba_assoc);
624 
625 	desc_printf(smbios_cache_mode_desc(c.smba_mode),
626 	    fp, "  Mode: %u", c.smba_mode);
627 
628 	desc_printf(smbios_cache_loc_desc(c.smba_location),
629 	    fp, "  Location: %u", c.smba_location);
630 
631 	flag_printf(fp, "Flags", c.smba_flags, sizeof (c.smba_flags) * NBBY,
632 	    smbios_cache_flag_name, smbios_cache_flag_desc);
633 }
634 
635 static void
636 print_port(smbios_hdl_t *shp, id_t id, FILE *fp)
637 {
638 	smbios_port_t p;
639 
640 	(void) smbios_info_port(shp, id, &p);
641 
642 	oprintf(fp, "  Internal Reference Designator: %s\n", p.smbo_iref);
643 	oprintf(fp, "  External Reference Designator: %s\n", p.smbo_eref);
644 
645 	desc_printf(smbios_port_conn_desc(p.smbo_itype),
646 	    fp, "  Internal Connector Type: %u", p.smbo_itype);
647 
648 	desc_printf(smbios_port_conn_desc(p.smbo_etype),
649 	    fp, "  External Connector Type: %u", p.smbo_etype);
650 
651 	desc_printf(smbios_port_type_desc(p.smbo_ptype),
652 	    fp, "  Port Type: %u", p.smbo_ptype);
653 }
654 
655 static void
656 print_slot(smbios_hdl_t *shp, id_t id, FILE *fp)
657 {
658 	smbios_slot_t s;
659 	smbios_version_t v;
660 
661 	(void) smbios_info_slot(shp, id, &s);
662 	smbios_info_smbios_version(shp, &v);
663 
664 	oprintf(fp, "  Reference Designator: %s\n", s.smbl_name);
665 	oprintf(fp, "  Slot ID: 0x%x\n", s.smbl_id);
666 
667 	desc_printf(smbios_slot_type_desc(s.smbl_type),
668 	    fp, "  Type: 0x%x", s.smbl_type);
669 
670 	desc_printf(smbios_slot_width_desc(s.smbl_width),
671 	    fp, "  Width: 0x%x", s.smbl_width);
672 
673 	desc_printf(smbios_slot_usage_desc(s.smbl_usage),
674 	    fp, "  Usage: 0x%x", s.smbl_usage);
675 
676 	desc_printf(smbios_slot_length_desc(s.smbl_length),
677 	    fp, "  Length: 0x%x", s.smbl_length);
678 
679 	flag_printf(fp, "Slot Characteristics 1",
680 	    s.smbl_ch1, sizeof (s.smbl_ch1) * NBBY,
681 	    smbios_slot_ch1_name, smbios_slot_ch1_desc);
682 
683 	flag_printf(fp, "Slot Characteristics 2",
684 	    s.smbl_ch2, sizeof (s.smbl_ch2) * NBBY,
685 	    smbios_slot_ch2_name, smbios_slot_ch2_desc);
686 
687 	if (check_oem(shp) != 0 && !smbios_vergteq(&v, 2, 6))
688 		return;
689 
690 	oprintf(fp, "  Segment Group: %u\n", s.smbl_sg);
691 	oprintf(fp, "  Bus Number: %u\n", s.smbl_bus);
692 	oprintf(fp, "  Device/Function Number: %u/%u\n", s.smbl_df >> 3,
693 	    s.smbl_df & 0x7);
694 
695 	if (s.smbl_dbw != 0) {
696 		oprintf(fp, "  Data Bus Width: %d\n", s.smbl_dbw);
697 	}
698 
699 	if (s.smbl_npeers > 0) {
700 		smbios_slot_peer_t *peer;
701 		uint_t i, npeers;
702 
703 		if (smbios_info_slot_peers(shp, id, &npeers, &peer) != 0) {
704 			smbios_warn(shp, "failed to read slot peer "
705 			    "information");
706 			return;
707 		}
708 
709 		for (i = 0; i < npeers; i++) {
710 			oprintf(fp, "  Slot Peer %u:\n", i);
711 			oprintf(fp, "    Segment group: %u\n",
712 			    peer[i].smblp_group);
713 			oprintf(fp, "    Bus/Device/Function: %u/%u/%u",
714 			    peer[i].smblp_bus, peer[i].smblp_device,
715 			    peer[i].smblp_function);
716 			oprintf(fp, "    Electrical width: %u\n",
717 			    peer[i].smblp_data_width);
718 		}
719 
720 		smbios_info_slot_peers_free(shp, npeers, peer);
721 	}
722 }
723 
724 static void
725 print_obdevs_ext(smbios_hdl_t *shp, id_t id, FILE *fp)
726 {
727 	boolean_t enabled;
728 	smbios_obdev_ext_t oe;
729 	const char *type;
730 
731 	(void) smbios_info_obdevs_ext(shp, id, &oe);
732 
733 	/*
734 	 * Bit 7 is always whether or not the device is enabled while bits 0:6
735 	 * are the actual device type.
736 	 */
737 	enabled = oe.smboe_dtype >> 7;
738 	type = smbios_onboard_type_desc(oe.smboe_dtype & 0x7f);
739 
740 	oprintf(fp, "  Reference Designator: %s\n", oe.smboe_name);
741 	oprintf(fp, "  Device Enabled: %s\n", enabled == B_TRUE ? "true" :
742 	    "false");
743 	oprintf(fp, "  Device Type: %s\n", type);
744 	oprintf(fp, "  Device Type Instance: %u\n", oe.smboe_dti);
745 	oprintf(fp, "  Segment Group Number: %u\n", oe.smboe_sg);
746 	oprintf(fp, "  Bus Number: %u\n", oe.smboe_bus);
747 	oprintf(fp, "  Device/Function Number: %u\n", oe.smboe_df);
748 }
749 
750 static void
751 print_obdevs(smbios_hdl_t *shp, id_t id, FILE *fp)
752 {
753 	smbios_obdev_t *argv;
754 	int i, argc;
755 
756 	if ((argc = smbios_info_obdevs(shp, id, 0, NULL)) > 0) {
757 		argv = alloca(sizeof (smbios_obdev_t) * argc);
758 		(void) smbios_info_obdevs(shp, id, argc, argv);
759 		for (i = 0; i < argc; i++)
760 			oprintf(fp, "  %s\n", argv[i].smbd_name);
761 	}
762 }
763 
764 static void
765 print_strtab(smbios_hdl_t *shp, id_t id, FILE *fp)
766 {
767 	const char **argv;
768 	int i, argc;
769 
770 	if ((argc = smbios_info_strtab(shp, id, 0, NULL)) > 0) {
771 		argv = alloca(sizeof (char *) * argc);
772 		(void) smbios_info_strtab(shp, id, argc, argv);
773 		for (i = 0; i < argc; i++)
774 			oprintf(fp, "  %s\n", argv[i]);
775 	}
776 }
777 
778 static void
779 print_lang(smbios_hdl_t *shp, id_t id, FILE *fp)
780 {
781 	smbios_lang_t l;
782 
783 	(void) smbios_info_lang(shp, &l);
784 
785 	oprintf(fp, "  Current Language: %s\n", l.smbla_cur);
786 	oprintf(fp, "  Language String Format: %u\n", l.smbla_fmt);
787 	oprintf(fp, "  Number of Installed Languages: %u\n", l.smbla_num);
788 	oprintf(fp, "  Installed Languages:\n");
789 
790 	print_strtab(shp, id, fp);
791 }
792 
793 /*ARGSUSED*/
794 static void
795 print_evlog(smbios_hdl_t *shp, id_t id, FILE *fp)
796 {
797 	smbios_evlog_t ev;
798 	uint32_t i;
799 
800 	(void) smbios_info_eventlog(shp, &ev);
801 
802 	oprintf(fp, "  Log Area Size: %lu bytes\n", (ulong_t)ev.smbev_size);
803 	oprintf(fp, "  Header Offset: %lu\n", (ulong_t)ev.smbev_hdr);
804 	oprintf(fp, "  Data Offset: %lu\n", (ulong_t)ev.smbev_data);
805 
806 	desc_printf(smbios_evlog_method_desc(ev.smbev_method),
807 	    fp, "  Data Access Method: %u", ev.smbev_method);
808 
809 	flag_printf(fp, "Log Flags",
810 	    ev.smbev_flags, sizeof (ev.smbev_flags) * NBBY,
811 	    smbios_evlog_flag_name, smbios_evlog_flag_desc);
812 
813 	desc_printf(smbios_evlog_format_desc(ev.smbev_format),
814 	    fp, "  Log Header Format: %u", ev.smbev_format);
815 
816 	oprintf(fp, "  Update Token: 0x%x\n", ev.smbev_token);
817 	oprintf(fp, "  Data Access Address: ");
818 
819 	switch (ev.smbev_method) {
820 	case SMB_EVM_1x1i_1x1d:
821 	case SMB_EVM_2x1i_1x1d:
822 	case SMB_EVM_1x2i_1x1d:
823 		oprintf(fp, "Index Address 0x%x, Data Address 0x%x\n",
824 		    ev.smbev_addr.eva_io.evi_iaddr,
825 		    ev.smbev_addr.eva_io.evi_daddr);
826 		break;
827 	case SMB_EVM_GPNV:
828 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_gpnv);
829 		break;
830 	default:
831 		oprintf(fp, "0x%x\n", ev.smbev_addr.eva_addr);
832 	}
833 
834 	oprintf(fp, "  Type Descriptors:\n");
835 
836 	for (i = 0; i < ev.smbev_typec; i++) {
837 		oprintf(fp, "  %u: Log Type 0x%x, Data Type 0x%x\n", i,
838 		    ev.smbev_typev[i].smbevt_ltype,
839 		    ev.smbev_typev[i].smbevt_dtype);
840 	}
841 }
842 
843 static void
844 print_bytes(const uint8_t *data, size_t size, FILE *fp)
845 {
846 	size_t row, rows = P2ROUNDUP(size, 16) / 16;
847 	size_t col, cols;
848 
849 	char buf[17];
850 	uint8_t x;
851 
852 	oprintf(fp, "\n  offset:   0 1 2 3  4 5 6 7  8 9 a b  c d e f  "
853 	    "0123456789abcdef\n");
854 
855 	for (row = 0; row < rows; row++) {
856 		oprintf(fp, "  %#6lx: ", (ulong_t)row * 16);
857 		cols = MIN(size - row * 16, 16);
858 
859 		for (col = 0; col < cols; col++) {
860 			if (col % 4 == 0)
861 				oprintf(fp, " ");
862 			x = *data++;
863 			oprintf(fp, "%02x", x);
864 			buf[col] = x <= ' ' || x > '~' ? '.' : x;
865 		}
866 
867 		for (; col < 16; col++) {
868 			if (col % 4 == 0)
869 				oprintf(fp, " ");
870 			oprintf(fp, "  ");
871 			buf[col] = ' ';
872 		}
873 
874 		buf[col] = '\0';
875 		oprintf(fp, "  %s\n", buf);
876 	}
877 
878 	oprintf(fp, "\n");
879 }
880 
881 static void
882 print_memarray(smbios_hdl_t *shp, id_t id, FILE *fp)
883 {
884 	smbios_memarray_t ma;
885 
886 	(void) smbios_info_memarray(shp, id, &ma);
887 
888 	desc_printf(smbios_memarray_loc_desc(ma.smbma_location),
889 	    fp, "  Location: %u", ma.smbma_location);
890 
891 	desc_printf(smbios_memarray_use_desc(ma.smbma_use),
892 	    fp, "  Use: %u", ma.smbma_use);
893 
894 	desc_printf(smbios_memarray_ecc_desc(ma.smbma_ecc),
895 	    fp, "  ECC: %u", ma.smbma_ecc);
896 
897 	oprintf(fp, "  Number of Slots/Sockets: %u\n", ma.smbma_ndevs);
898 	id_printf(fp, "  Memory Error Data: ", ma.smbma_err);
899 	oprintf(fp, "  Max Capacity: %llu bytes\n",
900 	    (u_longlong_t)ma.smbma_size);
901 }
902 
903 static void
904 print_memdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
905 {
906 	smbios_memdevice_t md;
907 
908 	(void) smbios_info_memdevice(shp, id, &md);
909 
910 	id_printf(fp, "  Physical Memory Array: ", md.smbmd_array);
911 	id_printf(fp, "  Memory Error Data: ", md.smbmd_error);
912 
913 	if (md.smbmd_twidth != -1u)
914 		oprintf(fp, "  Total Width: %u bits\n", md.smbmd_twidth);
915 	else
916 		oprintf(fp, "  Total Width: Unknown\n");
917 
918 	if (md.smbmd_dwidth != -1u)
919 		oprintf(fp, "  Data Width: %u bits\n", md.smbmd_dwidth);
920 	else
921 		oprintf(fp, "  Data Width: Unknown\n");
922 
923 	switch (md.smbmd_size) {
924 	case -1ull:
925 		oprintf(fp, "  Size: Unknown\n");
926 		break;
927 	case 0:
928 		oprintf(fp, "  Size: Not Populated\n");
929 		break;
930 	default:
931 		oprintf(fp, "  Size: %llu bytes\n",
932 		    (u_longlong_t)md.smbmd_size);
933 	}
934 
935 	desc_printf(smbios_memdevice_form_desc(md.smbmd_form),
936 	    fp, "  Form Factor: %u", md.smbmd_form);
937 
938 	if (md.smbmd_set == 0)
939 		oprintf(fp, "  Set: None\n");
940 	else if (md.smbmd_set == (uint8_t)-1u)
941 		oprintf(fp, "  Set: Unknown\n");
942 	else
943 		oprintf(fp, "  Set: %u\n", md.smbmd_set);
944 
945 	if (md.smbmd_rank != 0) {
946 		desc_printf(smbios_memdevice_rank_desc(md.smbmd_rank),
947 		    fp, "  Rank: %u", md.smbmd_rank);
948 	} else {
949 		oprintf(fp, "  Rank: Unknown\n");
950 	}
951 
952 	desc_printf(smbios_memdevice_type_desc(md.smbmd_type),
953 	    fp, "  Memory Type: %u", md.smbmd_type);
954 
955 	flag_printf(fp, "Flags", md.smbmd_flags, sizeof (md.smbmd_flags) * NBBY,
956 	    smbios_memdevice_flag_name, smbios_memdevice_flag_desc);
957 
958 	if (md.smbmd_speed != 0)
959 		oprintf(fp, "  Speed: %u MT/s\n", md.smbmd_speed);
960 	else
961 		oprintf(fp, "  Speed: Unknown\n");
962 
963 	if (md.smbmd_clkspeed != 0)
964 		oprintf(fp, "  Configured Speed: %u MT/s\n", md.smbmd_clkspeed);
965 	else
966 		oprintf(fp, "  Configured Speed: Unknown\n");
967 
968 	oprintf(fp, "  Device Locator: %s\n", md.smbmd_dloc);
969 	oprintf(fp, "  Bank Locator: %s\n", md.smbmd_bloc);
970 
971 	if (md.smbmd_minvolt != 0) {
972 		oprintf(fp, "  Minimum Voltage: %.2fV\n",
973 		    md.smbmd_minvolt / 1000.0);
974 	} else {
975 		oprintf(fp, "  Minimum Voltage: Unknown\n");
976 	}
977 
978 	if (md.smbmd_maxvolt != 0) {
979 		oprintf(fp, "  Maximum Voltage: %.2fV\n",
980 		    md.smbmd_maxvolt / 1000.0);
981 	} else {
982 		oprintf(fp, "  Maximum Voltage: Unknown\n");
983 	}
984 
985 	if (md.smbmd_confvolt != 0) {
986 		oprintf(fp, "  Configured Voltage: %.2fV\n",
987 		    md.smbmd_confvolt / 1000.0);
988 	} else {
989 		oprintf(fp, "  Configured Voltage: Unknown\n");
990 	}
991 
992 	if (md.smbmd_memtech != 0) {
993 		desc_printf(smbios_memdevice_memtech_desc(md.smbmd_memtech),
994 		    fp, "  Memory Technology: %u", md.smbmd_memtech);
995 	}
996 
997 	if (md.smbmd_opcap_flags != 0) {
998 		flag_printf(fp, "  Operating Mode Capabilities",
999 		    md.smbmd_opcap_flags, sizeof (md.smbmd_opcap_flags) * NBBY,
1000 		    smbios_memdevice_op_capab_name,
1001 		    smbios_memdevice_op_capab_desc);
1002 	}
1003 
1004 	if (md.smbmd_firmware_rev[0] != '\0') {
1005 		oprintf(fp, "  Firmware Revision: %s\n", md.smbmd_firmware_rev);
1006 	}
1007 
1008 	if (md.smbmd_modmfg_id != 0) {
1009 		jedec_print(fp, "Module Manufacturer ID", md.smbmd_modmfg_id);
1010 	}
1011 
1012 	if (md.smbmd_modprod_id  != 0) {
1013 		jedec_print(fp, "Module Product ID", md.smbmd_modprod_id);
1014 	}
1015 
1016 	if (md.smbmd_cntrlmfg_id != 0) {
1017 		jedec_print(fp, "Memory Subsystem Controller Manufacturer ID",
1018 		    md.smbmd_cntrlmfg_id);
1019 	}
1020 
1021 	if (md.smbmd_cntrlprod_id != 0) {
1022 		jedec_print(fp, "Memory Subsystem Controller Product ID",
1023 		    md.smbmd_cntrlprod_id);
1024 	}
1025 
1026 	if (md.smbmd_nvsize == UINT64_MAX) {
1027 		oprintf(fp, "  Non-volatile Size: Unknown\n");
1028 	} else if (md.smbmd_nvsize != 0) {
1029 		oprintf(fp, "  Non-volatile Size: %llu bytes\n",
1030 		    (u_longlong_t)md.smbmd_nvsize);
1031 	}
1032 
1033 	if (md.smbmd_volatile_size == UINT64_MAX) {
1034 		oprintf(fp, "  Volatile Size: Unknown\n");
1035 	} else if (md.smbmd_volatile_size != 0) {
1036 		oprintf(fp, "  Volatile Size: %llu bytes\n",
1037 		    (u_longlong_t)md.smbmd_volatile_size);
1038 	}
1039 
1040 	if (md.smbmd_cache_size == UINT64_MAX) {
1041 		oprintf(fp, "  Cache Size: Unknown\n");
1042 	} else if (md.smbmd_cache_size != 0) {
1043 		oprintf(fp, "  Cache Size: %llu bytes\n",
1044 		    (u_longlong_t)md.smbmd_cache_size);
1045 	}
1046 
1047 	if (md.smbmd_logical_size == UINT64_MAX) {
1048 		oprintf(fp, "  Logical Size: Unknown\n");
1049 	} else if (md.smbmd_logical_size != 0) {
1050 		oprintf(fp, "  Logical Size: %llu bytes\n",
1051 		    (u_longlong_t)md.smbmd_logical_size);
1052 	}
1053 }
1054 
1055 static void
1056 print_memarrmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1057 {
1058 	smbios_memarrmap_t ma;
1059 
1060 	(void) smbios_info_memarrmap(shp, id, &ma);
1061 
1062 	id_printf(fp, "  Physical Memory Array: ", ma.smbmam_array);
1063 	oprintf(fp, "  Devices per Row: %u\n", ma.smbmam_width);
1064 
1065 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1066 	    (u_longlong_t)ma.smbmam_addr, (u_longlong_t)ma.smbmam_size);
1067 }
1068 
1069 static void
1070 print_memdevmap(smbios_hdl_t *shp, id_t id, FILE *fp)
1071 {
1072 	smbios_memdevmap_t md;
1073 
1074 	(void) smbios_info_memdevmap(shp, id, &md);
1075 
1076 	id_printf(fp, "  Memory Device: ", md.smbmdm_device);
1077 	id_printf(fp, "  Memory Array Mapped Address: ", md.smbmdm_arrmap);
1078 
1079 	oprintf(fp, "  Physical Address: 0x%llx\n  Size: %llu bytes\n",
1080 	    (u_longlong_t)md.smbmdm_addr, (u_longlong_t)md.smbmdm_size);
1081 
1082 	oprintf(fp, "  Partition Row Position: %u\n", md.smbmdm_rpos);
1083 	oprintf(fp, "  Interleave Position: %u\n", md.smbmdm_ipos);
1084 	oprintf(fp, "  Interleave Data Depth: %u\n", md.smbmdm_idepth);
1085 }
1086 
1087 static void
1088 print_hwsec(smbios_hdl_t *shp, FILE *fp)
1089 {
1090 	smbios_hwsec_t h;
1091 
1092 	(void) smbios_info_hwsec(shp, &h);
1093 
1094 	desc_printf(smbios_hwsec_desc(h.smbh_pwr_ps),
1095 	    fp, "  Power-On Password Status: %u", h.smbh_pwr_ps);
1096 	desc_printf(smbios_hwsec_desc(h.smbh_kbd_ps),
1097 	    fp, "  Keyboard Password Status: %u", h.smbh_kbd_ps);
1098 	desc_printf(smbios_hwsec_desc(h.smbh_adm_ps),
1099 	    fp, "  Administrator Password Status: %u", h.smbh_adm_ps);
1100 	desc_printf(smbios_hwsec_desc(h.smbh_pan_ps),
1101 	    fp, "  Front Panel Reset Status: %u", h.smbh_pan_ps);
1102 }
1103 
1104 static void
1105 print_vprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1106 {
1107 	smbios_vprobe_t vp;
1108 
1109 	if (smbios_info_vprobe(shp, id, &vp) != 0) {
1110 		smbios_warn(shp, "failed to read voltage probe information");
1111 		return;
1112 	}
1113 
1114 	oprintf(fp, "  Description: %s\n", vp.smbvp_description != NULL ?
1115 	    vp.smbvp_description : "unknown");
1116 	desc_printf(smbios_vprobe_loc_desc(vp.smbvp_location),
1117 	    fp, "  Location: %u", vp.smbvp_location);
1118 	desc_printf(smbios_vprobe_status_desc(vp.smbvp_status),
1119 	    fp, "  Status: %u", vp.smbvp_status);
1120 
1121 	if (vp.smbvp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1122 		oprintf(fp, "  Maximum Possible Voltage: %u mV\n",
1123 		    vp.smbvp_maxval);
1124 	} else {
1125 		oprintf(fp, "  Maximum Possible Voltage: unknown\n");
1126 	}
1127 
1128 	if (vp.smbvp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1129 		oprintf(fp, "  Minimum Possible Voltage: %u mV\n",
1130 		    vp.smbvp_minval);
1131 	} else {
1132 		oprintf(fp, "  Minimum Possible Voltage: unknown\n");
1133 	}
1134 
1135 	if (vp.smbvp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1136 		oprintf(fp, "  Probe Resolution: %u.%u mV\n",
1137 		    vp.smbvp_resolution / 10,
1138 		    vp.smbvp_resolution % 10);
1139 	} else {
1140 		oprintf(fp, "  Probe Resolution: unknown\n");
1141 	}
1142 
1143 	if (vp.smbvp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1144 		oprintf(fp, "  Probe Tolerance: +/-%u mV\n",
1145 		    vp.smbvp_tolerance);
1146 	} else {
1147 		oprintf(fp, "  Probe Tolerance: unknown\n");
1148 	}
1149 
1150 	if (vp.smbvp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1151 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1152 		    vp.smbvp_accuracy / 100,
1153 		    vp.smbvp_accuracy % 100);
1154 	} else {
1155 		oprintf(fp, "  Probe Accuracy: unknown\n");
1156 	}
1157 
1158 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", vp.smbvp_oem);
1159 
1160 	if (vp.smbvp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1161 		oprintf(fp, "  Probe Nominal Value: %u mV\n", vp.smbvp_nominal);
1162 	} else {
1163 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1164 	}
1165 }
1166 
1167 static void
1168 print_cooldev(smbios_hdl_t *shp, id_t id, FILE *fp)
1169 {
1170 	smbios_cooldev_t cd;
1171 
1172 	if (smbios_info_cooldev(shp, id, &cd) != 0) {
1173 		smbios_warn(shp, "failed to read cooling device "
1174 		    "information");
1175 		return;
1176 	}
1177 
1178 	id_printf(fp, "  Temperature Probe Handle: ", cd.smbcd_tprobe);
1179 	desc_printf(smbios_cooldev_type_desc(cd.smbcd_type),
1180 	    fp, "  Device Type: %u", cd.smbcd_type);
1181 	desc_printf(smbios_cooldev_status_desc(cd.smbcd_status),
1182 	    fp, "  Status: %u", cd.smbcd_status);
1183 	oprintf(fp, "  Cooling Unit Group: %u\n", cd.smbcd_group);
1184 	oprintf(fp, "  OEM- or BIOS- defined data: 0x%x\n", cd.smbcd_oem);
1185 	if (cd.smbcd_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1186 		oprintf(fp, "  Nominal Speed: %u RPM\n", cd.smbcd_nominal);
1187 	} else {
1188 		oprintf(fp, "  Nominal Speed: unknown\n");
1189 	}
1190 
1191 	if (cd.smbcd_descr != NULL && cd.smbcd_descr[0] != '\0') {
1192 		oprintf(fp, "  Description: %s\n", cd.smbcd_descr);
1193 	}
1194 }
1195 
1196 static void
1197 print_tprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1198 {
1199 	smbios_tprobe_t tp;
1200 
1201 	if (smbios_info_tprobe(shp, id, &tp) != 0) {
1202 		smbios_warn(shp, "failed to read temperature probe "
1203 		    "information");
1204 		return;
1205 	}
1206 
1207 	oprintf(fp, "  Description: %s\n", tp.smbtp_description != NULL ?
1208 	    tp.smbtp_description : "unknown");
1209 	desc_printf(smbios_tprobe_loc_desc(tp.smbtp_location),
1210 	    fp, "  Location: %u", tp.smbtp_location);
1211 	desc_printf(smbios_tprobe_status_desc(tp.smbtp_status),
1212 	    fp, "  Status: %u", tp.smbtp_status);
1213 
1214 	if (tp.smbtp_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1215 		oprintf(fp, "  Maximum Possible Temperature: %u.%u C\n",
1216 		    tp.smbtp_maxval / 10, tp.smbtp_maxval % 10);
1217 	} else {
1218 		oprintf(fp, "  Maximum Possible Temperature: unknown\n");
1219 	}
1220 
1221 	if (tp.smbtp_minval != SMB_PROBE_UNKNOWN_VALUE) {
1222 		oprintf(fp, "  Minimum Possible Temperature: %u.%u C\n",
1223 		    tp.smbtp_minval / 10, tp.smbtp_minval % 10);
1224 	} else {
1225 		oprintf(fp, "  Minimum Possible Temperature: unknown\n");
1226 	}
1227 
1228 	if (tp.smbtp_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1229 		oprintf(fp, "  Probe Resolution: %u.%03u C\n",
1230 		    tp.smbtp_resolution / 1000,
1231 		    tp.smbtp_resolution % 1000);
1232 	} else {
1233 		oprintf(fp, "  Probe Resolution: unknown\n");
1234 	}
1235 
1236 	if (tp.smbtp_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1237 		oprintf(fp, "  Probe Tolerance: +/-%u.%u C\n",
1238 		    tp.smbtp_tolerance / 10, tp.smbtp_tolerance % 10);
1239 	} else {
1240 		oprintf(fp, "  Probe Tolerance: unknown\n");
1241 	}
1242 
1243 	if (tp.smbtp_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1244 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1245 		    tp.smbtp_accuracy / 100,
1246 		    tp.smbtp_accuracy % 100);
1247 	} else {
1248 		oprintf(fp, "  Probe Accuracy: unknown\n");
1249 	}
1250 
1251 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", tp.smbtp_oem);
1252 
1253 	if (tp.smbtp_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1254 		oprintf(fp, "  Probe Nominal Value: %u.%u C\n",
1255 		    tp.smbtp_nominal / 10, tp.smbtp_nominal % 10);
1256 	} else {
1257 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1258 	}
1259 }
1260 
1261 static void
1262 print_iprobe(smbios_hdl_t *shp, id_t id, FILE *fp)
1263 {
1264 	smbios_iprobe_t ip;
1265 
1266 	if (smbios_info_iprobe(shp, id, &ip) != 0) {
1267 		smbios_warn(shp, "failed to read current probe information");
1268 		return;
1269 	}
1270 
1271 	oprintf(fp, "  Description: %s\n", ip.smbip_description != NULL ?
1272 	    ip.smbip_description : "unknown");
1273 	desc_printf(smbios_iprobe_loc_desc(ip.smbip_location),
1274 	    fp, "  Location: %u", ip.smbip_location);
1275 	desc_printf(smbios_iprobe_status_desc(ip.smbip_status),
1276 	    fp, "  Status: %u", ip.smbip_status);
1277 
1278 	if (ip.smbip_maxval != SMB_PROBE_UNKNOWN_VALUE) {
1279 		oprintf(fp, "  Maximum Possible Current: %u mA\n",
1280 		    ip.smbip_maxval);
1281 	} else {
1282 		oprintf(fp, "  Maximum Possible Current: unknown\n");
1283 	}
1284 
1285 	if (ip.smbip_minval != SMB_PROBE_UNKNOWN_VALUE) {
1286 		oprintf(fp, "  Minimum Possible Current: %u mA\n",
1287 		    ip.smbip_minval);
1288 	} else {
1289 		oprintf(fp, "  Minimum Possible Current: unknown\n");
1290 	}
1291 
1292 	if (ip.smbip_resolution != SMB_PROBE_UNKNOWN_VALUE) {
1293 		oprintf(fp, "  Probe Resolution: %u.%u mA\n",
1294 		    ip.smbip_resolution / 10,
1295 		    ip.smbip_resolution % 10);
1296 	} else {
1297 		oprintf(fp, "  Probe Resolution: unknown\n");
1298 	}
1299 
1300 	if (ip.smbip_tolerance != SMB_PROBE_UNKNOWN_VALUE) {
1301 		oprintf(fp, "  Probe Tolerance: +/-%u mA\n",
1302 		    ip.smbip_tolerance);
1303 	} else {
1304 		oprintf(fp, "  Probe Tolerance: unknown\n");
1305 	}
1306 
1307 	if (ip.smbip_accuracy != SMB_PROBE_UNKNOWN_VALUE) {
1308 		oprintf(fp, "  Probe Accuracy: +/-%u.%02u%%\n",
1309 		    ip.smbip_accuracy / 100,
1310 		    ip.smbip_accuracy % 100);
1311 	} else {
1312 		oprintf(fp, "  Probe Accuracy: unknown\n");
1313 	}
1314 
1315 	oprintf(fp, "  OEM- or BIOS- defined value: 0x%x\n", ip.smbip_oem);
1316 
1317 	if (ip.smbip_nominal != SMB_PROBE_UNKNOWN_VALUE) {
1318 		oprintf(fp, "  Probe Nominal Value: %u mA\n", ip.smbip_nominal);
1319 	} else {
1320 		oprintf(fp, "  Probe Nominal Value: unknown\n");
1321 	}
1322 }
1323 
1324 
1325 static void
1326 print_boot(smbios_hdl_t *shp, FILE *fp)
1327 {
1328 	smbios_boot_t b;
1329 
1330 	(void) smbios_info_boot(shp, &b);
1331 
1332 	desc_printf(smbios_boot_desc(b.smbt_status),
1333 	    fp, "  Boot Status Code: 0x%x", b.smbt_status);
1334 
1335 	if (b.smbt_size != 0) {
1336 		oprintf(fp, "  Boot Data (%lu bytes):\n", (ulong_t)b.smbt_size);
1337 		print_bytes(b.smbt_data, b.smbt_size, fp);
1338 	}
1339 }
1340 
1341 static void
1342 print_ipmi(smbios_hdl_t *shp, FILE *fp)
1343 {
1344 	smbios_ipmi_t i;
1345 
1346 	(void) smbios_info_ipmi(shp, &i);
1347 
1348 	desc_printf(smbios_ipmi_type_desc(i.smbip_type),
1349 	    fp, "  Type: %u", i.smbip_type);
1350 
1351 	oprintf(fp, "  BMC IPMI Version: %u.%u\n",
1352 	    i.smbip_vers.smbv_major, i.smbip_vers.smbv_minor);
1353 
1354 	oprintf(fp, "  i2c Bus Slave Address: 0x%x\n", i.smbip_i2c);
1355 	oprintf(fp, "  NV Storage Device Bus ID: 0x%x\n", i.smbip_bus);
1356 	oprintf(fp, "  BMC Base Address: 0x%llx\n", (u_longlong_t)i.smbip_addr);
1357 	oprintf(fp, "  Interrupt Number: %u\n", i.smbip_intr);
1358 	oprintf(fp, "  Register Spacing: %u\n", i.smbip_regspacing);
1359 
1360 	flag_printf(fp, "Flags", i.smbip_flags, sizeof (i.smbip_flags) * NBBY,
1361 	    smbios_ipmi_flag_name, smbios_ipmi_flag_desc);
1362 }
1363 
1364 static void
1365 print_powersup(smbios_hdl_t *shp, id_t id, FILE *fp)
1366 {
1367 	smbios_powersup_t p;
1368 
1369 	if (smbios_info_powersup(shp, id, &p) != 0) {
1370 		smbios_warn(shp, "failed to read power supply information");
1371 		return;
1372 	}
1373 
1374 	oprintf(fp, "  Power Supply Group: %u\n", p.smbps_group);
1375 	if (p.smbps_maxout != 0x8000) {
1376 		oprintf(fp, "  Maximum Output: %llu mW\n", p.smbps_maxout);
1377 	} else {
1378 		oprintf(fp, "  Maximum Output: unknown\n");
1379 	}
1380 
1381 	flag_printf(fp, "Characteristics", p.smbps_flags,
1382 	    sizeof (p.smbps_flags) * NBBY, smbios_powersup_flag_name,
1383 	    smbios_powersup_flag_desc);
1384 
1385 	desc_printf(smbios_powersup_input_desc(p.smbps_ivrs),
1386 	    fp, "  Input Voltage Range Switching: %u", p.smbps_ivrs);
1387 	desc_printf(smbios_powersup_status_desc(p.smbps_status),
1388 	    fp, "  Status: %u", p.smbps_status);
1389 	desc_printf(smbios_powersup_type_desc(p.smbps_pstype),
1390 	    fp, "  Type: %u", p.smbps_pstype);
1391 
1392 	if (p.smbps_vprobe != 0xffff) {
1393 		oprintf(fp, "  Voltage Probe Handle: %lu\n", p.smbps_vprobe);
1394 	}
1395 
1396 	if (p.smbps_cooldev != 0xffff) {
1397 		oprintf(fp, "  Cooling Device Handle: %lu\n", p.smbps_cooldev);
1398 	}
1399 
1400 	if (p.smbps_iprobe != 0xffff) {
1401 		oprintf(fp, "  Current Probe Handle: %lu\n", p.smbps_iprobe);
1402 	}
1403 }
1404 
1405 static void
1406 print_extprocessor(smbios_hdl_t *shp, id_t id, FILE *fp)
1407 {
1408 	int i;
1409 	smbios_processor_ext_t ep;
1410 
1411 	if (check_oem(shp) != 0)
1412 		return;
1413 
1414 	(void) smbios_info_extprocessor(shp, id, &ep);
1415 
1416 	oprintf(fp, "  Processor: %u\n", ep.smbpe_processor);
1417 	oprintf(fp, "  FRU: %u\n", ep.smbpe_fru);
1418 	oprintf(fp, "  Initial APIC ID count: %u\n\n", ep.smbpe_n);
1419 
1420 	for (i = 0; i < ep.smbpe_n; i++) {
1421 		oprintf(fp, "  Logical Strand %u: Initial APIC ID: %u\n", i,
1422 		    ep.smbpe_apicid[i]);
1423 	}
1424 }
1425 
1426 static void
1427 print_extport(smbios_hdl_t *shp, id_t id, FILE *fp)
1428 {
1429 	smbios_port_ext_t epo;
1430 
1431 	if (check_oem(shp) != 0)
1432 		return;
1433 
1434 	(void) smbios_info_extport(shp, id, &epo);
1435 
1436 	oprintf(fp, "  Chassis Handle: %u\n", epo.smbporte_chassis);
1437 	oprintf(fp, "  Port Connector Handle: %u\n", epo.smbporte_port);
1438 	oprintf(fp, "  Device Type: %u\n", epo.smbporte_dtype);
1439 	oprintf(fp, "  Device Handle: %u\n", epo.smbporte_devhdl);
1440 	oprintf(fp, "  PHY: %u\n", epo.smbporte_phy);
1441 }
1442 
1443 static void
1444 print_pciexrc(smbios_hdl_t *shp, id_t id, FILE *fp)
1445 {
1446 	smbios_pciexrc_t pcie;
1447 
1448 	if (check_oem(shp) != 0)
1449 		return;
1450 
1451 	(void) smbios_info_pciexrc(shp, id, &pcie);
1452 
1453 	oprintf(fp, "  Component ID: %u\n", pcie.smbpcie_bb);
1454 	oprintf(fp, "  BDF: 0x%x\n", pcie.smbpcie_bdf);
1455 }
1456 
1457 static void
1458 print_extmemarray(smbios_hdl_t *shp, id_t id, FILE *fp)
1459 {
1460 	smbios_memarray_ext_t em;
1461 
1462 	if (check_oem(shp) != 0)
1463 		return;
1464 
1465 	(void) smbios_info_extmemarray(shp, id, &em);
1466 
1467 	oprintf(fp, "  Physical Memory Array Handle: %u\n", em.smbmae_ma);
1468 	oprintf(fp, "  Component Parent Handle: %u\n", em.smbmae_comp);
1469 	oprintf(fp, "  BDF: 0x%x\n", em.smbmae_bdf);
1470 }
1471 
1472 static void
1473 print_extmemdevice(smbios_hdl_t *shp, id_t id, FILE *fp)
1474 {
1475 	int i;
1476 	smbios_memdevice_ext_t emd;
1477 
1478 	if (check_oem(shp) != 0)
1479 		return;
1480 
1481 	(void) smbios_info_extmemdevice(shp, id, &emd);
1482 
1483 	oprintf(fp, "  Memory Device Handle: %u\n", emd.smbmdeve_md);
1484 	oprintf(fp, "  DRAM Channel: %u\n", emd.smbmdeve_drch);
1485 	oprintf(fp, "  Number of Chip Selects: %u\n", emd.smbmdeve_ncs);
1486 
1487 	for (i = 0; i < emd.smbmdeve_ncs; i++) {
1488 		oprintf(fp, "  Chip Select: %u\n", emd.smbmdeve_cs[i]);
1489 	}
1490 }
1491 
1492 static int
1493 print_struct(smbios_hdl_t *shp, const smbios_struct_t *sp, void *fp)
1494 {
1495 	smbios_info_t info;
1496 	int hex = opt_x;
1497 	const char *s;
1498 
1499 	if (opt_t != -1 && opt_t != sp->smbstr_type)
1500 		return (0); /* skip struct if type doesn't match -t */
1501 
1502 	if (!opt_O && (sp->smbstr_type == SMB_TYPE_MEMCTL ||
1503 	    sp->smbstr_type == SMB_TYPE_MEMMOD))
1504 		return (0); /* skip struct if type is obsolete */
1505 
1506 	if (g_hdr++ == 0 || !opt_s)
1507 		oprintf(fp, "%-5s %-4s %s\n", "ID", "SIZE", "TYPE");
1508 
1509 	oprintf(fp, "%-5u %-4lu",
1510 	    (uint_t)sp->smbstr_id, (ulong_t)sp->smbstr_size);
1511 
1512 	if ((s = smbios_type_name(sp->smbstr_type)) != NULL)
1513 		oprintf(fp, " %s (type %u)", s, sp->smbstr_type);
1514 	else if (sp->smbstr_type > SMB_TYPE_OEM_LO &&
1515 	    sp->smbstr_type < SMB_TYPE_OEM_HI)
1516 		oprintf(fp, " %s+%u (type %u)", "SMB_TYPE_OEM_LO",
1517 		    sp->smbstr_type - SMB_TYPE_OEM_LO, sp->smbstr_type);
1518 	else
1519 		oprintf(fp, " %u", sp->smbstr_type);
1520 
1521 	if ((s = smbios_type_desc(sp->smbstr_type)) != NULL)
1522 		oprintf(fp, " (%s)\n", s);
1523 	else
1524 		oprintf(fp, "\n");
1525 
1526 	if (opt_s)
1527 		return (0); /* only print header line if -s specified */
1528 
1529 	if (smbios_info_common(shp, sp->smbstr_id, &info) == 0) {
1530 		oprintf(fp, "\n");
1531 		print_common(&info, fp);
1532 	}
1533 
1534 	switch (sp->smbstr_type) {
1535 	case SMB_TYPE_BIOS:
1536 		oprintf(fp, "\n");
1537 		print_bios(shp, fp);
1538 		break;
1539 	case SMB_TYPE_SYSTEM:
1540 		oprintf(fp, "\n");
1541 		print_system(shp, fp);
1542 		break;
1543 	case SMB_TYPE_BASEBOARD:
1544 		oprintf(fp, "\n");
1545 		print_bboard(shp, sp->smbstr_id, fp);
1546 		break;
1547 	case SMB_TYPE_CHASSIS:
1548 		oprintf(fp, "\n");
1549 		print_chassis(shp, sp->smbstr_id, fp);
1550 		break;
1551 	case SMB_TYPE_PROCESSOR:
1552 		oprintf(fp, "\n");
1553 		print_processor(shp, sp->smbstr_id, fp);
1554 		break;
1555 	case SMB_TYPE_CACHE:
1556 		oprintf(fp, "\n");
1557 		print_cache(shp, sp->smbstr_id, fp);
1558 		break;
1559 	case SMB_TYPE_PORT:
1560 		oprintf(fp, "\n");
1561 		print_port(shp, sp->smbstr_id, fp);
1562 		break;
1563 	case SMB_TYPE_SLOT:
1564 		oprintf(fp, "\n");
1565 		print_slot(shp, sp->smbstr_id, fp);
1566 		break;
1567 	case SMB_TYPE_OBDEVS:
1568 		oprintf(fp, "\n");
1569 		print_obdevs(shp, sp->smbstr_id, fp);
1570 		break;
1571 	case SMB_TYPE_OEMSTR:
1572 	case SMB_TYPE_SYSCONFSTR:
1573 		oprintf(fp, "\n");
1574 		print_strtab(shp, sp->smbstr_id, fp);
1575 		break;
1576 	case SMB_TYPE_LANG:
1577 		oprintf(fp, "\n");
1578 		print_lang(shp, sp->smbstr_id, fp);
1579 		break;
1580 	case SMB_TYPE_EVENTLOG:
1581 		oprintf(fp, "\n");
1582 		print_evlog(shp, sp->smbstr_id, fp);
1583 		break;
1584 	case SMB_TYPE_MEMARRAY:
1585 		oprintf(fp, "\n");
1586 		print_memarray(shp, sp->smbstr_id, fp);
1587 		break;
1588 	case SMB_TYPE_MEMDEVICE:
1589 		oprintf(fp, "\n");
1590 		print_memdevice(shp, sp->smbstr_id, fp);
1591 		break;
1592 	case SMB_TYPE_MEMARRAYMAP:
1593 		oprintf(fp, "\n");
1594 		print_memarrmap(shp, sp->smbstr_id, fp);
1595 		break;
1596 	case SMB_TYPE_MEMDEVICEMAP:
1597 		oprintf(fp, "\n");
1598 		print_memdevmap(shp, sp->smbstr_id, fp);
1599 		break;
1600 	case SMB_TYPE_SECURITY:
1601 		oprintf(fp, "\n");
1602 		print_hwsec(shp, fp);
1603 		break;
1604 	case SMB_TYPE_VPROBE:
1605 		oprintf(fp, "\n");
1606 		print_vprobe(shp, sp->smbstr_id, fp);
1607 		break;
1608 	case SMB_TYPE_COOLDEV:
1609 		oprintf(fp, "\n");
1610 		print_cooldev(shp, sp->smbstr_id, fp);
1611 		break;
1612 	case SMB_TYPE_TPROBE:
1613 		oprintf(fp, "\n");
1614 		print_tprobe(shp, sp->smbstr_id, fp);
1615 		break;
1616 	case SMB_TYPE_IPROBE:
1617 		oprintf(fp, "\n");
1618 		print_iprobe(shp, sp->smbstr_id, fp);
1619 		break;
1620 	case SMB_TYPE_BOOT:
1621 		oprintf(fp, "\n");
1622 		print_boot(shp, fp);
1623 		break;
1624 	case SMB_TYPE_IPMIDEV:
1625 		oprintf(fp, "\n");
1626 		print_ipmi(shp, fp);
1627 		break;
1628 	case SMB_TYPE_POWERSUP:
1629 		oprintf(fp, "\n");
1630 		print_powersup(shp, sp->smbstr_id, fp);
1631 		break;
1632 	case SMB_TYPE_OBDEVEXT:
1633 		oprintf(fp, "\n");
1634 		print_obdevs_ext(shp, sp->smbstr_id, fp);
1635 		break;
1636 	case SUN_OEM_EXT_PROCESSOR:
1637 		oprintf(fp, "\n");
1638 		print_extprocessor(shp, sp->smbstr_id, fp);
1639 		break;
1640 	case SUN_OEM_EXT_PORT:
1641 		oprintf(fp, "\n");
1642 		print_extport(shp, sp->smbstr_id, fp);
1643 		break;
1644 	case SUN_OEM_PCIEXRC:
1645 		oprintf(fp, "\n");
1646 		print_pciexrc(shp, sp->smbstr_id, fp);
1647 		break;
1648 	case SUN_OEM_EXT_MEMARRAY:
1649 		oprintf(fp, "\n");
1650 		print_extmemarray(shp, sp->smbstr_id, fp);
1651 		break;
1652 	case SUN_OEM_EXT_MEMDEVICE:
1653 		oprintf(fp, "\n");
1654 		print_extmemdevice(shp, sp->smbstr_id, fp);
1655 		break;
1656 	default:
1657 		hex++;
1658 	}
1659 
1660 	if (hex)
1661 		print_bytes(sp->smbstr_data, sp->smbstr_size, fp);
1662 	else
1663 		oprintf(fp, "\n");
1664 
1665 	return (0);
1666 }
1667 
1668 static uint16_t
1669 getu16(const char *name, const char *s)
1670 {
1671 	u_longlong_t val;
1672 	char *p;
1673 
1674 	errno = 0;
1675 	val = strtoull(s, &p, 0);
1676 
1677 	if (errno != 0 || p == s || *p != '\0' || val > UINT16_MAX) {
1678 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
1679 		    g_pname, name, s);
1680 		exit(SMBIOS_USAGE);
1681 	}
1682 
1683 	return ((uint16_t)val);
1684 }
1685 
1686 static uint16_t
1687 getstype(const char *name, const char *s)
1688 {
1689 	const char *ts;
1690 	uint16_t t;
1691 
1692 	for (t = 0; t < SMB_TYPE_OEM_LO; t++) {
1693 		if ((ts = smbios_type_name(t)) != NULL && strcmp(s, ts) == 0)
1694 			return (t);
1695 	}
1696 
1697 	(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
1698 	    g_pname, name, s);
1699 
1700 	exit(SMBIOS_USAGE);
1701 	/*NOTREACHED*/
1702 }
1703 
1704 static int
1705 usage(FILE *fp)
1706 {
1707 	(void) fprintf(fp, "Usage: %s "
1708 	    "[-BeOsx] [-i id] [-t type] [-w file] [file]\n\n", g_pname);
1709 
1710 	(void) fprintf(fp,
1711 	    "\t-B disable header validation for broken BIOSes\n"
1712 	    "\t-e display SMBIOS entry point information\n"
1713 	    "\t-i display only the specified structure\n"
1714 	    "\t-O display obsolete structure types\n"
1715 	    "\t-s display only a summary of structure identifiers and types\n"
1716 	    "\t-t display only the specified structure type\n"
1717 	    "\t-w write the raw data to the specified file\n"
1718 	    "\t-x display raw data for structures\n");
1719 
1720 	return (SMBIOS_USAGE);
1721 }
1722 
1723 int
1724 main(int argc, char *argv[])
1725 {
1726 	const char *ifile = NULL;
1727 	const char *ofile = NULL;
1728 	int oflags = 0;
1729 
1730 	smbios_hdl_t *shp;
1731 	smbios_struct_t s;
1732 	int err, fd, c;
1733 	char *p;
1734 
1735 	if ((p = strrchr(argv[0], '/')) == NULL)
1736 		g_pname = argv[0];
1737 	else
1738 		g_pname = p + 1;
1739 
1740 	while (optind < argc) {
1741 		while ((c = getopt(argc, argv, "Bei:Ost:w:xZ")) != EOF) {
1742 			switch (c) {
1743 			case 'B':
1744 				oflags |= SMB_O_NOCKSUM | SMB_O_NOVERS;
1745 				break;
1746 			case 'e':
1747 				opt_e++;
1748 				break;
1749 			case 'i':
1750 				opt_i = getu16("struct ID", optarg);
1751 				break;
1752 			case 'O':
1753 				opt_O++;
1754 				break;
1755 			case 's':
1756 				opt_s++;
1757 				break;
1758 			case 't':
1759 				if (isdigit(optarg[0]))
1760 					opt_t = getu16("struct type", optarg);
1761 				else
1762 					opt_t = getstype("struct type", optarg);
1763 				break;
1764 			case 'w':
1765 				ofile = optarg;
1766 				break;
1767 			case 'x':
1768 				opt_x++;
1769 				break;
1770 			case 'Z':
1771 				oflags |= SMB_O_ZIDS; /* undocumented */
1772 				break;
1773 			default:
1774 				return (usage(stderr));
1775 			}
1776 		}
1777 
1778 		if (optind < argc) {
1779 			if (ifile != NULL) {
1780 				(void) fprintf(stderr, "%s: illegal "
1781 				    "argument -- %s\n", g_pname, argv[optind]);
1782 				return (SMBIOS_USAGE);
1783 			}
1784 			ifile = argv[optind++];
1785 		}
1786 	}
1787 
1788 	if ((shp = smbios_open(ifile, SMB_VERSION, oflags, &err)) == NULL) {
1789 		(void) fprintf(stderr, "%s: failed to load SMBIOS: %s\n",
1790 		    g_pname, smbios_errmsg(err));
1791 		return (SMBIOS_ERROR);
1792 	}
1793 
1794 	if (opt_i == -1 && opt_t == -1 && opt_e == 0 &&
1795 	    smbios_truncated(shp))
1796 		(void) fprintf(stderr, "%s: SMBIOS table is truncated\n",
1797 		    g_pname);
1798 
1799 	if (ofile != NULL) {
1800 		if ((fd = open(ofile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
1801 			(void) fprintf(stderr, "%s: failed to open %s: %s\n",
1802 			    g_pname, ofile, strerror(errno));
1803 			err = SMBIOS_ERROR;
1804 		} else if (smbios_write(shp, fd) != 0) {
1805 			(void) fprintf(stderr, "%s: failed to write %s: %s\n",
1806 			    g_pname, ofile, smbios_errmsg(smbios_errno(shp)));
1807 			err = SMBIOS_ERROR;
1808 		}
1809 		smbios_close(shp);
1810 		return (err);
1811 	}
1812 
1813 	if (opt_e) {
1814 		print_smbios(shp, stdout);
1815 		smbios_close(shp);
1816 		return (SMBIOS_SUCCESS);
1817 	}
1818 
1819 	if (opt_O && (opt_i != -1 || opt_t != -1))
1820 		opt_O++; /* -i or -t imply displaying obsolete records */
1821 
1822 	if (opt_i != -1)
1823 		err = smbios_lookup_id(shp, opt_i, &s);
1824 	else
1825 		err = smbios_iter(shp, print_struct, stdout);
1826 
1827 	if (err != 0) {
1828 		(void) fprintf(stderr, "%s: failed to access SMBIOS: %s\n",
1829 		    g_pname, smbios_errmsg(smbios_errno(shp)));
1830 		smbios_close(shp);
1831 		return (SMBIOS_ERROR);
1832 	}
1833 
1834 	if (opt_i != -1)
1835 		(void) print_struct(shp, &s, stdout);
1836 
1837 	smbios_close(shp);
1838 	return (SMBIOS_SUCCESS);
1839 }
1840