xref: /titanic_53/usr/src/cmd/prtfru/prtfru.c (revision 5bc0fc0e85213e08d6b0388ae0690b7377d409a2)
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 /*
22f3af4981Sdt207653  * Copyright 2007 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>
36f3af4981Sdt207653 #include <ctype.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include "fru_tag.h"
397c478bd9Sstevel@tonic-gate #include "libfrup.h"
407c478bd9Sstevel@tonic-gate #include "libfrureg.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	NUM_ITER_BYTES 4
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #define	HEAD_ITER 0
467c478bd9Sstevel@tonic-gate #define	TAIL_ITER 1	/*  not used  */
477c478bd9Sstevel@tonic-gate #define	NUM_ITER  2
487c478bd9Sstevel@tonic-gate #define	MAX_ITER  3
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #define	INDENT 3
517c478bd9Sstevel@tonic-gate #define	TIMESTRINGLEN 128
5294bc7577Sps154918 #define	TEMPERATURE_OFFSET 73
53*5bc0fc0eSdt207653 #define	MIN_VERSION 17
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static void	(*print_node)(fru_node_t fru_type, const char *path,
567c478bd9Sstevel@tonic-gate 				const char *name, end_node_fp_t *end_node,
577c478bd9Sstevel@tonic-gate 				void **end_args);
587c478bd9Sstevel@tonic-gate 
59f3af4981Sdt207653 static void	print_element(const uint8_t *data, const fru_regdef_t *def,
60f3af4981Sdt207653 const char *parent_path, int indent);
61f3af4981Sdt207653 
627c478bd9Sstevel@tonic-gate static char	tagname[sizeof ("?_0123456789_0123456789_0123456789")];
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static int	containers_only = 0, list_only = 0, saved_status = 0, xml = 0;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static FILE	*errlog;
677c478bd9Sstevel@tonic-gate 
68f3af4981Sdt207653 int iterglobal = 0;
69f3af4981Sdt207653 int FMAmessageR = -1;
7046a7ef8aSdt207653 int Fault_Install_DataR_flag = 0;
7146a7ef8aSdt207653 int Power_On_DataR_flag = 0;
72*5bc0fc0eSdt207653 int spd_memtype = 0;
73*5bc0fc0eSdt207653 int spd_revision = 0;
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * Definition for data elements found in devices but not found in
767c478bd9Sstevel@tonic-gate  * the system's version of libfrureg
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate static fru_regdef_t  unknown = {
797c478bd9Sstevel@tonic-gate 	REGDEF_VERSION,
807c478bd9Sstevel@tonic-gate 	tagname,
817c478bd9Sstevel@tonic-gate 	-1,
827c478bd9Sstevel@tonic-gate 	-1,
837c478bd9Sstevel@tonic-gate 	-1,
847c478bd9Sstevel@tonic-gate 	-1,
857c478bd9Sstevel@tonic-gate 	FDTYPE_ByteArray,
867c478bd9Sstevel@tonic-gate 	FDISP_Hex,
877c478bd9Sstevel@tonic-gate 	FRU_WHICH_UNDEFINED,
887c478bd9Sstevel@tonic-gate 	FRU_WHICH_UNDEFINED,
897c478bd9Sstevel@tonic-gate 	0,
907c478bd9Sstevel@tonic-gate 	NULL,
917c478bd9Sstevel@tonic-gate 	0,
927c478bd9Sstevel@tonic-gate 	FRU_NOT_ITERATED,
937c478bd9Sstevel@tonic-gate 	NULL
947c478bd9Sstevel@tonic-gate };
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * Write message to standard error and possibly the error log buffer
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate static void
1017c478bd9Sstevel@tonic-gate error(const char *format, ...)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	va_list	args;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/* make relevant output appear before error message */
1077c478bd9Sstevel@tonic-gate 	if (fflush(stdout) == EOF) {
1087c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Error flushing output:  %s\n",
1097c478bd9Sstevel@tonic-gate 		    strerror(errno));
1107c478bd9Sstevel@tonic-gate 		exit(1);
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	va_start(args, format);
1147c478bd9Sstevel@tonic-gate 	if (vfprintf(stderr, format, args) < 0) exit(1);
1157c478bd9Sstevel@tonic-gate 	if (errlog && (vfprintf(errlog, format, args) < 0)) exit(1);
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * Write message to standard output
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate static void
1227c478bd9Sstevel@tonic-gate output(const char *format, ...)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	va_list   args;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	va_start(args, format);
1287c478bd9Sstevel@tonic-gate 	if (vfprintf(stdout, format, args) < 0) {
1297c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1307c478bd9Sstevel@tonic-gate 		    strerror(errno));
1317c478bd9Sstevel@tonic-gate 		exit(1);
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate  * Safe wrapper for putchar()
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate static void
1397c478bd9Sstevel@tonic-gate voidputchar(int c)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	if (putchar(c) == EOF) {
1427c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1437c478bd9Sstevel@tonic-gate 		    strerror(errno));
1447c478bd9Sstevel@tonic-gate 		exit(1);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static void  (*safeputchar)(int c) = voidputchar;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate  * Safe wrapper for puts()
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate static void
1547c478bd9Sstevel@tonic-gate voidputs(const char *s)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	if (fputs(s, stdout) == EOF) {
1577c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1587c478bd9Sstevel@tonic-gate 		    strerror(errno));
1597c478bd9Sstevel@tonic-gate 		exit(1);
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate static void  (*safeputs)(const char *s) = voidputs;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * XML-safe wrapper for putchar():  quotes XML-special characters
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate static void
1697c478bd9Sstevel@tonic-gate xputchar(int c)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	switch (c) {
1727c478bd9Sstevel@tonic-gate 	case '<':
1737c478bd9Sstevel@tonic-gate 		c = fputs("&lt;", stdout);
1747c478bd9Sstevel@tonic-gate 		break;
1757c478bd9Sstevel@tonic-gate 	case '>':
1767c478bd9Sstevel@tonic-gate 		c = fputs("&gt;", stdout);
1777c478bd9Sstevel@tonic-gate 		break;
1787c478bd9Sstevel@tonic-gate 	case '&':
1797c478bd9Sstevel@tonic-gate 		c = fputs("&amp;", stdout);
1807c478bd9Sstevel@tonic-gate 		break;
1817c478bd9Sstevel@tonic-gate 	case '"':
1827c478bd9Sstevel@tonic-gate 		c = fputs("&quot;", stdout);
1837c478bd9Sstevel@tonic-gate 		break;
1847c478bd9Sstevel@tonic-gate 	default:
1857c478bd9Sstevel@tonic-gate 		c = putchar(c);
1867c478bd9Sstevel@tonic-gate 		break;
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (c == EOF) {
1907c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
1917c478bd9Sstevel@tonic-gate 		    strerror(errno));
1927c478bd9Sstevel@tonic-gate 		exit(1);
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * XML-safe analog of puts():  quotes XML-special characters
1987c478bd9Sstevel@tonic-gate  */
1997c478bd9Sstevel@tonic-gate static void
2007c478bd9Sstevel@tonic-gate xputs(const char *s)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	char c;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	for (/* */; ((c = *s) != 0); s++)
2057c478bd9Sstevel@tonic-gate 		xputchar(c);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate  * Output the XML DTD derived from the registry provided by libfrureg
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate int
2127c478bd9Sstevel@tonic-gate output_dtd(void)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	char			**element;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	unsigned int		i, j, num_elements = 0;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	uint8_t			*tagged;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	const fru_regdef_t	*def;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (((element = fru_reg_list_entries(&num_elements)) == NULL) ||
2247c478bd9Sstevel@tonic-gate 	    (num_elements == 0)) {
2257c478bd9Sstevel@tonic-gate 		error(gettext("No FRU ID Registry elements"));
2267c478bd9Sstevel@tonic-gate 		return (1);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if ((tagged = calloc(num_elements, sizeof (*tagged))) == NULL) {
2307c478bd9Sstevel@tonic-gate 		error(gettext("Unable to get memory for tagged element list"),
2317c478bd9Sstevel@tonic-gate 		    strerror(errno));
2327c478bd9Sstevel@tonic-gate 		return (1);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * Output the DTD preamble
2377c478bd9Sstevel@tonic-gate 	 */
2387c478bd9Sstevel@tonic-gate 	output("<!ELEMENT FRUID_XML_Tree (Parameter*, "
2397c478bd9Sstevel@tonic-gate 	    "(Fru | Location | Container)*,\n"
2407c478bd9Sstevel@tonic-gate 	    "                          Parameter*, ErrorLog?, Parameter*)>\n"
2417c478bd9Sstevel@tonic-gate 	    "<!ATTLIST FRUID_XML_Tree>\n"
2427c478bd9Sstevel@tonic-gate 	    "\n"
2437c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Parameter EMPTY>\n"
2447c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter type CDATA #REQUIRED>\n"
2457c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter name CDATA #REQUIRED>\n"
2467c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter value CDATA #REQUIRED>\n"
2477c478bd9Sstevel@tonic-gate 	    "\n"
2487c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Fru (Fru | Location | Container)*>\n"
2497c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Fru name CDATA #REQUIRED>\n"
2507c478bd9Sstevel@tonic-gate 	    "\n"
2517c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Location (Fru | Location | Container)*>\n"
25294bc7577Sps154918 	    "<!ATTLIST Location\n"
25394bc7577Sps154918 	    "	name CDATA #IMPLIED\n"
25494bc7577Sps154918 	    "	value CDATA #IMPLIED\n"
25594bc7577Sps154918 	    ">\n"
2567c478bd9Sstevel@tonic-gate 	    "\n"
2577c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Container (ContainerData?, "
2587c478bd9Sstevel@tonic-gate 	    "(Fru | Location | Container)*)>\n"
2597c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Container name CDATA #REQUIRED>\n"
2607c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Container imagefile CDATA #IMPLIED>\n"
2617c478bd9Sstevel@tonic-gate 	    "\n"
2627c478bd9Sstevel@tonic-gate 	    "<!ELEMENT ContainerData (Segment*)>\n"
2637c478bd9Sstevel@tonic-gate 	    "<!ATTLIST ContainerData>\n"
2647c478bd9Sstevel@tonic-gate 	    "\n"
2657c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Segment name CDATA #REQUIRED>\n"
2667c478bd9Sstevel@tonic-gate 	    "\n"
2677c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Index EMPTY>\n"
2687c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Index value CDATA #REQUIRED>\n"
2697c478bd9Sstevel@tonic-gate 	    "\n"
2707c478bd9Sstevel@tonic-gate 	    "<!ELEMENT ErrorLog (#PCDATA)>\n"
2717c478bd9Sstevel@tonic-gate 	    "<!ATTLIST ErrorLog>\n"
2727c478bd9Sstevel@tonic-gate 	    "\n");
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	/*
2757c478bd9Sstevel@tonic-gate 	 * Output the definition for each element
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_elements; i++) {
2787c478bd9Sstevel@tonic-gate 		assert(element[i] != NULL);
27994bc7577Sps154918 		/* Prevent incompatible duplicate defn. from FRUID Registry. */
28094bc7577Sps154918 		if ((strcmp("Location", element[i])) == 0) continue;
2817c478bd9Sstevel@tonic-gate 		if ((def = fru_reg_lookup_def_by_name(element[i])) == NULL) {
2827c478bd9Sstevel@tonic-gate 			error(gettext("Error looking up registry "
2837c478bd9Sstevel@tonic-gate 			    "definition for \"%s\"\n"),
2847c478bd9Sstevel@tonic-gate 			    element[i]);
2857c478bd9Sstevel@tonic-gate 			return (1);
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		if (def->tagType != FRU_X) tagged[i] = 1;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 		if (def->dataType == FDTYPE_Record) {
2917c478bd9Sstevel@tonic-gate 			if (def->iterationType == FRU_NOT_ITERATED)
2927c478bd9Sstevel@tonic-gate 				output("<!ELEMENT %s (%s", element[i],
2937c478bd9Sstevel@tonic-gate 				    def->enumTable[0].text);
2947c478bd9Sstevel@tonic-gate 			else
2957c478bd9Sstevel@tonic-gate 				output("<!ELEMENT %s (Index_%s*)>\n"
2967c478bd9Sstevel@tonic-gate 				    "<!ATTLIST Index_%s>\n"
2977c478bd9Sstevel@tonic-gate 				    "<!ELEMENT Index_%s (%s",
2987c478bd9Sstevel@tonic-gate 				    element[i], element[i], element[i],
2997c478bd9Sstevel@tonic-gate 				    element[i], def->enumTable[0].text);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 			for (j = 1; j < def->enumCount; j++)
3027c478bd9Sstevel@tonic-gate 				output(",\n\t%s", def->enumTable[j].text);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 			output(")>\n");
3057c478bd9Sstevel@tonic-gate 		} else if (def->iterationType == FRU_NOT_ITERATED) {
3067c478bd9Sstevel@tonic-gate 			output("<!ELEMENT %s EMPTY>\n"
3077c478bd9Sstevel@tonic-gate 			    "<!ATTLIST %s value CDATA #REQUIRED>\n",
3087c478bd9Sstevel@tonic-gate 			    element[i], element[i]);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 			if (def->dataType == FDTYPE_Enumeration) {
3117c478bd9Sstevel@tonic-gate 				output("<!-- %s valid enumeration values\n");
3127c478bd9Sstevel@tonic-gate 				for (j = 0; j < def->enumCount; j++) {
3137c478bd9Sstevel@tonic-gate 					output("\t\"");
3147c478bd9Sstevel@tonic-gate 					xputs(def->enumTable[j].text);
3157c478bd9Sstevel@tonic-gate 					output("\"\n");
3167c478bd9Sstevel@tonic-gate 				}
3177c478bd9Sstevel@tonic-gate 				output("-->\n");
3187c478bd9Sstevel@tonic-gate 			}
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 		else
3217c478bd9Sstevel@tonic-gate 			output("<!ELEMENT %s (Index*)>\n", element[i]);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 		output("\n");
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/* Provide for returning the tag for an "unknown" element */
3277c478bd9Sstevel@tonic-gate 	output("<!ATTLIST UNKNOWN tag CDATA \"UNKNOWN\">\n\n");
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * List all data elements as possible members of "Segment"
3327c478bd9Sstevel@tonic-gate 	 */
3337c478bd9Sstevel@tonic-gate 	output("<!ELEMENT Segment ((UNKNOWN");
3347c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_elements; i++) {
3357c478bd9Sstevel@tonic-gate 		if (tagged[i]) output("\n\t| %s", element[i]);
3367c478bd9Sstevel@tonic-gate 		free(element[i]);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 	output(")*)>\n");
3397c478bd9Sstevel@tonic-gate 	free(element);
3407c478bd9Sstevel@tonic-gate 	free(tagged);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	return (0);
3437c478bd9Sstevel@tonic-gate }
344f3af4981Sdt207653 /*
345f3af4981Sdt207653  * Function to convert bcd to binary to correct the SPD_Manufacturer_Week
346f3af4981Sdt207653  *
347f3af4981Sdt207653  */
348f3af4981Sdt207653 static void convertbcdtobinary(int *val)
349f3af4981Sdt207653 {
350*5bc0fc0eSdt207653 	unsigned int newval = (unsigned int)*val, tmpval = 0;
351*5bc0fc0eSdt207653 	while (newval > 0) {
352*5bc0fc0eSdt207653 		tmpval = (tmpval << 4) | (newval & 0xF);
353*5bc0fc0eSdt207653 		newval >>= 4;
354*5bc0fc0eSdt207653 	}
355*5bc0fc0eSdt207653 	while (tmpval > 0) {
356*5bc0fc0eSdt207653 		newval = (newval * 10) + (tmpval & 0xF);
357*5bc0fc0eSdt207653 		tmpval >>= 4;
358f3af4981Sdt207653 	}
359f3af4981Sdt207653 	*val = newval;
360f3af4981Sdt207653 }
361f3af4981Sdt207653 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate  * Safely pretty-print the value of a field
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate static void
3677c478bd9Sstevel@tonic-gate print_field(const uint8_t *field, const fru_regdef_t *def)
3687c478bd9Sstevel@tonic-gate {
369f3af4981Sdt207653 	char		*errmsg = NULL, timestring[TIMESTRINGLEN], path[16384];
3707c478bd9Sstevel@tonic-gate 
371f3af4981Sdt207653 	int		i, valueint;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	uint64_t	value;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	time_t		timefield;
3767c478bd9Sstevel@tonic-gate 
377f3af4981Sdt207653 	struct tm	*tm;
3787c478bd9Sstevel@tonic-gate 
379f3af4981Sdt207653 	uchar_t		first_byte, data[128];
380f3af4981Sdt207653 
381f3af4981Sdt207653 	const fru_regdef_t	*new_def;
382f3af4981Sdt207653 
383f3af4981Sdt207653 	const char 	*elem_name = NULL;
384f3af4981Sdt207653 	const char	*parent_path;
3857c478bd9Sstevel@tonic-gate 	switch (def->dataType) {
3867c478bd9Sstevel@tonic-gate 	case FDTYPE_Binary:
3877c478bd9Sstevel@tonic-gate 		assert(def->payloadLen <= sizeof (value));
3887c478bd9Sstevel@tonic-gate 		switch (def->dispType) {
3897c478bd9Sstevel@tonic-gate 		case FDISP_Binary:
3907c478bd9Sstevel@tonic-gate 			for (i = 0; i < def->payloadLen; i++)
3917c478bd9Sstevel@tonic-gate 				output("%c%c%c%c%c%c%c%c",
3927c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x80) ? '1' : '0'),
3937c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x40) ? '1' : '0'),
3947c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x20) ? '1' : '0'),
3957c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x10) ? '1' : '0'),
3967c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x08) ? '1' : '0'),
3977c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x04) ? '1' : '0'),
3987c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x02) ? '1' : '0'),
3997c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x01) ? '1' : '0'));
4007c478bd9Sstevel@tonic-gate 			return;
4017c478bd9Sstevel@tonic-gate 		case FDISP_Octal:
4027c478bd9Sstevel@tonic-gate 		case FDISP_Decimal:
4037c478bd9Sstevel@tonic-gate 			value = 0;
404f3af4981Sdt207653 			valueint = 0;
4057c478bd9Sstevel@tonic-gate 			(void) memcpy((((uint8_t *)&value) +
4067c478bd9Sstevel@tonic-gate 			    sizeof (value) - def->payloadLen),
4077c478bd9Sstevel@tonic-gate 			    field, def->payloadLen);
40894bc7577Sps154918 			if ((value != 0) &&
409f3af4981Sdt207653 			    (strcmp(def->name, "SPD_Manufacture_Week") == 0)) {
410f3af4981Sdt207653 				valueint = (int)value;
411*5bc0fc0eSdt207653 				if (spd_memtype && spd_revision) {
412f3af4981Sdt207653 					convertbcdtobinary(&valueint);
413*5bc0fc0eSdt207653 					spd_memtype = 0;
414*5bc0fc0eSdt207653 					spd_revision = 0;
415*5bc0fc0eSdt207653 				}
416f3af4981Sdt207653 				output("%d", valueint);
417f3af4981Sdt207653 				return;
418f3af4981Sdt207653 			}
419f3af4981Sdt207653 			if ((value != 0) &&
42094bc7577Sps154918 			    ((strcmp(def->name, "Lowest") == 0) ||
42194bc7577Sps154918 			    (strcmp(def->name, "Highest") == 0) ||
42294bc7577Sps154918 			    (strcmp(def->name, "Latest") == 0)))
4231e3549a6Sps154918 				output((def->dispType == FDISP_Octal) ?
4241e3549a6Sps154918 				"%llo" : "%lld (%lld degrees C)",
4251e3549a6Sps154918 				    value, (value - TEMPERATURE_OFFSET));
4261e3549a6Sps154918 			else
4277c478bd9Sstevel@tonic-gate 				output((def->dispType == FDISP_Octal) ?
4287c478bd9Sstevel@tonic-gate 				"%llo" : "%lld", value);
4297c478bd9Sstevel@tonic-gate 			return;
4307c478bd9Sstevel@tonic-gate 		case FDISP_Time:
4317c478bd9Sstevel@tonic-gate 			if (def->payloadLen > sizeof (timefield)) {
4327c478bd9Sstevel@tonic-gate 				errmsg = "time value too large for formatting";
4337c478bd9Sstevel@tonic-gate 				break;
4347c478bd9Sstevel@tonic-gate 			}
435f3af4981Sdt207653 			timefield = 0;
436f3af4981Sdt207653 			(void) memcpy((((uint8_t *)&timefield) +
437f3af4981Sdt207653 			    sizeof (timefield) - def->payloadLen),
438f3af4981Sdt207653 			    field, def->payloadLen);
439f3af4981Sdt207653 			if (timefield == 0) {
440f3af4981Sdt207653 				errmsg = "No Value Recorded";
441f3af4981Sdt207653 				break;
442f3af4981Sdt207653 			}
443f3af4981Sdt207653 			if ((tm = localtime(&timefield)) == NULL) {
444f3af4981Sdt207653 				errmsg = "cannot convert time value";
445f3af4981Sdt207653 				break;
446f3af4981Sdt207653 			}
447f3af4981Sdt207653 			if (strftime(timestring, sizeof (timestring), "%C", tm)
448f3af4981Sdt207653 			    == 0) {
4497c478bd9Sstevel@tonic-gate 				errmsg = "formatted time would overflow buffer";
4507c478bd9Sstevel@tonic-gate 				break;
4517c478bd9Sstevel@tonic-gate 			}
4527c478bd9Sstevel@tonic-gate 			safeputs(timestring);
4537c478bd9Sstevel@tonic-gate 			return;
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 		break;
4567c478bd9Sstevel@tonic-gate 	case FDTYPE_ASCII:
457f3af4981Sdt207653 		if (!xml) {
458f3af4981Sdt207653 			if (strcmp(def->name, "Message") == 0) {
459f3af4981Sdt207653 				if (FMAmessageR == 0)
460f3af4981Sdt207653 					elem_name = "FMA_Event_DataR";
461f3af4981Sdt207653 				else if (FMAmessageR == 1)
462f3af4981Sdt207653 					elem_name = "FMA_MessageR";
463f3af4981Sdt207653 				if (elem_name != NULL) {
464f3af4981Sdt207653 					(void) memcpy(data, field,
465f3af4981Sdt207653 					    def->payloadLen);
466f3af4981Sdt207653 					new_def =
46746a7ef8aSdt207653 					    fru_reg_lookup_def_by_name
46846a7ef8aSdt207653 					    (elem_name);
469aad09a1cSdt207653 					(void) snprintf(path, sizeof (path),
470f3af4981Sdt207653 					"/Status_EventsR[%d]/Message(FMA)",
471f3af4981Sdt207653 					    iterglobal);
472f3af4981Sdt207653 					parent_path = path;
473f3af4981Sdt207653 					output("\n");
474f3af4981Sdt207653 					print_element(data, new_def,
475f3af4981Sdt207653 					    parent_path, 2*INDENT);
476f3af4981Sdt207653 					return;
477f3af4981Sdt207653 				}
478f3af4981Sdt207653 			}
479f3af4981Sdt207653 		}
4807c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->payloadLen && field[i]; i++)
4817c478bd9Sstevel@tonic-gate 			safeputchar(field[i]);
4827c478bd9Sstevel@tonic-gate 		return;
4837c478bd9Sstevel@tonic-gate 	case FDTYPE_Enumeration:
4847c478bd9Sstevel@tonic-gate 		value = 0;
4857c478bd9Sstevel@tonic-gate 		(void) memcpy((((uint8_t *)&value) + sizeof (value)
4867c478bd9Sstevel@tonic-gate 		    - def->payloadLen),
4877c478bd9Sstevel@tonic-gate 		    field, def->payloadLen);
4887c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->enumCount; i++)
4897c478bd9Sstevel@tonic-gate 			if (def->enumTable[i].value == value) {
490f3af4981Sdt207653 				if (strcmp(def->name, "Event_Code") == 0) {
491f3af4981Sdt207653 					if (strcmp(def->enumTable[i].text,
492f3af4981Sdt207653 "FMA Message R") == 0)
493f3af4981Sdt207653 						FMAmessageR = 1;
494f3af4981Sdt207653 				else
495f3af4981Sdt207653 					if (strcmp(def->enumTable[i].text,
496f3af4981Sdt207653 "FMA Event Data R") == 0)
497f3af4981Sdt207653 						FMAmessageR = 0;
498f3af4981Sdt207653 				}
499*5bc0fc0eSdt207653 				if (strcmp(def->name,
500*5bc0fc0eSdt207653 "SPD_Fundamental_Memory_Type") == 0) {
501*5bc0fc0eSdt207653 					if (strcmp(def->enumTable[i].text,
502*5bc0fc0eSdt207653 "DDR II SDRAM") == 0)
503*5bc0fc0eSdt207653 						spd_memtype = 1;
504*5bc0fc0eSdt207653 				}
5057c478bd9Sstevel@tonic-gate 				safeputs(def->enumTable[i].text);
5067c478bd9Sstevel@tonic-gate 				return;
5077c478bd9Sstevel@tonic-gate 			}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		errmsg = "unrecognized value";
5107c478bd9Sstevel@tonic-gate 		break;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/* If nothing matched above, print the field in hex */
514f3af4981Sdt207653 	switch (def->dispType) {
515f3af4981Sdt207653 		case FDISP_MSGID:
516f3af4981Sdt207653 			(void) memcpy((uchar_t *)&first_byte, field, 1);
517f3af4981Sdt207653 			if (isprint(first_byte)) {
518f3af4981Sdt207653 				for (i = 0; i < def->payloadLen && field[i];
519f3af4981Sdt207653 				    i++)
520f3af4981Sdt207653 					safeputchar(field[i]);
521f3af4981Sdt207653 			}
522f3af4981Sdt207653 			break;
523f3af4981Sdt207653 		case FDISP_UUID:
524f3af4981Sdt207653 			for (i = 0; i < def->payloadLen; i++) {
525f3af4981Sdt207653 				if ((i == 4) || (i == 6) ||
526f3af4981Sdt207653 				    (i == 8) || (i == 10))
527f3af4981Sdt207653 				output("-");
528f3af4981Sdt207653 				output("%2.2x", field[i]);
529f3af4981Sdt207653 			}
530f3af4981Sdt207653 			break;
531f3af4981Sdt207653 		default:
532*5bc0fc0eSdt207653 			if (strcmp(def->name,
533*5bc0fc0eSdt207653 			"SPD_Data_Revision_Code") == 0) {
534*5bc0fc0eSdt207653 				value = 0;
535*5bc0fc0eSdt207653 				valueint = 0;
536*5bc0fc0eSdt207653 				(void) memcpy((((uint8_t *)&value)
537*5bc0fc0eSdt207653 				    + sizeof (value) - def->payloadLen),
538*5bc0fc0eSdt207653 				    field, def->payloadLen);
539*5bc0fc0eSdt207653 				valueint = (int)value;
540*5bc0fc0eSdt207653 				if ((valueint >= MIN_VERSION) && (spd_memtype))
541*5bc0fc0eSdt207653 					spd_revision = 1;
542*5bc0fc0eSdt207653 			}
5437c478bd9Sstevel@tonic-gate 			for (i = 0; i < def->payloadLen; i++)
5447c478bd9Sstevel@tonic-gate 				output("%2.2X", field[i]);
545f3af4981Sdt207653 			break;
546f3af4981Sdt207653 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	/* Safely print any error message associated with the field */
5497c478bd9Sstevel@tonic-gate 	if (errmsg) {
550f3af4981Sdt207653 		if (strcmp(def->name, "Fault_Diag_Secs") != 0) {
5517c478bd9Sstevel@tonic-gate 			output(" (");
5527c478bd9Sstevel@tonic-gate 			safeputs(errmsg);
553f3af4981Sdt207653 			output(")");
554f3af4981Sdt207653 		}
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate /*
5597c478bd9Sstevel@tonic-gate  * Recursively print the contents of a data element
5607c478bd9Sstevel@tonic-gate  */
5617c478bd9Sstevel@tonic-gate static void
5627c478bd9Sstevel@tonic-gate print_element(const uint8_t *data, const fru_regdef_t *def,
5637c478bd9Sstevel@tonic-gate     const char *parent_path, int indent)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	char	*path;
5667c478bd9Sstevel@tonic-gate 	size_t	len;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	int	bytes = 0, i;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	indent = (xml) ? (indent + INDENT) : (2*INDENT);
57246a7ef8aSdt207653 	if (strcmp(def->name, "Sun_SPD_DataR") == 0) {
57346a7ef8aSdt207653 		Fault_Install_DataR_flag = indent;
57446a7ef8aSdt207653 		Power_On_DataR_flag = indent;
57546a7ef8aSdt207653 	}
5767c478bd9Sstevel@tonic-gate 	/*
5777c478bd9Sstevel@tonic-gate 	 * Construct the path, or, for XML, the name, for the current
5787c478bd9Sstevel@tonic-gate 	 * data element
5797c478bd9Sstevel@tonic-gate 	 */
5807c478bd9Sstevel@tonic-gate 	if ((def->iterationCount == 0) &&
5817c478bd9Sstevel@tonic-gate 	    (def->iterationType != FRU_NOT_ITERATED)) {
5827c478bd9Sstevel@tonic-gate 		if (xml) {
5837c478bd9Sstevel@tonic-gate 			if (def->dataType == FDTYPE_Record) {
5847c478bd9Sstevel@tonic-gate 				len = strlen("Index_") + strlen(def->name) + 1;
5857c478bd9Sstevel@tonic-gate 				path = alloca(len);
5867c478bd9Sstevel@tonic-gate 				(void) snprintf(path, len,
5877c478bd9Sstevel@tonic-gate 				    "Index_%s", def->name);
5887c478bd9Sstevel@tonic-gate 			}
5897c478bd9Sstevel@tonic-gate 			else
5907c478bd9Sstevel@tonic-gate 				path = "Index";
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 		else
5937c478bd9Sstevel@tonic-gate 			path = (char *)parent_path;
5947c478bd9Sstevel@tonic-gate 	} else {
5957c478bd9Sstevel@tonic-gate 		if (xml)
5967c478bd9Sstevel@tonic-gate 			path = (char *)def->name;
5977c478bd9Sstevel@tonic-gate 		else {
5987c478bd9Sstevel@tonic-gate 			len = strlen(parent_path) + sizeof ("/") +
5997c478bd9Sstevel@tonic-gate 			    strlen(def->name) +
6007c478bd9Sstevel@tonic-gate 			    (def->iterationCount ? sizeof ("[255]") : 0);
6017c478bd9Sstevel@tonic-gate 			path = alloca(len);
6027c478bd9Sstevel@tonic-gate 			bytes = snprintf(path, len,
6037c478bd9Sstevel@tonic-gate 			    "%s/%s", parent_path, def->name);
6047c478bd9Sstevel@tonic-gate 		}
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
60746a7ef8aSdt207653 	if ((Fault_Install_DataR_flag) &&
60846a7ef8aSdt207653 	    (strcmp(path, "E_1_46") == 0) || (strcmp(path, "/E_1_46") == 0)) {
60946a7ef8aSdt207653 		int cnt;
61046a7ef8aSdt207653 		char timestring[128];
61146a7ef8aSdt207653 		time_t timefield = 0;
61246a7ef8aSdt207653 		struct tm *tm;
61346a7ef8aSdt207653 		indent = Fault_Install_DataR_flag;
61446a7ef8aSdt207653 		(void) memcpy((uint8_t *)&timefield, data, 4);
61546a7ef8aSdt207653 		if (timefield == 0) {
61646a7ef8aSdt207653 			(void) sprintf(timestring,
61746a7ef8aSdt207653 			    "00000000 (No Value Recorded)\"");
61846a7ef8aSdt207653 		} else {
61946a7ef8aSdt207653 			if ((tm = localtime(&timefield)) == NULL)
62046a7ef8aSdt207653 				(void) sprintf(timestring,
62146a7ef8aSdt207653 				    "cannot convert time value");
62246a7ef8aSdt207653 			if (strftime(timestring,
62346a7ef8aSdt207653 			    sizeof (timestring), "%C", tm) == 0)
62446a7ef8aSdt207653 				(void) sprintf(timestring,
62546a7ef8aSdt207653 				    "formatted time would overflow buffer");
62646a7ef8aSdt207653 		}
62746a7ef8aSdt207653 		if (xml) {
62846a7ef8aSdt207653 			(void) sprintf(path, "Fault_Install_DataR");
62946a7ef8aSdt207653 			output("%*s<%s>\n", indent, "", path);
63046a7ef8aSdt207653 			indent = Fault_Install_DataR_flag + INDENT;
63146a7ef8aSdt207653 			(void) sprintf(path, "UNIX_Timestamp32");
63246a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
63346a7ef8aSdt207653 			/*CSTYLED*/
63446a7ef8aSdt207653 			output("%s\"/>\n", timestring);
63546a7ef8aSdt207653 			(void) sprintf(path, "MACADDR");
63646a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
63746a7ef8aSdt207653 			for (cnt = 4; cnt < 4 + 6; cnt++) {
63846a7ef8aSdt207653 				output("%2.2x", data[cnt]);
63946a7ef8aSdt207653 				if (cnt < 4 + 6 - 1)
64046a7ef8aSdt207653 					output(":");
64146a7ef8aSdt207653 			}
64246a7ef8aSdt207653 			/*CSTYLED*/
64346a7ef8aSdt207653 			output("\"/>\n");
64446a7ef8aSdt207653 			(void) sprintf(path, "Status");
64546a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
64646a7ef8aSdt207653 			/*CSTYLED*/
64746a7ef8aSdt207653 			output("%2.2x\"/>\n", data[10]);
64846a7ef8aSdt207653 			(void) sprintf(path, "Initiator");
64946a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
65046a7ef8aSdt207653 			/*CSTYLED*/
65146a7ef8aSdt207653 			output("%2.2x\"/>\n", data[11]);
65246a7ef8aSdt207653 			(void) sprintf(path, "Message_Type");
65346a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
65446a7ef8aSdt207653 			/*CSTYLED*/
65546a7ef8aSdt207653 			output("%2.2x\"/>\n", data[12]);
65646a7ef8aSdt207653 			(void) sprintf(path, "Message_32");
65746a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
65846a7ef8aSdt207653 			for (cnt = 13; cnt < 13 + 32; cnt++)
65946a7ef8aSdt207653 				output("%2.2x", data[cnt]);
66046a7ef8aSdt207653 			/*CSTYLED*/
66146a7ef8aSdt207653 			output("\"/>\n");
66246a7ef8aSdt207653 			indent = Fault_Install_DataR_flag;
66346a7ef8aSdt207653 			(void) sprintf(path, "Fault_Install_DataR");
66446a7ef8aSdt207653 			output("%*s</%s>\n", indent, "", path);
66546a7ef8aSdt207653 		} else {
66646a7ef8aSdt207653 			(void) sprintf(path, "/Fault_Install_DataR");
66746a7ef8aSdt207653 			output("%*s%s\n", indent, "", path);
66846a7ef8aSdt207653 			(void) sprintf(path,
66946a7ef8aSdt207653 			    "/Fault_Install_DataR/UNIX_Timestamp32");
67046a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
67146a7ef8aSdt207653 			output("%s\n", timestring);
67246a7ef8aSdt207653 			(void) sprintf(path, "/Fault_Install_DataR/MACADDR");
67346a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
67446a7ef8aSdt207653 			for (cnt = 4; cnt < 4 + 6; cnt++) {
67546a7ef8aSdt207653 				output("%2.2x", data[cnt]);
67646a7ef8aSdt207653 				if (cnt < 4 + 6 - 1)
67746a7ef8aSdt207653 					output(":");
67846a7ef8aSdt207653 			}
67946a7ef8aSdt207653 			output("\n");
68046a7ef8aSdt207653 			(void) sprintf(path, "/Fault_Install_DataR/Status");
68146a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
68246a7ef8aSdt207653 			output("%2.2x\n", data[10]);
68346a7ef8aSdt207653 			(void) sprintf(path, "/Fault_Install_DataR/Initiator");
68446a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
68546a7ef8aSdt207653 			output("%2.2x\n", data[11]);
68646a7ef8aSdt207653 			(void) sprintf(path,
68746a7ef8aSdt207653 			    "/Fault_Install_DataR/Message_Type");
68846a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
68946a7ef8aSdt207653 			output("%2.2x\n", data[12]);
69046a7ef8aSdt207653 			(void) sprintf(path, "/Fault_Install_DataR/Message_32");
69146a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
69246a7ef8aSdt207653 			for (cnt = 13; cnt < 13 + 32; cnt++)
69346a7ef8aSdt207653 				output("%2.2x", data[cnt]);
69446a7ef8aSdt207653 			output("\n");
69546a7ef8aSdt207653 		}
69646a7ef8aSdt207653 		Fault_Install_DataR_flag = 0;
69746a7ef8aSdt207653 		return;
69846a7ef8aSdt207653 	} else if ((Power_On_DataR_flag) && (
69946a7ef8aSdt207653 	    strcmp(path, "C_10_8") == 0 ||
70046a7ef8aSdt207653 	    (strcmp(path, "/C_10_8") == 0))) {
70146a7ef8aSdt207653 		int cnt;
70246a7ef8aSdt207653 		char timestring[128];
70346a7ef8aSdt207653 		time_t timefield = 0;
70446a7ef8aSdt207653 		struct tm *tm;
70546a7ef8aSdt207653 		indent = Power_On_DataR_flag;
70646a7ef8aSdt207653 		(void) memcpy((uint8_t *)&timefield, data, 4);
70746a7ef8aSdt207653 		if (timefield == 0) {
70846a7ef8aSdt207653 			(void) sprintf(timestring,
70946a7ef8aSdt207653 			    "00000000 (No Value Recorded)");
71046a7ef8aSdt207653 		} else {
71146a7ef8aSdt207653 			if ((tm = localtime(&timefield)) == NULL)
71246a7ef8aSdt207653 				(void) sprintf(timestring,
71346a7ef8aSdt207653 				    "cannot convert time value");
71446a7ef8aSdt207653 			if (strftime(timestring,
71546a7ef8aSdt207653 			    sizeof (timestring), "%C", tm) == 0)
71646a7ef8aSdt207653 				(void) sprintf(timestring,
71746a7ef8aSdt207653 				    "formatted time would overflow buffer");
71846a7ef8aSdt207653 		}
71946a7ef8aSdt207653 		if (xml) {
72046a7ef8aSdt207653 			(void) sprintf(path, "Power_On_DataR");
72146a7ef8aSdt207653 			output("%*s<%s>\n", indent, "", path);
72246a7ef8aSdt207653 			indent = Power_On_DataR_flag + INDENT;
72346a7ef8aSdt207653 			(void) sprintf(path, "UNIX_Timestamp32");
72446a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
72546a7ef8aSdt207653 			/*CSTYLED*/
72646a7ef8aSdt207653 			output("%s\"/>\n", timestring);
72746a7ef8aSdt207653 			(void) sprintf(path, "Power_On_Minutes");
72846a7ef8aSdt207653 			output("%*s<%s value=\"", indent, "", path);
72946a7ef8aSdt207653 			for (cnt = 4; cnt < 4 + 4; cnt++)
73046a7ef8aSdt207653 				output("%2.2x", data[cnt]);
73146a7ef8aSdt207653 			/*CSTYLED*/
73246a7ef8aSdt207653 			output("\"/>\n");
73346a7ef8aSdt207653 			indent = Power_On_DataR_flag;
73446a7ef8aSdt207653 			(void) sprintf(path, "Power_On_DataR");
73546a7ef8aSdt207653 			output("%*s</%s>\n", indent, "", path);
73646a7ef8aSdt207653 		} else {
73746a7ef8aSdt207653 			(void) sprintf(path, "/Power_On_DataR");
73846a7ef8aSdt207653 			output("%*s%s\n", indent, "", path);
73946a7ef8aSdt207653 			(void) sprintf(path,
74046a7ef8aSdt207653 			    "/Power_On_DataR/UNIX_Timestamp32");
74146a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
74246a7ef8aSdt207653 			output("%s\n", timestring);
74346a7ef8aSdt207653 			(void) sprintf(path,
74446a7ef8aSdt207653 			    "/Power_On_DataR/Power_On_Minutes");
74546a7ef8aSdt207653 			output("%*s%s: ", indent, "", path);
74646a7ef8aSdt207653 			for (cnt = 4; cnt < 4 + 4; cnt++)
74746a7ef8aSdt207653 				output("%2.2x", data[cnt]);
74846a7ef8aSdt207653 			output("\n");
74946a7ef8aSdt207653 		}
75046a7ef8aSdt207653 		Power_On_DataR_flag = 0;
75146a7ef8aSdt207653 		return;
75246a7ef8aSdt207653 	}
7537c478bd9Sstevel@tonic-gate 	/*
7547c478bd9Sstevel@tonic-gate 	 * Handle the various categories of data elements:  iteration,
7557c478bd9Sstevel@tonic-gate 	 * record, and field
7567c478bd9Sstevel@tonic-gate 	 */
7577c478bd9Sstevel@tonic-gate 	if (def->iterationCount) {
7587c478bd9Sstevel@tonic-gate 		int		iterlen = (def->payloadLen - NUM_ITER_BYTES)/
7597c478bd9Sstevel@tonic-gate 		    def->iterationCount,
7607c478bd9Sstevel@tonic-gate 		    n, valid = 1;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		uint8_t		head, num;
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		fru_regdef_t	newdef;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 		/*
7687c478bd9Sstevel@tonic-gate 		 * Make a new element definition to describe the components
7697c478bd9Sstevel@tonic-gate 		 * of the iteration
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		(void) memcpy(&newdef, def, sizeof (newdef));
7727c478bd9Sstevel@tonic-gate 		newdef.iterationCount = 0;
7737c478bd9Sstevel@tonic-gate 		newdef.payloadLen = iterlen;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		/*
7767c478bd9Sstevel@tonic-gate 		 * Validate the contents of the iteration control bytes
7777c478bd9Sstevel@tonic-gate 		 */
7787c478bd9Sstevel@tonic-gate 		if (data[HEAD_ITER] >= def->iterationCount) {
7797c478bd9Sstevel@tonic-gate 			valid = 0;
7807c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration head:  %d "
7817c478bd9Sstevel@tonic-gate 			    "(should be less than %d)\n"),
7827c478bd9Sstevel@tonic-gate 			    path, data[HEAD_ITER], def->iterationCount);
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		if (data[NUM_ITER] > def->iterationCount) {
7867c478bd9Sstevel@tonic-gate 			valid = 0;
7877c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration count:  %d "
7887c478bd9Sstevel@tonic-gate 			    "(should not be greater than %d)\n"),
7897c478bd9Sstevel@tonic-gate 			    path, data[NUM_ITER], def->iterationCount);
7907c478bd9Sstevel@tonic-gate 		}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 		if (data[MAX_ITER] != def->iterationCount) {
7937c478bd9Sstevel@tonic-gate 			valid = 0;
7947c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration maximum:  %d "
7957c478bd9Sstevel@tonic-gate 			    "(should equal %d)\n"),
7967c478bd9Sstevel@tonic-gate 			    path, data[MAX_ITER], def->iterationCount);
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 		if (valid) {
8007c478bd9Sstevel@tonic-gate 			head = data[HEAD_ITER];
8017c478bd9Sstevel@tonic-gate 			num  = data[NUM_ITER];
8027c478bd9Sstevel@tonic-gate 		} else {
8037c478bd9Sstevel@tonic-gate 			head = 0;
8047c478bd9Sstevel@tonic-gate 			num  = def->iterationCount;
8057c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Showing all iterations\n"), path);
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		if (xml)
8097c478bd9Sstevel@tonic-gate 			output("%*s<%s>\n", indent, "", path);
8107c478bd9Sstevel@tonic-gate 		else
8117c478bd9Sstevel@tonic-gate 			output("%*s%s (%d iterations)\n", indent, "", path,
8127c478bd9Sstevel@tonic-gate 			    num);
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		/*
8157c478bd9Sstevel@tonic-gate 		 * Print each component of the iteration
8167c478bd9Sstevel@tonic-gate 		 */
8177c478bd9Sstevel@tonic-gate 		for (i = head, n = 0, data += 4;
8187c478bd9Sstevel@tonic-gate 		    n < num;
8197c478bd9Sstevel@tonic-gate 		    i = ((i + 1) % def->iterationCount), n++) {
8207c478bd9Sstevel@tonic-gate 			if (!xml) (void) sprintf((path + bytes), "[%d]", n);
821f3af4981Sdt207653 			iterglobal = n;
8227c478bd9Sstevel@tonic-gate 			print_element((data + i*iterlen), &newdef, path,
8237c478bd9Sstevel@tonic-gate 			    indent);
8247c478bd9Sstevel@tonic-gate 		}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 		if (xml) output("%*s</%s>\n", indent, "", path);
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	} else if (def->dataType == FDTYPE_Record) {
8297c478bd9Sstevel@tonic-gate 		const fru_regdef_t  *component;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		if (xml)
8327c478bd9Sstevel@tonic-gate 			output("%*s<%s>\n", indent, "", path);
8337c478bd9Sstevel@tonic-gate 		else
8347c478bd9Sstevel@tonic-gate 			output("%*s%s\n", indent, "", path);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		/*
8377c478bd9Sstevel@tonic-gate 		 * Print each component of the record
8387c478bd9Sstevel@tonic-gate 		 */
8397c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->enumCount;
8407c478bd9Sstevel@tonic-gate 		    i++, data += component->payloadLen) {
8417c478bd9Sstevel@tonic-gate 			component = fru_reg_lookup_def_by_name(
8427c478bd9Sstevel@tonic-gate 			    def->enumTable[i].text);
8437c478bd9Sstevel@tonic-gate 			assert(component != NULL);
8447c478bd9Sstevel@tonic-gate 			print_element(data, component, path, indent);
8457c478bd9Sstevel@tonic-gate 		}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		if (xml) output("%*s</%s>\n", indent, "", path);
8487c478bd9Sstevel@tonic-gate 	} else if (xml) {
8497c478bd9Sstevel@tonic-gate 		/*
8507c478bd9Sstevel@tonic-gate 		 * Base case:  print the field formatted for XML
8517c478bd9Sstevel@tonic-gate 		 */
8527c478bd9Sstevel@tonic-gate 		char  *format = ((def == &unknown)
8537c478bd9Sstevel@tonic-gate 		    ? "%*s<UNKNOWN tag=\"%s\" value=\""
8547c478bd9Sstevel@tonic-gate 		    : "%*s<%s value=\"");
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		output(format, indent, "", path);
8577c478bd9Sstevel@tonic-gate 		print_field(data, def);
8587c478bd9Sstevel@tonic-gate 		/*CSTYLED*/
8597c478bd9Sstevel@tonic-gate 		output("\"/>\n");	/* \" confuses cstyle */
860f3af4981Sdt207653 
861f3af4981Sdt207653 		if ((strcmp(def->name, "Message") == 0) &&
862f3af4981Sdt207653 		    ((FMAmessageR == 0) || (FMAmessageR == 1))) {
863f3af4981Sdt207653 			const char	*elem_name = NULL;
864f3af4981Sdt207653 			const char	*parent_path;
865f3af4981Sdt207653 			uchar_t		tmpdata[128];
866f3af4981Sdt207653 			char		path[16384];
867f3af4981Sdt207653 			const fru_regdef_t	*new_def;
868f3af4981Sdt207653 
869f3af4981Sdt207653 			if (FMAmessageR == 0)
870f3af4981Sdt207653 				elem_name = "FMA_Event_DataR";
871f3af4981Sdt207653 			else if (FMAmessageR == 1)
872f3af4981Sdt207653 				elem_name = "FMA_MessageR";
873f3af4981Sdt207653 			if (elem_name != NULL) {
874f3af4981Sdt207653 				(void) memcpy(tmpdata, data, def->payloadLen);
875f3af4981Sdt207653 				new_def = fru_reg_lookup_def_by_name(elem_name);
87677acf672Sdt207653 				(void) snprintf(path, sizeof (path),
877f3af4981Sdt207653 				"/Status_EventsR[%d]/Message(FMA)", iterglobal);
878f3af4981Sdt207653 				parent_path = path;
879f3af4981Sdt207653 				print_element(tmpdata, new_def,
880f3af4981Sdt207653 				    parent_path, 2*INDENT);
881f3af4981Sdt207653 				FMAmessageR = -1;
882f3af4981Sdt207653 			}
883f3af4981Sdt207653 		}
884f3af4981Sdt207653 
8857c478bd9Sstevel@tonic-gate 	} else {
8867c478bd9Sstevel@tonic-gate 		/*
8877c478bd9Sstevel@tonic-gate 		 * Base case:  print the field
8887c478bd9Sstevel@tonic-gate 		 */
8897c478bd9Sstevel@tonic-gate 		output("%*s%s: ", indent, "", path);
8907c478bd9Sstevel@tonic-gate 		print_field(data, def);
8917c478bd9Sstevel@tonic-gate 		output("\n");
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate  * Print the contents of a packet (i.e., a tagged data element)
8977c478bd9Sstevel@tonic-gate  */
8987c478bd9Sstevel@tonic-gate /* ARGSUSED */
8997c478bd9Sstevel@tonic-gate static int
9007c478bd9Sstevel@tonic-gate print_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate 	int			tag_type = get_tag_type(tag);
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	size_t			payload_length = 0;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	const fru_regdef_t	*def;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/*
9097c478bd9Sstevel@tonic-gate 	 * Build a definition for unrecognized tags (e.g., not in libfrureg)
9107c478bd9Sstevel@tonic-gate 	 */
9117c478bd9Sstevel@tonic-gate 	if ((tag_type == -1) ||
9127c478bd9Sstevel@tonic-gate 	    ((payload_length = get_payload_length(tag)) != length)) {
9137c478bd9Sstevel@tonic-gate 		def = &unknown;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		unknown.tagType    = -1;
9167c478bd9Sstevel@tonic-gate 		unknown.tagDense   = -1;
9177c478bd9Sstevel@tonic-gate 		unknown.payloadLen = length;
9187c478bd9Sstevel@tonic-gate 		unknown.dataLength = unknown.payloadLen;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		if (tag_type == -1)
9217c478bd9Sstevel@tonic-gate 			(void) snprintf(tagname, sizeof (tagname), "INVALID");
9227c478bd9Sstevel@tonic-gate 		else
9237c478bd9Sstevel@tonic-gate 			(void) snprintf(tagname, sizeof (tagname),
9247c478bd9Sstevel@tonic-gate 			    "%s_%u_%u_%u", get_tagtype_str(tag_type),
9257c478bd9Sstevel@tonic-gate 			    get_tag_dense(tag), payload_length, length);
9267c478bd9Sstevel@tonic-gate 	} else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) {
9277c478bd9Sstevel@tonic-gate 		def = &unknown;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 		unknown.tagType    = tag_type;
9307c478bd9Sstevel@tonic-gate 		unknown.tagDense   = get_tag_dense(tag);
9317c478bd9Sstevel@tonic-gate 		unknown.payloadLen = payload_length;
9327c478bd9Sstevel@tonic-gate 		unknown.dataLength = unknown.payloadLen;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 		(void) snprintf(tagname, sizeof (tagname), "%s_%u_%u",
9357c478bd9Sstevel@tonic-gate 		    get_tagtype_str(unknown.tagType),
9367c478bd9Sstevel@tonic-gate 		    unknown.tagDense, payload_length);
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	/*
9417c478bd9Sstevel@tonic-gate 	 * Print the defined element
9427c478bd9Sstevel@tonic-gate 	 */
9437c478bd9Sstevel@tonic-gate 	print_element(payload, def, "", INDENT);
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate /*
9497c478bd9Sstevel@tonic-gate  * Print a segment's name and the contents of each data element in the segment
9507c478bd9Sstevel@tonic-gate  */
9517c478bd9Sstevel@tonic-gate static int
9527c478bd9Sstevel@tonic-gate print_packets_in_segment(fru_seghdl_t segment, void *args)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	char	*name;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	int	status;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if ((status = fru_get_segment_name(segment, &name)) != FRU_SUCCESS) {
9607c478bd9Sstevel@tonic-gate 		saved_status = status;
9617c478bd9Sstevel@tonic-gate 		name = "";
9627c478bd9Sstevel@tonic-gate 		error(gettext("Error getting segment name:  %s\n"),
9637c478bd9Sstevel@tonic-gate 		    fru_strerror(status));
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	if (xml)
9687c478bd9Sstevel@tonic-gate 		output("%*s<Segment name=\"%s\">\n", INDENT, "", name);
9697c478bd9Sstevel@tonic-gate 	else
9707c478bd9Sstevel@tonic-gate 		output("%*sSEGMENT: %s\n", INDENT, "", name);
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/* Iterate over the packets in the segment, printing the contents */
9737c478bd9Sstevel@tonic-gate 	if ((status = fru_for_each_packet(segment, print_packet, args))
9747c478bd9Sstevel@tonic-gate 	    != FRU_SUCCESS) {
9757c478bd9Sstevel@tonic-gate 		saved_status = status;
9767c478bd9Sstevel@tonic-gate 		error(gettext("Error processing data in segment \"%s\":  %s\n"),
9777c478bd9Sstevel@tonic-gate 		    name, fru_strerror(status));
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	if (xml) output("%*s</Segment>\n", INDENT, "");
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	free(name);
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate /* ARGSUSED */
9887c478bd9Sstevel@tonic-gate static void
9897c478bd9Sstevel@tonic-gate print_node_path(fru_node_t fru_type, const char *path, const char *name,
9907c478bd9Sstevel@tonic-gate     end_node_fp_t *end_node, void **end_args)
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate 	output("%s%s\n", path,
9937c478bd9Sstevel@tonic-gate 	    ((fru_type == FRU_NODE_CONTAINER) ? " (container)"
9947c478bd9Sstevel@tonic-gate 	    : ((fru_type == FRU_NODE_FRU) ? " (fru)" : "")));
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate /*
9987c478bd9Sstevel@tonic-gate  * Close the XML element for a "location" node
9997c478bd9Sstevel@tonic-gate  */
10007c478bd9Sstevel@tonic-gate /* ARGSUSED */
10017c478bd9Sstevel@tonic-gate static void
10027c478bd9Sstevel@tonic-gate end_location_xml(fru_nodehdl_t node, const char *path, const char *name,
10037c478bd9Sstevel@tonic-gate     void *args)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	assert(args != NULL);
10067c478bd9Sstevel@tonic-gate 	output("</Location> <!-- %s -->\n", args);
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate /*
10107c478bd9Sstevel@tonic-gate  * Close the XML element for a "fru" node
10117c478bd9Sstevel@tonic-gate  */
10127c478bd9Sstevel@tonic-gate /* ARGSUSED */
10137c478bd9Sstevel@tonic-gate static void
10147c478bd9Sstevel@tonic-gate end_fru_xml(fru_nodehdl_t node, const char *path, const char *name, void *args)
10157c478bd9Sstevel@tonic-gate {
10167c478bd9Sstevel@tonic-gate 	assert(args != NULL);
10177c478bd9Sstevel@tonic-gate 	output("</Fru> <!-- %s -->\n", args);
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate /*
10217c478bd9Sstevel@tonic-gate  * Close the XML element for a "container" node
10227c478bd9Sstevel@tonic-gate  */
10237c478bd9Sstevel@tonic-gate /* ARGSUSED */
10247c478bd9Sstevel@tonic-gate static void
10257c478bd9Sstevel@tonic-gate end_container_xml(fru_nodehdl_t node, const char *path, const char *name,
10267c478bd9Sstevel@tonic-gate     void *args)
10277c478bd9Sstevel@tonic-gate {
10287c478bd9Sstevel@tonic-gate 	assert(args != NULL);
10297c478bd9Sstevel@tonic-gate 	output("</Container> <!-- %s -->\n", args);
10307c478bd9Sstevel@tonic-gate }
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate /*
10337c478bd9Sstevel@tonic-gate  * Introduce a node in XML and set the appropriate node-closing function
10347c478bd9Sstevel@tonic-gate  */
10357c478bd9Sstevel@tonic-gate /* ARGSUSED */
10367c478bd9Sstevel@tonic-gate static void
10377c478bd9Sstevel@tonic-gate print_node_xml(fru_node_t fru_type, const char *path, const char *name,
10387c478bd9Sstevel@tonic-gate     end_node_fp_t *end_node, void **end_args)
10397c478bd9Sstevel@tonic-gate {
10407c478bd9Sstevel@tonic-gate 	switch (fru_type) {
10417c478bd9Sstevel@tonic-gate 	case FRU_NODE_FRU:
10427c478bd9Sstevel@tonic-gate 		output("<Fru name=\"%s\">\n", name);
10437c478bd9Sstevel@tonic-gate 		*end_node = end_fru_xml;
10447c478bd9Sstevel@tonic-gate 		break;
10457c478bd9Sstevel@tonic-gate 	case FRU_NODE_CONTAINER:
10467c478bd9Sstevel@tonic-gate 		output("<Container name=\"%s\">\n", name);
10477c478bd9Sstevel@tonic-gate 		*end_node = end_container_xml;
10487c478bd9Sstevel@tonic-gate 		break;
10497c478bd9Sstevel@tonic-gate 	default:
10507c478bd9Sstevel@tonic-gate 		output("<Location name=\"%s\">\n", name);
10517c478bd9Sstevel@tonic-gate 		*end_node = end_location_xml;
10527c478bd9Sstevel@tonic-gate 		break;
10537c478bd9Sstevel@tonic-gate 	}
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	*end_args = (void *) name;
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate /*
10597c478bd9Sstevel@tonic-gate  * Print node info and, where appropriate, node contents
10607c478bd9Sstevel@tonic-gate  */
10617c478bd9Sstevel@tonic-gate /* ARGSUSED */
10627c478bd9Sstevel@tonic-gate static fru_errno_t
10637c478bd9Sstevel@tonic-gate process_node(fru_nodehdl_t node, const char *path, const char *name,
10647c478bd9Sstevel@tonic-gate 		void *args, end_node_fp_t *end_node, void **end_args)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate 	int		status;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	fru_node_t	fru_type = FRU_NODE_UNKNOWN;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	if ((status = fru_get_node_type(node, &fru_type)) != FRU_SUCCESS) {
10727c478bd9Sstevel@tonic-gate 		saved_status = status;
10737c478bd9Sstevel@tonic-gate 		error(gettext("Error getting node type:  %s\n"),
10747c478bd9Sstevel@tonic-gate 		    fru_strerror(status));
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 	if (containers_only) {
10787c478bd9Sstevel@tonic-gate 		if (fru_type != FRU_NODE_CONTAINER)
10797c478bd9Sstevel@tonic-gate 			return (FRU_SUCCESS);
10807c478bd9Sstevel@tonic-gate 		name = path;
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	/* Introduce the node */
10847c478bd9Sstevel@tonic-gate 	assert(print_node != NULL);
10857c478bd9Sstevel@tonic-gate 	print_node(fru_type, path, name, end_node, end_args);
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	if (list_only)
10887c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	/* Print the contents of each packet in each segment of a container */
10917c478bd9Sstevel@tonic-gate 	if (fru_type == FRU_NODE_CONTAINER) {
10927c478bd9Sstevel@tonic-gate 		if (xml) output("<ContainerData>\n");
10937c478bd9Sstevel@tonic-gate 		if ((status =
10947c478bd9Sstevel@tonic-gate 		    fru_for_each_segment(node, print_packets_in_segment,
10957c478bd9Sstevel@tonic-gate 		    NULL))
10967c478bd9Sstevel@tonic-gate 		    != FRU_SUCCESS) {
10977c478bd9Sstevel@tonic-gate 			saved_status = status;
10987c478bd9Sstevel@tonic-gate 			error(gettext("Error  processing node \"%s\":  %s\n"),
10997c478bd9Sstevel@tonic-gate 			    name, fru_strerror(status));
11007c478bd9Sstevel@tonic-gate 		}
11017c478bd9Sstevel@tonic-gate 		if (xml) output("</ContainerData>\n");
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate /*
11087c478bd9Sstevel@tonic-gate  * Process the node if its path matches the search path in "args"
11097c478bd9Sstevel@tonic-gate  */
11107c478bd9Sstevel@tonic-gate /* ARGSUSED */
11117c478bd9Sstevel@tonic-gate static fru_errno_t
11127c478bd9Sstevel@tonic-gate process_matching_node(fru_nodehdl_t node, const char *path, const char *name,
11137c478bd9Sstevel@tonic-gate     void *args, end_node_fp_t *end_node, void **end_args)
11147c478bd9Sstevel@tonic-gate 	{
11157c478bd9Sstevel@tonic-gate 	int  status;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (!fru_pathmatch(path, args))
11197c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	status = process_node(node, path, path, args, end_node, end_args);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	return ((status == FRU_SUCCESS) ? FRU_WALK_TERMINATE : status);
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate /*
11277c478bd9Sstevel@tonic-gate  * Write the trailer required for well-formed DTD-compliant XML
11287c478bd9Sstevel@tonic-gate  */
11297c478bd9Sstevel@tonic-gate static void
11307c478bd9Sstevel@tonic-gate terminate_xml()
11317c478bd9Sstevel@tonic-gate {
11327c478bd9Sstevel@tonic-gate 	errno = 0;
11337c478bd9Sstevel@tonic-gate 	if (ftell(errlog) > 0) {
11347c478bd9Sstevel@tonic-gate 		char  c;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		output("<ErrorLog>\n");
11377c478bd9Sstevel@tonic-gate 		rewind(errlog);
11387c478bd9Sstevel@tonic-gate 		if (!errno)
11397c478bd9Sstevel@tonic-gate 			while ((c = getc(errlog)) != EOF)
11407c478bd9Sstevel@tonic-gate 				xputchar(c);
11417c478bd9Sstevel@tonic-gate 		output("</ErrorLog>\n");
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	if (errno) {
11457c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
11467c478bd9Sstevel@tonic-gate 		errlog = NULL;
11477c478bd9Sstevel@tonic-gate 		error(gettext("Error copying error messages to \"ErrorLog\""),
11487c478bd9Sstevel@tonic-gate 		    strerror(errno));
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	output("</FRUID_XML_Tree>\n");
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate /*
11557c478bd9Sstevel@tonic-gate  * Print available FRU ID information
11567c478bd9Sstevel@tonic-gate  */
11577c478bd9Sstevel@tonic-gate int
11587c478bd9Sstevel@tonic-gate prtfru(const char *searchpath, int containers_only_flag, int list_only_flag,
11597c478bd9Sstevel@tonic-gate 	int xml_flag)
11607c478bd9Sstevel@tonic-gate {
11617c478bd9Sstevel@tonic-gate 	fru_errno_t    status;
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	fru_nodehdl_t  frutree = 0;
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	/* Copy parameter flags to global flags */
11677c478bd9Sstevel@tonic-gate 	containers_only	= containers_only_flag;
11687c478bd9Sstevel@tonic-gate 	list_only	= list_only_flag;
11697c478bd9Sstevel@tonic-gate 	xml		= xml_flag;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	/* Help arrange for correct, efficient interleaving of output */
11737c478bd9Sstevel@tonic-gate 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	/* Initialize for XML--or not */
11777c478bd9Sstevel@tonic-gate 	if (xml) {
11787c478bd9Sstevel@tonic-gate 		safeputchar = xputchar;
11797c478bd9Sstevel@tonic-gate 		safeputs    = xputs;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		print_node  = print_node_xml;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 		if ((errlog = tmpfile()) == NULL) {
11847c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
11857c478bd9Sstevel@tonic-gate 			    "Error creating error log file:  %s\n",
11867c478bd9Sstevel@tonic-gate 			    strerror(errno));
11877c478bd9Sstevel@tonic-gate 			return (1);
11887c478bd9Sstevel@tonic-gate 		}
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 		/* Output the XML preamble */
11917c478bd9Sstevel@tonic-gate 		output("<?xml version=\"1.0\" ?>\n"
11927c478bd9Sstevel@tonic-gate 		    "<!--\n"
11937c478bd9Sstevel@tonic-gate 		    " Copyright 2000-2002 Sun Microsystems, Inc.  "
11947c478bd9Sstevel@tonic-gate 		    "All rights reserved.\n"
11957c478bd9Sstevel@tonic-gate 		    " Use is subject to license terms.\n"
11967c478bd9Sstevel@tonic-gate 		    "-->\n\n"
11977c478bd9Sstevel@tonic-gate 		    "<!DOCTYPE FRUID_XML_Tree SYSTEM \"prtfrureg.dtd\">\n\n"
11987c478bd9Sstevel@tonic-gate 		    "<FRUID_XML_Tree>\n");
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 		/* Arrange to always properly terminate XML */
12017c478bd9Sstevel@tonic-gate 		if (atexit(terminate_xml))
12027c478bd9Sstevel@tonic-gate 			error(gettext("Warning:  XML will not be terminated:  "
12037c478bd9Sstevel@tonic-gate 			    "%s\n"), strerror(errno));
12047c478bd9Sstevel@tonic-gate 	} else
12057c478bd9Sstevel@tonic-gate 		print_node = print_node_path;
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	/* Get the root node */
12097c478bd9Sstevel@tonic-gate 	if ((status = fru_get_root(&frutree)) == FRU_NODENOTFOUND) {
12107c478bd9Sstevel@tonic-gate 		error(gettext("This system does not provide FRU ID data\n"));
12117c478bd9Sstevel@tonic-gate 		return (1);
12127c478bd9Sstevel@tonic-gate 	} else if (status != FRU_SUCCESS) {
12137c478bd9Sstevel@tonic-gate 		error(gettext("Unable to access FRU ID data:  %s\n"),
12147c478bd9Sstevel@tonic-gate 		    fru_strerror(status));
12157c478bd9Sstevel@tonic-gate 		return (1);
12167c478bd9Sstevel@tonic-gate 	}
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	/* Process the tree */
12197c478bd9Sstevel@tonic-gate 	if (searchpath == NULL) {
12207c478bd9Sstevel@tonic-gate 		status = fru_walk_tree(frutree, "", process_node, NULL);
12217c478bd9Sstevel@tonic-gate 	} else {
12227c478bd9Sstevel@tonic-gate 		status = fru_walk_tree(frutree, "", process_matching_node,
12237c478bd9Sstevel@tonic-gate 		    (void *)searchpath);
12247c478bd9Sstevel@tonic-gate 		if (status == FRU_WALK_TERMINATE) {
12257c478bd9Sstevel@tonic-gate 			status = FRU_SUCCESS;
12267c478bd9Sstevel@tonic-gate 		} else if (status == FRU_SUCCESS) {
12277c478bd9Sstevel@tonic-gate 			error(gettext("\"%s\" not found\n"), searchpath);
12287c478bd9Sstevel@tonic-gate 			return (1);
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	if (status != FRU_SUCCESS)
12337c478bd9Sstevel@tonic-gate 		error(gettext("Error processing FRU tree:  %s\n"),
12347c478bd9Sstevel@tonic-gate 		    fru_strerror(status));
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	return (((status == FRU_SUCCESS) && (saved_status == 0)) ? 0 : 1);
12377c478bd9Sstevel@tonic-gate }
1238