xref: /titanic_53/usr/src/cmd/prtfru/prtfru.c (revision 1e3549a6454dbbb2d27b0f1fdb707b1d24b7141b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
594bc7577Sps154918  * Common Development and Distribution License (the "License").
694bc7577Sps154918  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2294bc7577Sps154918  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <alloca.h>
297c478bd9Sstevel@tonic-gate #include <assert.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <libintl.h>
327c478bd9Sstevel@tonic-gate #include <stdarg.h>
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include "fru_tag.h"
387c478bd9Sstevel@tonic-gate #include "libfrup.h"
397c478bd9Sstevel@tonic-gate #include "libfrureg.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define	NUM_ITER_BYTES 4
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define	HEAD_ITER 0
457c478bd9Sstevel@tonic-gate #define	TAIL_ITER 1	/*  not used  */
467c478bd9Sstevel@tonic-gate #define	NUM_ITER  2
477c478bd9Sstevel@tonic-gate #define	MAX_ITER  3
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #define	INDENT 3
507c478bd9Sstevel@tonic-gate #define	TIMESTRINGLEN 128
5194bc7577Sps154918 #define	TEMPERATURE_OFFSET 73
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static void	(*print_node)(fru_node_t fru_type, const char *path,
547c478bd9Sstevel@tonic-gate 				const char *name, end_node_fp_t *end_node,
557c478bd9Sstevel@tonic-gate 				void **end_args);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static char	tagname[sizeof ("?_0123456789_0123456789_0123456789")];
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static int	containers_only = 0, list_only = 0, saved_status = 0, xml = 0;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static FILE	*errlog;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * Definition for data elements found in devices but not found in
657c478bd9Sstevel@tonic-gate  * the system's version of libfrureg
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate static fru_regdef_t  unknown = {
687c478bd9Sstevel@tonic-gate 	REGDEF_VERSION,
697c478bd9Sstevel@tonic-gate 	tagname,
707c478bd9Sstevel@tonic-gate 	-1,
717c478bd9Sstevel@tonic-gate 	-1,
727c478bd9Sstevel@tonic-gate 	-1,
737c478bd9Sstevel@tonic-gate 	-1,
747c478bd9Sstevel@tonic-gate 	FDTYPE_ByteArray,
757c478bd9Sstevel@tonic-gate 	FDISP_Hex,
767c478bd9Sstevel@tonic-gate 	FRU_WHICH_UNDEFINED,
777c478bd9Sstevel@tonic-gate 	FRU_WHICH_UNDEFINED,
787c478bd9Sstevel@tonic-gate 	0,
797c478bd9Sstevel@tonic-gate 	NULL,
807c478bd9Sstevel@tonic-gate 	0,
817c478bd9Sstevel@tonic-gate 	FRU_NOT_ITERATED,
827c478bd9Sstevel@tonic-gate 	NULL
837c478bd9Sstevel@tonic-gate };
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate  * Write message to standard error and possibly the error log buffer
887c478bd9Sstevel@tonic-gate  */
897c478bd9Sstevel@tonic-gate static void
907c478bd9Sstevel@tonic-gate error(const char *format, ...)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	va_list	args;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/* make relevant output appear before error message */
967c478bd9Sstevel@tonic-gate 	if (fflush(stdout) == EOF) {
977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Error flushing output:  %s\n",
987c478bd9Sstevel@tonic-gate 				strerror(errno));
997c478bd9Sstevel@tonic-gate 		exit(1);
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	va_start(args, format);
1037c478bd9Sstevel@tonic-gate 	if (vfprintf(stderr, format, args) < 0) exit(1);
1047c478bd9Sstevel@tonic-gate 	if (errlog && (vfprintf(errlog, format, args) < 0)) exit(1);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Write message to standard output
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate static void
1117c478bd9Sstevel@tonic-gate output(const char *format, ...)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	va_list   args;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	va_start(args, format);
1177c478bd9Sstevel@tonic-gate 	if (vfprintf(stdout, format, args) < 0) {
1187c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1197c478bd9Sstevel@tonic-gate 			strerror(errno));
1207c478bd9Sstevel@tonic-gate 		exit(1);
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * Safe wrapper for putchar()
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate static void
1287c478bd9Sstevel@tonic-gate voidputchar(int c)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 	if (putchar(c) == EOF) {
1317c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1327c478bd9Sstevel@tonic-gate 			strerror(errno));
1337c478bd9Sstevel@tonic-gate 		exit(1);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static void  (*safeputchar)(int c) = voidputchar;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Safe wrapper for puts()
1417c478bd9Sstevel@tonic-gate  */
1427c478bd9Sstevel@tonic-gate static void
1437c478bd9Sstevel@tonic-gate voidputs(const char *s)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	if (fputs(s, stdout) == EOF) {
1467c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1477c478bd9Sstevel@tonic-gate 			strerror(errno));
1487c478bd9Sstevel@tonic-gate 		exit(1);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static void  (*safeputs)(const char *s) = voidputs;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * XML-safe wrapper for putchar():  quotes XML-special characters
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate static void
1587c478bd9Sstevel@tonic-gate xputchar(int c)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	switch (c) {
1617c478bd9Sstevel@tonic-gate 	case '<':
1627c478bd9Sstevel@tonic-gate 		c = fputs("&lt;", stdout);
1637c478bd9Sstevel@tonic-gate 		break;
1647c478bd9Sstevel@tonic-gate 	case '>':
1657c478bd9Sstevel@tonic-gate 		c = fputs("&gt;", stdout);
1667c478bd9Sstevel@tonic-gate 		break;
1677c478bd9Sstevel@tonic-gate 	case '&':
1687c478bd9Sstevel@tonic-gate 		c = fputs("&amp;", stdout);
1697c478bd9Sstevel@tonic-gate 		break;
1707c478bd9Sstevel@tonic-gate 	case '"':
1717c478bd9Sstevel@tonic-gate 		c = fputs("&quot;", stdout);
1727c478bd9Sstevel@tonic-gate 		break;
1737c478bd9Sstevel@tonic-gate 	default:
1747c478bd9Sstevel@tonic-gate 		c = putchar(c);
1757c478bd9Sstevel@tonic-gate 		break;
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (c == EOF) {
1797c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1807c478bd9Sstevel@tonic-gate 			strerror(errno));
1817c478bd9Sstevel@tonic-gate 		exit(1);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * XML-safe analog of puts():  quotes XML-special characters
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate static void
1897c478bd9Sstevel@tonic-gate xputs(const char *s)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	char c;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	for (/* */; ((c = *s) != 0); s++)
1947c478bd9Sstevel@tonic-gate 		xputchar(c);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * Output the XML DTD derived from the registry provided by libfrureg
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate int
2017c478bd9Sstevel@tonic-gate output_dtd(void)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate 	char			**element;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	unsigned int		i, j, num_elements = 0;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	uint8_t			*tagged;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	const fru_regdef_t	*def;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (((element = fru_reg_list_entries(&num_elements)) == NULL) ||
2137c478bd9Sstevel@tonic-gate 	    (num_elements == 0)) {
2147c478bd9Sstevel@tonic-gate 		error(gettext("No FRU ID Registry elements"));
2157c478bd9Sstevel@tonic-gate 		return (1);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if ((tagged = calloc(num_elements, sizeof (*tagged))) == NULL) {
2197c478bd9Sstevel@tonic-gate 		error(gettext("Unable to get memory for tagged element list"),
2207c478bd9Sstevel@tonic-gate 			strerror(errno));
2217c478bd9Sstevel@tonic-gate 		return (1);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/*
2257c478bd9Sstevel@tonic-gate 	 * Output the DTD preamble
2267c478bd9Sstevel@tonic-gate 	 */
2277c478bd9Sstevel@tonic-gate 	output("<!ELEMENT FRUID_XML_Tree (Parameter*, "
2287c478bd9Sstevel@tonic-gate 	    "(Fru | Location | Container)*,\n"
2297c478bd9Sstevel@tonic-gate 	    "                          Parameter*, ErrorLog?, Parameter*)>\n"
2307c478bd9Sstevel@tonic-gate 	    "<!ATTLIST FRUID_XML_Tree>\n"
2317c478bd9Sstevel@tonic-gate 	    "\n"
2327c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Parameter EMPTY>\n"
2337c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter type CDATA #REQUIRED>\n"
2347c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter name CDATA #REQUIRED>\n"
2357c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter value CDATA #REQUIRED>\n"
2367c478bd9Sstevel@tonic-gate 	    "\n"
2377c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Fru (Fru | Location | Container)*>\n"
2387c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Fru name CDATA #REQUIRED>\n"
2397c478bd9Sstevel@tonic-gate 	    "\n"
2407c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Location (Fru | Location | Container)*>\n"
24194bc7577Sps154918 	    "<!ATTLIST Location\n"
24294bc7577Sps154918 	    "	name CDATA #IMPLIED\n"
24394bc7577Sps154918 	    "	value CDATA #IMPLIED\n"
24494bc7577Sps154918 	    ">\n"
2457c478bd9Sstevel@tonic-gate 	    "\n"
2467c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Container (ContainerData?, "
2477c478bd9Sstevel@tonic-gate 	    "(Fru | Location | Container)*)>\n"
2487c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Container name CDATA #REQUIRED>\n"
2497c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Container imagefile CDATA #IMPLIED>\n"
2507c478bd9Sstevel@tonic-gate 	    "\n"
2517c478bd9Sstevel@tonic-gate 	    "<!ELEMENT ContainerData (Segment*)>\n"
2527c478bd9Sstevel@tonic-gate 	    "<!ATTLIST ContainerData>\n"
2537c478bd9Sstevel@tonic-gate 	    "\n"
2547c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Segment name CDATA #REQUIRED>\n"
2557c478bd9Sstevel@tonic-gate 	    "\n"
2567c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Index EMPTY>\n"
2577c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Index value CDATA #REQUIRED>\n"
2587c478bd9Sstevel@tonic-gate 	    "\n"
2597c478bd9Sstevel@tonic-gate 	    "<!ELEMENT ErrorLog (#PCDATA)>\n"
2607c478bd9Sstevel@tonic-gate 	    "<!ATTLIST ErrorLog>\n"
2617c478bd9Sstevel@tonic-gate 	    "\n");
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * Output the definition for each element
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_elements; i++) {
2677c478bd9Sstevel@tonic-gate 		assert(element[i] != NULL);
26894bc7577Sps154918 		/* Prevent incompatible duplicate defn. from FRUID Registry. */
26994bc7577Sps154918 		if ((strcmp("Location", element[i])) == 0) continue;
2707c478bd9Sstevel@tonic-gate 		if ((def = fru_reg_lookup_def_by_name(element[i])) == NULL) {
2717c478bd9Sstevel@tonic-gate 			error(gettext("Error looking up registry "
2727c478bd9Sstevel@tonic-gate 					"definition for \"%s\"\n"),
2737c478bd9Sstevel@tonic-gate 				element[i]);
2747c478bd9Sstevel@tonic-gate 			return (1);
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		if (def->tagType != FRU_X) tagged[i] = 1;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		if (def->dataType == FDTYPE_Record) {
2807c478bd9Sstevel@tonic-gate 			if (def->iterationType == FRU_NOT_ITERATED)
2817c478bd9Sstevel@tonic-gate 				output("<!ELEMENT %s (%s", element[i],
2827c478bd9Sstevel@tonic-gate 				    def->enumTable[0].text);
2837c478bd9Sstevel@tonic-gate 			else
2847c478bd9Sstevel@tonic-gate 				output("<!ELEMENT %s (Index_%s*)>\n"
2857c478bd9Sstevel@tonic-gate 				    "<!ATTLIST Index_%s>\n"
2867c478bd9Sstevel@tonic-gate 				    "<!ELEMENT Index_%s (%s",
2877c478bd9Sstevel@tonic-gate 				    element[i], element[i], element[i],
2887c478bd9Sstevel@tonic-gate 				    element[i], def->enumTable[0].text);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 			for (j = 1; j < def->enumCount; j++)
2917c478bd9Sstevel@tonic-gate 				output(",\n\t%s", def->enumTable[j].text);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 			output(")>\n");
2947c478bd9Sstevel@tonic-gate 		} else if (def->iterationType == FRU_NOT_ITERATED) {
2957c478bd9Sstevel@tonic-gate 			output("<!ELEMENT %s EMPTY>\n"
2967c478bd9Sstevel@tonic-gate 			    "<!ATTLIST %s value CDATA #REQUIRED>\n",
2977c478bd9Sstevel@tonic-gate 			    element[i], element[i]);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 			if (def->dataType == FDTYPE_Enumeration) {
3007c478bd9Sstevel@tonic-gate 				output("<!-- %s valid enumeration values\n");
3017c478bd9Sstevel@tonic-gate 				for (j = 0; j < def->enumCount; j++) {
3027c478bd9Sstevel@tonic-gate 					output("\t\"");
3037c478bd9Sstevel@tonic-gate 					xputs(def->enumTable[j].text);
3047c478bd9Sstevel@tonic-gate 					output("\"\n");
3057c478bd9Sstevel@tonic-gate 				}
3067c478bd9Sstevel@tonic-gate 				output("-->\n");
3077c478bd9Sstevel@tonic-gate 			}
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 		else
3107c478bd9Sstevel@tonic-gate 			output("<!ELEMENT %s (Index*)>\n", element[i]);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 		output("\n");
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* Provide for returning the tag for an "unknown" element */
3167c478bd9Sstevel@tonic-gate 	output("<!ATTLIST UNKNOWN tag CDATA \"UNKNOWN\">\n\n");
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * List all data elements as possible members of "Segment"
3217c478bd9Sstevel@tonic-gate 	 */
3227c478bd9Sstevel@tonic-gate 	output("<!ELEMENT Segment ((UNKNOWN");
3237c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_elements; i++) {
3247c478bd9Sstevel@tonic-gate 		if (tagged[i]) output("\n\t| %s", element[i]);
3257c478bd9Sstevel@tonic-gate 		free(element[i]);
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 	output(")*)>\n");
3287c478bd9Sstevel@tonic-gate 	free(element);
3297c478bd9Sstevel@tonic-gate 	free(tagged);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	return (0);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate  * Safely pretty-print the value of a field
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate static void
3387c478bd9Sstevel@tonic-gate print_field(const uint8_t *field, const fru_regdef_t *def)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	char		*errmsg = NULL, timestring[TIMESTRINGLEN];
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	int		i;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	uint64_t	value;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	time_t		timefield;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	switch (def->dataType) {
3507c478bd9Sstevel@tonic-gate 	case FDTYPE_Binary:
3517c478bd9Sstevel@tonic-gate 		assert(def->payloadLen <= sizeof (value));
3527c478bd9Sstevel@tonic-gate 		switch (def->dispType) {
3537c478bd9Sstevel@tonic-gate 		case FDISP_Binary:
3547c478bd9Sstevel@tonic-gate 			for (i = 0; i < def->payloadLen; i++)
3557c478bd9Sstevel@tonic-gate 				output("%c%c%c%c%c%c%c%c",
3567c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x80) ? '1' : '0'),
3577c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x40) ? '1' : '0'),
3587c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x20) ? '1' : '0'),
3597c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x10) ? '1' : '0'),
3607c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x08) ? '1' : '0'),
3617c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x04) ? '1' : '0'),
3627c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x02) ? '1' : '0'),
3637c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x01) ? '1' : '0'));
3647c478bd9Sstevel@tonic-gate 			return;
3657c478bd9Sstevel@tonic-gate 		case FDISP_Octal:
3667c478bd9Sstevel@tonic-gate 		case FDISP_Decimal:
3677c478bd9Sstevel@tonic-gate 			value = 0;
3687c478bd9Sstevel@tonic-gate 			(void) memcpy((((uint8_t *)&value) +
3697c478bd9Sstevel@tonic-gate 					sizeof (value) - def->payloadLen),
3707c478bd9Sstevel@tonic-gate 					field, def->payloadLen);
37194bc7577Sps154918 			if ((value != 0) &&
37294bc7577Sps154918 				((strcmp(def->name, "Lowest") == 0) ||
37394bc7577Sps154918 				(strcmp(def->name, "Highest") == 0) ||
37494bc7577Sps154918 				(strcmp(def->name, "Latest") == 0)))
375*1e3549a6Sps154918 				output((def->dispType == FDISP_Octal) ?
376*1e3549a6Sps154918 				"%llo" : "%lld (%lld degrees C)",
377*1e3549a6Sps154918 				value, (value - TEMPERATURE_OFFSET));
378*1e3549a6Sps154918 			else
3797c478bd9Sstevel@tonic-gate 				output((def->dispType == FDISP_Octal) ?
3807c478bd9Sstevel@tonic-gate 				"%llo" : "%lld", value);
3817c478bd9Sstevel@tonic-gate 			return;
3827c478bd9Sstevel@tonic-gate 		case FDISP_Time:
3837c478bd9Sstevel@tonic-gate 			if (def->payloadLen > sizeof (timefield)) {
3847c478bd9Sstevel@tonic-gate 				errmsg = "time value too large for formatting";
3857c478bd9Sstevel@tonic-gate 				break;
3867c478bd9Sstevel@tonic-gate 			}
3877c478bd9Sstevel@tonic-gate 			(void) memcpy(&timefield, field, sizeof (timefield));
3887c478bd9Sstevel@tonic-gate 			if (strftime(timestring, sizeof (timestring), "%C",
3897c478bd9Sstevel@tonic-gate 					localtime(&timefield)) == 0) {
3907c478bd9Sstevel@tonic-gate 				errmsg = "formatted time would overflow buffer";
3917c478bd9Sstevel@tonic-gate 				break;
3927c478bd9Sstevel@tonic-gate 			}
3937c478bd9Sstevel@tonic-gate 			safeputs(timestring);
3947c478bd9Sstevel@tonic-gate 			return;
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 		break;
3977c478bd9Sstevel@tonic-gate 	case FDTYPE_ASCII:
3987c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->payloadLen && field[i]; i++)
3997c478bd9Sstevel@tonic-gate 			safeputchar(field[i]);
4007c478bd9Sstevel@tonic-gate 		return;
4017c478bd9Sstevel@tonic-gate 	case FDTYPE_Enumeration:
4027c478bd9Sstevel@tonic-gate 		value = 0;
4037c478bd9Sstevel@tonic-gate 		(void) memcpy((((uint8_t *)&value) + sizeof (value)
4047c478bd9Sstevel@tonic-gate 					- def->payloadLen),
4057c478bd9Sstevel@tonic-gate 					field, def->payloadLen);
4067c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->enumCount; i++)
4077c478bd9Sstevel@tonic-gate 			if (def->enumTable[i].value == value) {
4087c478bd9Sstevel@tonic-gate 				safeputs(def->enumTable[i].text);
4097c478bd9Sstevel@tonic-gate 				return;
4107c478bd9Sstevel@tonic-gate 			}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 		errmsg = "unrecognized value";
4137c478bd9Sstevel@tonic-gate 		break;
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/* If nothing matched above, print the field in hex */
4177c478bd9Sstevel@tonic-gate 	for (i = 0; i < def->payloadLen; i++)
4187c478bd9Sstevel@tonic-gate 		output("%2.2X", field[i]);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	/* Safely print any error message associated with the field */
4217c478bd9Sstevel@tonic-gate 	if (errmsg) {
4227c478bd9Sstevel@tonic-gate 		output(" (");
4237c478bd9Sstevel@tonic-gate 		safeputs(errmsg);
4247c478bd9Sstevel@tonic-gate 		output(")\n");
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate /*
4297c478bd9Sstevel@tonic-gate  * Recursively print the contents of a data element
4307c478bd9Sstevel@tonic-gate  */
4317c478bd9Sstevel@tonic-gate static void
4327c478bd9Sstevel@tonic-gate print_element(const uint8_t *data, const fru_regdef_t *def,
4337c478bd9Sstevel@tonic-gate     const char *parent_path, int indent)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	char	*path;
4367c478bd9Sstevel@tonic-gate 	size_t	len;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	int	bytes = 0, i;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	indent = (xml) ? (indent + INDENT) : (2*INDENT);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/*
4447c478bd9Sstevel@tonic-gate 	 * Construct the path, or, for XML, the name, for the current
4457c478bd9Sstevel@tonic-gate 	 * data element
4467c478bd9Sstevel@tonic-gate 	 */
4477c478bd9Sstevel@tonic-gate 	if ((def->iterationCount == 0) &&
4487c478bd9Sstevel@tonic-gate 	    (def->iterationType != FRU_NOT_ITERATED)) {
4497c478bd9Sstevel@tonic-gate 		if (xml) {
4507c478bd9Sstevel@tonic-gate 			if (def->dataType == FDTYPE_Record) {
4517c478bd9Sstevel@tonic-gate 				len = strlen("Index_") + strlen(def->name) + 1;
4527c478bd9Sstevel@tonic-gate 				path = alloca(len);
4537c478bd9Sstevel@tonic-gate 				(void) snprintf(path, len,
4547c478bd9Sstevel@tonic-gate 				    "Index_%s", def->name);
4557c478bd9Sstevel@tonic-gate 			}
4567c478bd9Sstevel@tonic-gate 			else
4577c478bd9Sstevel@tonic-gate 				path = "Index";
4587c478bd9Sstevel@tonic-gate 		}
4597c478bd9Sstevel@tonic-gate 		else
4607c478bd9Sstevel@tonic-gate 			path = (char *)parent_path;
4617c478bd9Sstevel@tonic-gate 	} else {
4627c478bd9Sstevel@tonic-gate 		if (xml)
4637c478bd9Sstevel@tonic-gate 			path = (char *)def->name;
4647c478bd9Sstevel@tonic-gate 		else {
4657c478bd9Sstevel@tonic-gate 			len = strlen(parent_path) + sizeof ("/") +
4667c478bd9Sstevel@tonic-gate 			    strlen(def->name) +
4677c478bd9Sstevel@tonic-gate 			    (def->iterationCount ? sizeof ("[255]") : 0);
4687c478bd9Sstevel@tonic-gate 			path = alloca(len);
4697c478bd9Sstevel@tonic-gate 			bytes = snprintf(path, len,
4707c478bd9Sstevel@tonic-gate 			    "%s/%s", parent_path, def->name);
4717c478bd9Sstevel@tonic-gate 		}
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	/*
4757c478bd9Sstevel@tonic-gate 	 * Handle the various categories of data elements:  iteration,
4767c478bd9Sstevel@tonic-gate 	 * record, and field
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	if (def->iterationCount) {
4797c478bd9Sstevel@tonic-gate 		int		iterlen = (def->payloadLen - NUM_ITER_BYTES)/
4807c478bd9Sstevel@tonic-gate 						def->iterationCount,
4817c478bd9Sstevel@tonic-gate 				n, valid = 1;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		uint8_t		head, num;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 		fru_regdef_t	newdef;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		/*
4897c478bd9Sstevel@tonic-gate 		 * Make a new element definition to describe the components
4907c478bd9Sstevel@tonic-gate 		 * of the iteration
4917c478bd9Sstevel@tonic-gate 		 */
4927c478bd9Sstevel@tonic-gate 		(void) memcpy(&newdef, def, sizeof (newdef));
4937c478bd9Sstevel@tonic-gate 		newdef.iterationCount = 0;
4947c478bd9Sstevel@tonic-gate 		newdef.payloadLen = iterlen;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		/*
4977c478bd9Sstevel@tonic-gate 		 * Validate the contents of the iteration control bytes
4987c478bd9Sstevel@tonic-gate 		 */
4997c478bd9Sstevel@tonic-gate 		if (data[HEAD_ITER] >= def->iterationCount) {
5007c478bd9Sstevel@tonic-gate 			valid = 0;
5017c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration head:  %d "
5027c478bd9Sstevel@tonic-gate 			    "(should be less than %d)\n"),
5037c478bd9Sstevel@tonic-gate 			    path, data[HEAD_ITER], def->iterationCount);
5047c478bd9Sstevel@tonic-gate 		}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 		if (data[NUM_ITER] > def->iterationCount) {
5077c478bd9Sstevel@tonic-gate 			valid = 0;
5087c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration count:  %d "
5097c478bd9Sstevel@tonic-gate 			    "(should not be greater than %d)\n"),
5107c478bd9Sstevel@tonic-gate 			    path, data[NUM_ITER], def->iterationCount);
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 		if (data[MAX_ITER] != def->iterationCount) {
5147c478bd9Sstevel@tonic-gate 			valid = 0;
5157c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration maximum:  %d "
5167c478bd9Sstevel@tonic-gate 			    "(should equal %d)\n"),
5177c478bd9Sstevel@tonic-gate 			    path, data[MAX_ITER], def->iterationCount);
5187c478bd9Sstevel@tonic-gate 		}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		if (valid) {
5217c478bd9Sstevel@tonic-gate 			head = data[HEAD_ITER];
5227c478bd9Sstevel@tonic-gate 			num  = data[NUM_ITER];
5237c478bd9Sstevel@tonic-gate 		} else {
5247c478bd9Sstevel@tonic-gate 			head = 0;
5257c478bd9Sstevel@tonic-gate 			num  = def->iterationCount;
5267c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Showing all iterations\n"), path);
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 		if (xml)
5307c478bd9Sstevel@tonic-gate 			output("%*s<%s>\n", indent, "", path);
5317c478bd9Sstevel@tonic-gate 		else
5327c478bd9Sstevel@tonic-gate 			output("%*s%s (%d iterations)\n", indent, "", path,
5337c478bd9Sstevel@tonic-gate 				num);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		/*
5367c478bd9Sstevel@tonic-gate 		 * Print each component of the iteration
5377c478bd9Sstevel@tonic-gate 		 */
5387c478bd9Sstevel@tonic-gate 		for (i = head, n = 0, data += 4;
5397c478bd9Sstevel@tonic-gate 				n < num;
5407c478bd9Sstevel@tonic-gate 				i = ((i + 1) % def->iterationCount), n++) {
5417c478bd9Sstevel@tonic-gate 			if (!xml) (void) sprintf((path + bytes), "[%d]", n);
5427c478bd9Sstevel@tonic-gate 			print_element((data + i*iterlen), &newdef, path,
5437c478bd9Sstevel@tonic-gate 					indent);
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 		if (xml) output("%*s</%s>\n", indent, "", path);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	} else if (def->dataType == FDTYPE_Record) {
5497c478bd9Sstevel@tonic-gate 		const fru_regdef_t  *component;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		if (xml)
5527c478bd9Sstevel@tonic-gate 			output("%*s<%s>\n", indent, "", path);
5537c478bd9Sstevel@tonic-gate 		else
5547c478bd9Sstevel@tonic-gate 			output("%*s%s\n", indent, "", path);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		/*
5577c478bd9Sstevel@tonic-gate 		 * Print each component of the record
5587c478bd9Sstevel@tonic-gate 		 */
5597c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->enumCount;
5607c478bd9Sstevel@tonic-gate 				i++, data += component->payloadLen) {
5617c478bd9Sstevel@tonic-gate 			component = fru_reg_lookup_def_by_name(
5627c478bd9Sstevel@tonic-gate 				def->enumTable[i].text);
5637c478bd9Sstevel@tonic-gate 			assert(component != NULL);
5647c478bd9Sstevel@tonic-gate 			print_element(data, component, path, indent);
5657c478bd9Sstevel@tonic-gate 		}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		if (xml) output("%*s</%s>\n", indent, "", path);
5687c478bd9Sstevel@tonic-gate 	} else if (xml) {
5697c478bd9Sstevel@tonic-gate 		/*
5707c478bd9Sstevel@tonic-gate 		 * Base case:  print the field formatted for XML
5717c478bd9Sstevel@tonic-gate 		 */
5727c478bd9Sstevel@tonic-gate 		char  *format = ((def == &unknown)
5737c478bd9Sstevel@tonic-gate 		    ? "%*s<UNKNOWN tag=\"%s\" value=\""
5747c478bd9Sstevel@tonic-gate 		    : "%*s<%s value=\"");
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		output(format, indent, "", path);
5777c478bd9Sstevel@tonic-gate 		print_field(data, def);
5787c478bd9Sstevel@tonic-gate 		/*CSTYLED*/
5797c478bd9Sstevel@tonic-gate 		output("\"/>\n");	/* \" confuses cstyle */
5807c478bd9Sstevel@tonic-gate 	} else {
5817c478bd9Sstevel@tonic-gate 		/*
5827c478bd9Sstevel@tonic-gate 		 * Base case:  print the field
5837c478bd9Sstevel@tonic-gate 		 */
5847c478bd9Sstevel@tonic-gate 		output("%*s%s: ", indent, "", path);
5857c478bd9Sstevel@tonic-gate 		print_field(data, def);
5867c478bd9Sstevel@tonic-gate 		output("\n");
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate  * Print the contents of a packet (i.e., a tagged data element)
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate /* ARGSUSED */
5947c478bd9Sstevel@tonic-gate static int
5957c478bd9Sstevel@tonic-gate print_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	int			tag_type = get_tag_type(tag);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	size_t			payload_length = 0;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	const fru_regdef_t	*def;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * Build a definition for unrecognized tags (e.g., not in libfrureg)
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	if ((tag_type == -1) ||
6087c478bd9Sstevel@tonic-gate 	    ((payload_length = get_payload_length(tag)) != length)) {
6097c478bd9Sstevel@tonic-gate 		def = &unknown;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		unknown.tagType    = -1;
6127c478bd9Sstevel@tonic-gate 		unknown.tagDense   = -1;
6137c478bd9Sstevel@tonic-gate 		unknown.payloadLen = length;
6147c478bd9Sstevel@tonic-gate 		unknown.dataLength = unknown.payloadLen;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 		if (tag_type == -1)
6177c478bd9Sstevel@tonic-gate 			(void) snprintf(tagname, sizeof (tagname), "INVALID");
6187c478bd9Sstevel@tonic-gate 		else
6197c478bd9Sstevel@tonic-gate 			(void) snprintf(tagname, sizeof (tagname),
6207c478bd9Sstevel@tonic-gate 			    "%s_%u_%u_%u", get_tagtype_str(tag_type),
6217c478bd9Sstevel@tonic-gate 			    get_tag_dense(tag), payload_length, length);
6227c478bd9Sstevel@tonic-gate 	} else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) {
6237c478bd9Sstevel@tonic-gate 		def = &unknown;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		unknown.tagType    = tag_type;
6267c478bd9Sstevel@tonic-gate 		unknown.tagDense   = get_tag_dense(tag);
6277c478bd9Sstevel@tonic-gate 		unknown.payloadLen = payload_length;
6287c478bd9Sstevel@tonic-gate 		unknown.dataLength = unknown.payloadLen;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 		(void) snprintf(tagname, sizeof (tagname), "%s_%u_%u",
6317c478bd9Sstevel@tonic-gate 		    get_tagtype_str(unknown.tagType),
6327c478bd9Sstevel@tonic-gate 		    unknown.tagDense, payload_length);
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * Print the defined element
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	print_element(payload, def, "", INDENT);
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate  * Print a segment's name and the contents of each data element in the segment
6467c478bd9Sstevel@tonic-gate  */
6477c478bd9Sstevel@tonic-gate static int
6487c478bd9Sstevel@tonic-gate print_packets_in_segment(fru_seghdl_t segment, void *args)
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate 	char	*name;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	int	status;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	if ((status = fru_get_segment_name(segment, &name)) != FRU_SUCCESS) {
6567c478bd9Sstevel@tonic-gate 		saved_status = status;
6577c478bd9Sstevel@tonic-gate 		name = "";
6587c478bd9Sstevel@tonic-gate 		error(gettext("Error getting segment name:  %s\n"),
6597c478bd9Sstevel@tonic-gate 		    fru_strerror(status));
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (xml)
6647c478bd9Sstevel@tonic-gate 		output("%*s<Segment name=\"%s\">\n", INDENT, "", name);
6657c478bd9Sstevel@tonic-gate 	else
6667c478bd9Sstevel@tonic-gate 		output("%*sSEGMENT: %s\n", INDENT, "", name);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	/* Iterate over the packets in the segment, printing the contents */
6697c478bd9Sstevel@tonic-gate 	if ((status = fru_for_each_packet(segment, print_packet, args))
6707c478bd9Sstevel@tonic-gate 	    != FRU_SUCCESS) {
6717c478bd9Sstevel@tonic-gate 		saved_status = status;
6727c478bd9Sstevel@tonic-gate 		error(gettext("Error processing data in segment \"%s\":  %s\n"),
6737c478bd9Sstevel@tonic-gate 			name, fru_strerror(status));
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	if (xml) output("%*s</Segment>\n", INDENT, "");
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	free(name);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate /* ARGSUSED */
6847c478bd9Sstevel@tonic-gate static void
6857c478bd9Sstevel@tonic-gate print_node_path(fru_node_t fru_type, const char *path, const char *name,
6867c478bd9Sstevel@tonic-gate     end_node_fp_t *end_node, void **end_args)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	output("%s%s\n", path,
6897c478bd9Sstevel@tonic-gate 	    ((fru_type == FRU_NODE_CONTAINER) ? " (container)"
6907c478bd9Sstevel@tonic-gate 		: ((fru_type == FRU_NODE_FRU) ? " (fru)" : "")));
6917c478bd9Sstevel@tonic-gate }
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate /*
6947c478bd9Sstevel@tonic-gate  * Close the XML element for a "location" node
6957c478bd9Sstevel@tonic-gate  */
6967c478bd9Sstevel@tonic-gate /* ARGSUSED */
6977c478bd9Sstevel@tonic-gate static void
6987c478bd9Sstevel@tonic-gate end_location_xml(fru_nodehdl_t node, const char *path, const char *name,
6997c478bd9Sstevel@tonic-gate     void *args)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate 	assert(args != NULL);
7027c478bd9Sstevel@tonic-gate 	output("</Location> <!-- %s -->\n", args);
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate /*
7067c478bd9Sstevel@tonic-gate  * Close the XML element for a "fru" node
7077c478bd9Sstevel@tonic-gate  */
7087c478bd9Sstevel@tonic-gate /* ARGSUSED */
7097c478bd9Sstevel@tonic-gate static void
7107c478bd9Sstevel@tonic-gate end_fru_xml(fru_nodehdl_t node, const char *path, const char *name, void *args)
7117c478bd9Sstevel@tonic-gate {
7127c478bd9Sstevel@tonic-gate 	assert(args != NULL);
7137c478bd9Sstevel@tonic-gate 	output("</Fru> <!-- %s -->\n", args);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate /*
7177c478bd9Sstevel@tonic-gate  * Close the XML element for a "container" node
7187c478bd9Sstevel@tonic-gate  */
7197c478bd9Sstevel@tonic-gate /* ARGSUSED */
7207c478bd9Sstevel@tonic-gate static void
7217c478bd9Sstevel@tonic-gate end_container_xml(fru_nodehdl_t node, const char *path, const char *name,
7227c478bd9Sstevel@tonic-gate     void *args)
7237c478bd9Sstevel@tonic-gate {
7247c478bd9Sstevel@tonic-gate 	assert(args != NULL);
7257c478bd9Sstevel@tonic-gate 	output("</Container> <!-- %s -->\n", args);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * Introduce a node in XML and set the appropriate node-closing function
7307c478bd9Sstevel@tonic-gate  */
7317c478bd9Sstevel@tonic-gate /* ARGSUSED */
7327c478bd9Sstevel@tonic-gate static void
7337c478bd9Sstevel@tonic-gate print_node_xml(fru_node_t fru_type, const char *path, const char *name,
7347c478bd9Sstevel@tonic-gate     end_node_fp_t *end_node, void **end_args)
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate 	switch (fru_type) {
7377c478bd9Sstevel@tonic-gate 	case FRU_NODE_FRU:
7387c478bd9Sstevel@tonic-gate 		output("<Fru name=\"%s\">\n", name);
7397c478bd9Sstevel@tonic-gate 		*end_node = end_fru_xml;
7407c478bd9Sstevel@tonic-gate 		break;
7417c478bd9Sstevel@tonic-gate 	case FRU_NODE_CONTAINER:
7427c478bd9Sstevel@tonic-gate 		output("<Container name=\"%s\">\n", name);
7437c478bd9Sstevel@tonic-gate 		*end_node = end_container_xml;
7447c478bd9Sstevel@tonic-gate 		break;
7457c478bd9Sstevel@tonic-gate 	default:
7467c478bd9Sstevel@tonic-gate 		output("<Location name=\"%s\">\n", name);
7477c478bd9Sstevel@tonic-gate 		*end_node = end_location_xml;
7487c478bd9Sstevel@tonic-gate 		break;
7497c478bd9Sstevel@tonic-gate 	}
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	*end_args = (void *) name;
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate  * Print node info and, where appropriate, node contents
7567c478bd9Sstevel@tonic-gate  */
7577c478bd9Sstevel@tonic-gate /* ARGSUSED */
7587c478bd9Sstevel@tonic-gate static fru_errno_t
7597c478bd9Sstevel@tonic-gate process_node(fru_nodehdl_t node, const char *path, const char *name,
7607c478bd9Sstevel@tonic-gate 		void *args, end_node_fp_t *end_node, void **end_args)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	int		status;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	fru_node_t	fru_type = FRU_NODE_UNKNOWN;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	if ((status = fru_get_node_type(node, &fru_type)) != FRU_SUCCESS) {
7687c478bd9Sstevel@tonic-gate 		saved_status = status;
7697c478bd9Sstevel@tonic-gate 		error(gettext("Error getting node type:  %s\n"),
7707c478bd9Sstevel@tonic-gate 			fru_strerror(status));
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	if (containers_only) {
7747c478bd9Sstevel@tonic-gate 		if (fru_type != FRU_NODE_CONTAINER)
7757c478bd9Sstevel@tonic-gate 			return (FRU_SUCCESS);
7767c478bd9Sstevel@tonic-gate 		name = path;
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	/* Introduce the node */
7807c478bd9Sstevel@tonic-gate 	assert(print_node != NULL);
7817c478bd9Sstevel@tonic-gate 	print_node(fru_type, path, name, end_node, end_args);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	if (list_only)
7847c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	/* Print the contents of each packet in each segment of a container */
7877c478bd9Sstevel@tonic-gate 	if (fru_type == FRU_NODE_CONTAINER) {
7887c478bd9Sstevel@tonic-gate 		if (xml) output("<ContainerData>\n");
7897c478bd9Sstevel@tonic-gate 		if ((status =
7907c478bd9Sstevel@tonic-gate 			fru_for_each_segment(node, print_packets_in_segment,
7917c478bd9Sstevel@tonic-gate 						NULL))
7927c478bd9Sstevel@tonic-gate 		    != FRU_SUCCESS) {
7937c478bd9Sstevel@tonic-gate 			saved_status = status;
7947c478bd9Sstevel@tonic-gate 			error(gettext("Error  processing node \"%s\":  %s\n"),
7957c478bd9Sstevel@tonic-gate 				name, fru_strerror(status));
7967c478bd9Sstevel@tonic-gate 		}
7977c478bd9Sstevel@tonic-gate 		if (xml) output("</ContainerData>\n");
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate /*
8047c478bd9Sstevel@tonic-gate  * Process the node if its path matches the search path in "args"
8057c478bd9Sstevel@tonic-gate  */
8067c478bd9Sstevel@tonic-gate /* ARGSUSED */
8077c478bd9Sstevel@tonic-gate static fru_errno_t
8087c478bd9Sstevel@tonic-gate process_matching_node(fru_nodehdl_t node, const char *path, const char *name,
8097c478bd9Sstevel@tonic-gate     void *args, end_node_fp_t *end_node, void **end_args)
8107c478bd9Sstevel@tonic-gate {
8117c478bd9Sstevel@tonic-gate 	int  status;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	if (!fru_pathmatch(path, args))
8157c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	status = process_node(node, path, path, args, end_node, end_args);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	return ((status == FRU_SUCCESS) ? FRU_WALK_TERMINATE : status);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate  * Write the trailer required for well-formed DTD-compliant XML
8247c478bd9Sstevel@tonic-gate  */
8257c478bd9Sstevel@tonic-gate static void
8267c478bd9Sstevel@tonic-gate terminate_xml()
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	errno = 0;
8297c478bd9Sstevel@tonic-gate 	if (ftell(errlog) > 0) {
8307c478bd9Sstevel@tonic-gate 		char  c;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		output("<ErrorLog>\n");
8337c478bd9Sstevel@tonic-gate 		rewind(errlog);
8347c478bd9Sstevel@tonic-gate 		if (!errno)
8357c478bd9Sstevel@tonic-gate 			while ((c = getc(errlog)) != EOF)
8367c478bd9Sstevel@tonic-gate 				xputchar(c);
8377c478bd9Sstevel@tonic-gate 		output("</ErrorLog>\n");
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	if (errno) {
8417c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
8427c478bd9Sstevel@tonic-gate 		errlog = NULL;
8437c478bd9Sstevel@tonic-gate 		error(gettext("Error copying error messages to \"ErrorLog\""),
8447c478bd9Sstevel@tonic-gate 		    strerror(errno));
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	output("</FRUID_XML_Tree>\n");
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate  * Print available FRU ID information
8527c478bd9Sstevel@tonic-gate  */
8537c478bd9Sstevel@tonic-gate int
8547c478bd9Sstevel@tonic-gate prtfru(const char *searchpath, int containers_only_flag, int list_only_flag,
8557c478bd9Sstevel@tonic-gate 	int xml_flag)
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	fru_errno_t    status;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	fru_nodehdl_t  frutree = 0;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	/* Copy parameter flags to global flags */
8637c478bd9Sstevel@tonic-gate 	containers_only	= containers_only_flag;
8647c478bd9Sstevel@tonic-gate 	list_only	= list_only_flag;
8657c478bd9Sstevel@tonic-gate 	xml		= xml_flag;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/* Help arrange for correct, efficient interleaving of output */
8697c478bd9Sstevel@tonic-gate 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	/* Initialize for XML--or not */
8737c478bd9Sstevel@tonic-gate 	if (xml) {
8747c478bd9Sstevel@tonic-gate 		safeputchar = xputchar;
8757c478bd9Sstevel@tonic-gate 		safeputs    = xputs;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 		print_node  = print_node_xml;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		if ((errlog = tmpfile()) == NULL) {
8807c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
8817c478bd9Sstevel@tonic-gate 			    "Error creating error log file:  %s\n",
8827c478bd9Sstevel@tonic-gate 			    strerror(errno));
8837c478bd9Sstevel@tonic-gate 			return (1);
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 		/* Output the XML preamble */
8877c478bd9Sstevel@tonic-gate 		output("<?xml version=\"1.0\" ?>\n"
8887c478bd9Sstevel@tonic-gate 		    "<!--\n"
8897c478bd9Sstevel@tonic-gate 		    " Copyright 2000-2002 Sun Microsystems, Inc.  "
8907c478bd9Sstevel@tonic-gate 		    "All rights reserved.\n"
8917c478bd9Sstevel@tonic-gate 		    " Use is subject to license terms.\n"
8927c478bd9Sstevel@tonic-gate 		    "-->\n\n"
8937c478bd9Sstevel@tonic-gate 		    "<!DOCTYPE FRUID_XML_Tree SYSTEM \"prtfrureg.dtd\">\n\n"
8947c478bd9Sstevel@tonic-gate 		    "<FRUID_XML_Tree>\n");
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		/* Arrange to always properly terminate XML */
8977c478bd9Sstevel@tonic-gate 		if (atexit(terminate_xml))
8987c478bd9Sstevel@tonic-gate 			error(gettext("Warning:  XML will not be terminated:  "
8997c478bd9Sstevel@tonic-gate 					"%s\n"), strerror(errno));
9007c478bd9Sstevel@tonic-gate 	} else
9017c478bd9Sstevel@tonic-gate 		print_node = print_node_path;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	/* Get the root node */
9057c478bd9Sstevel@tonic-gate 	if ((status = fru_get_root(&frutree)) == FRU_NODENOTFOUND) {
9067c478bd9Sstevel@tonic-gate 		error(gettext("This system does not provide FRU ID data\n"));
9077c478bd9Sstevel@tonic-gate 		return (1);
9087c478bd9Sstevel@tonic-gate 	} else if (status != FRU_SUCCESS) {
9097c478bd9Sstevel@tonic-gate 		error(gettext("Unable to access FRU ID data:  %s\n"),
9107c478bd9Sstevel@tonic-gate 			fru_strerror(status));
9117c478bd9Sstevel@tonic-gate 		return (1);
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/* Process the tree */
9157c478bd9Sstevel@tonic-gate 	if (searchpath == NULL) {
9167c478bd9Sstevel@tonic-gate 		status = fru_walk_tree(frutree, "", process_node, NULL);
9177c478bd9Sstevel@tonic-gate 	} else {
9187c478bd9Sstevel@tonic-gate 		status = fru_walk_tree(frutree, "", process_matching_node,
9197c478bd9Sstevel@tonic-gate 					(void *)searchpath);
9207c478bd9Sstevel@tonic-gate 		if (status == FRU_WALK_TERMINATE) {
9217c478bd9Sstevel@tonic-gate 			status = FRU_SUCCESS;
9227c478bd9Sstevel@tonic-gate 		} else if (status == FRU_SUCCESS) {
9237c478bd9Sstevel@tonic-gate 			error(gettext("\"%s\" not found\n"), searchpath);
9247c478bd9Sstevel@tonic-gate 			return (1);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	if (status != FRU_SUCCESS)
9297c478bd9Sstevel@tonic-gate 		error(gettext("Error processing FRU tree:  %s\n"),
9307c478bd9Sstevel@tonic-gate 			fru_strerror(status));
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	return (((status == FRU_SUCCESS) && (saved_status == 0)) ? 0 : 1);
9337c478bd9Sstevel@tonic-gate }
934