xref: /titanic_53/usr/src/cmd/prtfru/prtfru.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <alloca.h>
30*7c478bd9Sstevel@tonic-gate #include <assert.h>
31*7c478bd9Sstevel@tonic-gate #include <errno.h>
32*7c478bd9Sstevel@tonic-gate #include <libintl.h>
33*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include "fru_tag.h"
39*7c478bd9Sstevel@tonic-gate #include "libfrup.h"
40*7c478bd9Sstevel@tonic-gate #include "libfrureg.h"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #define	NUM_ITER_BYTES 4
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #define	HEAD_ITER 0
46*7c478bd9Sstevel@tonic-gate #define	TAIL_ITER 1	/*  not used  */
47*7c478bd9Sstevel@tonic-gate #define	NUM_ITER  2
48*7c478bd9Sstevel@tonic-gate #define	MAX_ITER  3
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #define	INDENT 3
51*7c478bd9Sstevel@tonic-gate #define	TIMESTRINGLEN 128
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static void	(*print_node)(fru_node_t fru_type, const char *path,
55*7c478bd9Sstevel@tonic-gate 				const char *name, end_node_fp_t *end_node,
56*7c478bd9Sstevel@tonic-gate 				void **end_args);
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate static char	tagname[sizeof ("?_0123456789_0123456789_0123456789")];
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate static int	containers_only = 0, list_only = 0, saved_status = 0, xml = 0;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate static FILE	*errlog;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * Definition for data elements found in devices but not found in
66*7c478bd9Sstevel@tonic-gate  * the system's version of libfrureg
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate static fru_regdef_t  unknown = {
69*7c478bd9Sstevel@tonic-gate 	REGDEF_VERSION,
70*7c478bd9Sstevel@tonic-gate 	tagname,
71*7c478bd9Sstevel@tonic-gate 	-1,
72*7c478bd9Sstevel@tonic-gate 	-1,
73*7c478bd9Sstevel@tonic-gate 	-1,
74*7c478bd9Sstevel@tonic-gate 	-1,
75*7c478bd9Sstevel@tonic-gate 	FDTYPE_ByteArray,
76*7c478bd9Sstevel@tonic-gate 	FDISP_Hex,
77*7c478bd9Sstevel@tonic-gate 	FRU_WHICH_UNDEFINED,
78*7c478bd9Sstevel@tonic-gate 	FRU_WHICH_UNDEFINED,
79*7c478bd9Sstevel@tonic-gate 	0,
80*7c478bd9Sstevel@tonic-gate 	NULL,
81*7c478bd9Sstevel@tonic-gate 	0,
82*7c478bd9Sstevel@tonic-gate 	FRU_NOT_ITERATED,
83*7c478bd9Sstevel@tonic-gate 	NULL
84*7c478bd9Sstevel@tonic-gate };
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /*
88*7c478bd9Sstevel@tonic-gate  * Write message to standard error and possibly the error log buffer
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate static void
91*7c478bd9Sstevel@tonic-gate error(const char *format, ...)
92*7c478bd9Sstevel@tonic-gate {
93*7c478bd9Sstevel@tonic-gate 	va_list	args;
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	/* make relevant output appear before error message */
97*7c478bd9Sstevel@tonic-gate 	if (fflush(stdout) == EOF) {
98*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Error flushing output:  %s\n",
99*7c478bd9Sstevel@tonic-gate 				strerror(errno));
100*7c478bd9Sstevel@tonic-gate 		exit(1);
101*7c478bd9Sstevel@tonic-gate 	}
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
104*7c478bd9Sstevel@tonic-gate 	if (vfprintf(stderr, format, args) < 0) exit(1);
105*7c478bd9Sstevel@tonic-gate 	if (errlog && (vfprintf(errlog, format, args) < 0)) exit(1);
106*7c478bd9Sstevel@tonic-gate }
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /*
109*7c478bd9Sstevel@tonic-gate  * Write message to standard output
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate static void
112*7c478bd9Sstevel@tonic-gate output(const char *format, ...)
113*7c478bd9Sstevel@tonic-gate {
114*7c478bd9Sstevel@tonic-gate 	va_list   args;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	va_start(args, format);
118*7c478bd9Sstevel@tonic-gate 	if (vfprintf(stdout, format, args) < 0) {
119*7c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
120*7c478bd9Sstevel@tonic-gate 			strerror(errno));
121*7c478bd9Sstevel@tonic-gate 		exit(1);
122*7c478bd9Sstevel@tonic-gate 	}
123*7c478bd9Sstevel@tonic-gate }
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate /*
126*7c478bd9Sstevel@tonic-gate  * Safe wrapper for putchar()
127*7c478bd9Sstevel@tonic-gate  */
128*7c478bd9Sstevel@tonic-gate static void
129*7c478bd9Sstevel@tonic-gate voidputchar(int c)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	if (putchar(c) == EOF) {
132*7c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
133*7c478bd9Sstevel@tonic-gate 			strerror(errno));
134*7c478bd9Sstevel@tonic-gate 		exit(1);
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate }
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate static void  (*safeputchar)(int c) = voidputchar;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * Safe wrapper for puts()
142*7c478bd9Sstevel@tonic-gate  */
143*7c478bd9Sstevel@tonic-gate static void
144*7c478bd9Sstevel@tonic-gate voidputs(const char *s)
145*7c478bd9Sstevel@tonic-gate {
146*7c478bd9Sstevel@tonic-gate 	if (fputs(s, stdout) == EOF) {
147*7c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
148*7c478bd9Sstevel@tonic-gate 			strerror(errno));
149*7c478bd9Sstevel@tonic-gate 		exit(1);
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate static void  (*safeputs)(const char *s) = voidputs;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate /*
156*7c478bd9Sstevel@tonic-gate  * XML-safe wrapper for putchar():  quotes XML-special characters
157*7c478bd9Sstevel@tonic-gate  */
158*7c478bd9Sstevel@tonic-gate static void
159*7c478bd9Sstevel@tonic-gate xputchar(int c)
160*7c478bd9Sstevel@tonic-gate {
161*7c478bd9Sstevel@tonic-gate 	switch (c) {
162*7c478bd9Sstevel@tonic-gate 	case '<':
163*7c478bd9Sstevel@tonic-gate 		c = fputs("&lt;", stdout);
164*7c478bd9Sstevel@tonic-gate 		break;
165*7c478bd9Sstevel@tonic-gate 	case '>':
166*7c478bd9Sstevel@tonic-gate 		c = fputs("&gt;", stdout);
167*7c478bd9Sstevel@tonic-gate 		break;
168*7c478bd9Sstevel@tonic-gate 	case '&':
169*7c478bd9Sstevel@tonic-gate 		c = fputs("&amp;", stdout);
170*7c478bd9Sstevel@tonic-gate 		break;
171*7c478bd9Sstevel@tonic-gate 	case '"':
172*7c478bd9Sstevel@tonic-gate 		c = fputs("&quot;", stdout);
173*7c478bd9Sstevel@tonic-gate 		break;
174*7c478bd9Sstevel@tonic-gate 	default:
175*7c478bd9Sstevel@tonic-gate 		c = putchar(c);
176*7c478bd9Sstevel@tonic-gate 		break;
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	if (c == EOF) {
180*7c478bd9Sstevel@tonic-gate 		error(gettext("Error writing output:  %s\n"),
181*7c478bd9Sstevel@tonic-gate 			strerror(errno));
182*7c478bd9Sstevel@tonic-gate 		exit(1);
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate /*
187*7c478bd9Sstevel@tonic-gate  * XML-safe analog of puts():  quotes XML-special characters
188*7c478bd9Sstevel@tonic-gate  */
189*7c478bd9Sstevel@tonic-gate static void
190*7c478bd9Sstevel@tonic-gate xputs(const char *s)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	char c;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	for (/* */; ((c = *s) != 0); s++)
195*7c478bd9Sstevel@tonic-gate 		xputchar(c);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate  * Output the XML DTD derived from the registry provided by libfrureg
200*7c478bd9Sstevel@tonic-gate  */
201*7c478bd9Sstevel@tonic-gate int
202*7c478bd9Sstevel@tonic-gate output_dtd(void)
203*7c478bd9Sstevel@tonic-gate {
204*7c478bd9Sstevel@tonic-gate 	char			**element;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	unsigned int		i, j, num_elements = 0;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	uint8_t			*tagged;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	const fru_regdef_t	*def;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	if (((element = fru_reg_list_entries(&num_elements)) == NULL) ||
214*7c478bd9Sstevel@tonic-gate 	    (num_elements == 0)) {
215*7c478bd9Sstevel@tonic-gate 		error(gettext("No FRU ID Registry elements"));
216*7c478bd9Sstevel@tonic-gate 		return (1);
217*7c478bd9Sstevel@tonic-gate 	}
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	if ((tagged = calloc(num_elements, sizeof (*tagged))) == NULL) {
220*7c478bd9Sstevel@tonic-gate 		error(gettext("Unable to get memory for tagged element list"),
221*7c478bd9Sstevel@tonic-gate 			strerror(errno));
222*7c478bd9Sstevel@tonic-gate 		return (1);
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	/*
226*7c478bd9Sstevel@tonic-gate 	 * Output the DTD preamble
227*7c478bd9Sstevel@tonic-gate 	 */
228*7c478bd9Sstevel@tonic-gate 	output("<!ELEMENT FRUID_XML_Tree (Parameter*, "
229*7c478bd9Sstevel@tonic-gate 	    "(Fru | Location | Container)*,\n"
230*7c478bd9Sstevel@tonic-gate 	    "                          Parameter*, ErrorLog?, Parameter*)>\n"
231*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST FRUID_XML_Tree>\n"
232*7c478bd9Sstevel@tonic-gate 	    "\n"
233*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Parameter EMPTY>\n"
234*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter type CDATA #REQUIRED>\n"
235*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter name CDATA #REQUIRED>\n"
236*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Parameter value CDATA #REQUIRED>\n"
237*7c478bd9Sstevel@tonic-gate 	    "\n"
238*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Fru (Fru | Location | Container)*>\n"
239*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Fru name CDATA #REQUIRED>\n"
240*7c478bd9Sstevel@tonic-gate 	    "\n"
241*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Location (Fru | Location | Container)*>\n"
242*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Location name CDATA #REQUIRED>\n"
243*7c478bd9Sstevel@tonic-gate 	    "\n"
244*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Container (ContainerData?, "
245*7c478bd9Sstevel@tonic-gate 	    "(Fru | Location | Container)*)>\n"
246*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Container name CDATA #REQUIRED>\n"
247*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Container imagefile CDATA #IMPLIED>\n"
248*7c478bd9Sstevel@tonic-gate 	    "\n"
249*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT ContainerData (Segment*)>\n"
250*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST ContainerData>\n"
251*7c478bd9Sstevel@tonic-gate 	    "\n"
252*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Segment name CDATA #REQUIRED>\n"
253*7c478bd9Sstevel@tonic-gate 	    "\n"
254*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT Index EMPTY>\n"
255*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST Index value CDATA #REQUIRED>\n"
256*7c478bd9Sstevel@tonic-gate 	    "\n"
257*7c478bd9Sstevel@tonic-gate 	    "<!ELEMENT ErrorLog (#PCDATA)>\n"
258*7c478bd9Sstevel@tonic-gate 	    "<!ATTLIST ErrorLog>\n"
259*7c478bd9Sstevel@tonic-gate 	    "\n");
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	/*
262*7c478bd9Sstevel@tonic-gate 	 * Output the definition for each element
263*7c478bd9Sstevel@tonic-gate 	 */
264*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_elements; i++) {
265*7c478bd9Sstevel@tonic-gate 		assert(element[i] != NULL);
266*7c478bd9Sstevel@tonic-gate 		if ((def = fru_reg_lookup_def_by_name(element[i])) == NULL) {
267*7c478bd9Sstevel@tonic-gate 			error(gettext("Error looking up registry "
268*7c478bd9Sstevel@tonic-gate 					"definition for \"%s\"\n"),
269*7c478bd9Sstevel@tonic-gate 				element[i]);
270*7c478bd9Sstevel@tonic-gate 			return (1);
271*7c478bd9Sstevel@tonic-gate 		}
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		if (def->tagType != FRU_X) tagged[i] = 1;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 		if (def->dataType == FDTYPE_Record) {
276*7c478bd9Sstevel@tonic-gate 			if (def->iterationType == FRU_NOT_ITERATED)
277*7c478bd9Sstevel@tonic-gate 				output("<!ELEMENT %s (%s", element[i],
278*7c478bd9Sstevel@tonic-gate 				    def->enumTable[0].text);
279*7c478bd9Sstevel@tonic-gate 			else
280*7c478bd9Sstevel@tonic-gate 				output("<!ELEMENT %s (Index_%s*)>\n"
281*7c478bd9Sstevel@tonic-gate 				    "<!ATTLIST Index_%s>\n"
282*7c478bd9Sstevel@tonic-gate 				    "<!ELEMENT Index_%s (%s",
283*7c478bd9Sstevel@tonic-gate 				    element[i], element[i], element[i],
284*7c478bd9Sstevel@tonic-gate 				    element[i], def->enumTable[0].text);
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 			for (j = 1; j < def->enumCount; j++)
287*7c478bd9Sstevel@tonic-gate 				output(",\n\t%s", def->enumTable[j].text);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 			output(")>\n");
290*7c478bd9Sstevel@tonic-gate 		} else if (def->iterationType == FRU_NOT_ITERATED) {
291*7c478bd9Sstevel@tonic-gate 			output("<!ELEMENT %s EMPTY>\n"
292*7c478bd9Sstevel@tonic-gate 			    "<!ATTLIST %s value CDATA #REQUIRED>\n",
293*7c478bd9Sstevel@tonic-gate 			    element[i], element[i]);
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 			if (def->dataType == FDTYPE_Enumeration) {
296*7c478bd9Sstevel@tonic-gate 				output("<!-- %s valid enumeration values\n");
297*7c478bd9Sstevel@tonic-gate 				for (j = 0; j < def->enumCount; j++) {
298*7c478bd9Sstevel@tonic-gate 					output("\t\"");
299*7c478bd9Sstevel@tonic-gate 					xputs(def->enumTable[j].text);
300*7c478bd9Sstevel@tonic-gate 					output("\"\n");
301*7c478bd9Sstevel@tonic-gate 				}
302*7c478bd9Sstevel@tonic-gate 				output("-->\n");
303*7c478bd9Sstevel@tonic-gate 			}
304*7c478bd9Sstevel@tonic-gate 		}
305*7c478bd9Sstevel@tonic-gate 		else
306*7c478bd9Sstevel@tonic-gate 			output("<!ELEMENT %s (Index*)>\n", element[i]);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 		output("\n");
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/* Provide for returning the tag for an "unknown" element */
312*7c478bd9Sstevel@tonic-gate 	output("<!ATTLIST UNKNOWN tag CDATA \"UNKNOWN\">\n\n");
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/*
316*7c478bd9Sstevel@tonic-gate 	 * List all data elements as possible members of "Segment"
317*7c478bd9Sstevel@tonic-gate 	 */
318*7c478bd9Sstevel@tonic-gate 	output("<!ELEMENT Segment ((UNKNOWN");
319*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_elements; i++) {
320*7c478bd9Sstevel@tonic-gate 		if (tagged[i]) output("\n\t| %s", element[i]);
321*7c478bd9Sstevel@tonic-gate 		free(element[i]);
322*7c478bd9Sstevel@tonic-gate 	}
323*7c478bd9Sstevel@tonic-gate 	output(")*)>\n");
324*7c478bd9Sstevel@tonic-gate 	free(element);
325*7c478bd9Sstevel@tonic-gate 	free(tagged);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	return (0);
328*7c478bd9Sstevel@tonic-gate }
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate /*
331*7c478bd9Sstevel@tonic-gate  * Safely pretty-print the value of a field
332*7c478bd9Sstevel@tonic-gate  */
333*7c478bd9Sstevel@tonic-gate static void
334*7c478bd9Sstevel@tonic-gate print_field(const uint8_t *field, const fru_regdef_t *def)
335*7c478bd9Sstevel@tonic-gate {
336*7c478bd9Sstevel@tonic-gate 	char		*errmsg = NULL, timestring[TIMESTRINGLEN];
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	int		i;
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	uint64_t	value;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	time_t		timefield;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	switch (def->dataType) {
346*7c478bd9Sstevel@tonic-gate 	case FDTYPE_Binary:
347*7c478bd9Sstevel@tonic-gate 		assert(def->payloadLen <= sizeof (value));
348*7c478bd9Sstevel@tonic-gate 		switch (def->dispType) {
349*7c478bd9Sstevel@tonic-gate 		case FDISP_Binary:
350*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < def->payloadLen; i++)
351*7c478bd9Sstevel@tonic-gate 				output("%c%c%c%c%c%c%c%c",
352*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x80) ? '1' : '0'),
353*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x40) ? '1' : '0'),
354*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x20) ? '1' : '0'),
355*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x10) ? '1' : '0'),
356*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x08) ? '1' : '0'),
357*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x04) ? '1' : '0'),
358*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x02) ? '1' : '0'),
359*7c478bd9Sstevel@tonic-gate 				    ((field[i] & 0x01) ? '1' : '0'));
360*7c478bd9Sstevel@tonic-gate 			return;
361*7c478bd9Sstevel@tonic-gate 		case FDISP_Octal:
362*7c478bd9Sstevel@tonic-gate 		case FDISP_Decimal:
363*7c478bd9Sstevel@tonic-gate 			value = 0;
364*7c478bd9Sstevel@tonic-gate 			(void) memcpy((((uint8_t *)&value) +
365*7c478bd9Sstevel@tonic-gate 					sizeof (value) - def->payloadLen),
366*7c478bd9Sstevel@tonic-gate 					field, def->payloadLen);
367*7c478bd9Sstevel@tonic-gate 			output((def->dispType == FDISP_Octal) ?
368*7c478bd9Sstevel@tonic-gate 				"%llo" : "%lld", value);
369*7c478bd9Sstevel@tonic-gate 			return;
370*7c478bd9Sstevel@tonic-gate 		case FDISP_Time:
371*7c478bd9Sstevel@tonic-gate 			if (def->payloadLen > sizeof (timefield)) {
372*7c478bd9Sstevel@tonic-gate 				errmsg = "time value too large for formatting";
373*7c478bd9Sstevel@tonic-gate 				break;
374*7c478bd9Sstevel@tonic-gate 			}
375*7c478bd9Sstevel@tonic-gate 			(void) memcpy(&timefield, field, sizeof (timefield));
376*7c478bd9Sstevel@tonic-gate 			if (strftime(timestring, sizeof (timestring), "%C",
377*7c478bd9Sstevel@tonic-gate 					localtime(&timefield)) == 0) {
378*7c478bd9Sstevel@tonic-gate 				errmsg = "formatted time would overflow buffer";
379*7c478bd9Sstevel@tonic-gate 				break;
380*7c478bd9Sstevel@tonic-gate 			}
381*7c478bd9Sstevel@tonic-gate 			safeputs(timestring);
382*7c478bd9Sstevel@tonic-gate 			return;
383*7c478bd9Sstevel@tonic-gate 		}
384*7c478bd9Sstevel@tonic-gate 		break;
385*7c478bd9Sstevel@tonic-gate 	case FDTYPE_ASCII:
386*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->payloadLen && field[i]; i++)
387*7c478bd9Sstevel@tonic-gate 			safeputchar(field[i]);
388*7c478bd9Sstevel@tonic-gate 		return;
389*7c478bd9Sstevel@tonic-gate 	case FDTYPE_Enumeration:
390*7c478bd9Sstevel@tonic-gate 		value = 0;
391*7c478bd9Sstevel@tonic-gate 		(void) memcpy((((uint8_t *)&value) + sizeof (value)
392*7c478bd9Sstevel@tonic-gate 					- def->payloadLen),
393*7c478bd9Sstevel@tonic-gate 					field, def->payloadLen);
394*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->enumCount; i++)
395*7c478bd9Sstevel@tonic-gate 			if (def->enumTable[i].value == value) {
396*7c478bd9Sstevel@tonic-gate 				safeputs(def->enumTable[i].text);
397*7c478bd9Sstevel@tonic-gate 				return;
398*7c478bd9Sstevel@tonic-gate 			}
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 		errmsg = "unrecognized value";
401*7c478bd9Sstevel@tonic-gate 		break;
402*7c478bd9Sstevel@tonic-gate 	}
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate 	/* If nothing matched above, print the field in hex */
405*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < def->payloadLen; i++)
406*7c478bd9Sstevel@tonic-gate 		output("%2.2X", field[i]);
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	/* Safely print any error message associated with the field */
409*7c478bd9Sstevel@tonic-gate 	if (errmsg) {
410*7c478bd9Sstevel@tonic-gate 		output(" (");
411*7c478bd9Sstevel@tonic-gate 		safeputs(errmsg);
412*7c478bd9Sstevel@tonic-gate 		output(")\n");
413*7c478bd9Sstevel@tonic-gate 	}
414*7c478bd9Sstevel@tonic-gate }
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate /*
417*7c478bd9Sstevel@tonic-gate  * Recursively print the contents of a data element
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate static void
420*7c478bd9Sstevel@tonic-gate print_element(const uint8_t *data, const fru_regdef_t *def,
421*7c478bd9Sstevel@tonic-gate     const char *parent_path, int indent)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	char	*path;
424*7c478bd9Sstevel@tonic-gate 	size_t	len;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	int	bytes = 0, i;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	indent = (xml) ? (indent + INDENT) : (2*INDENT);
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	/*
432*7c478bd9Sstevel@tonic-gate 	 * Construct the path, or, for XML, the name, for the current
433*7c478bd9Sstevel@tonic-gate 	 * data element
434*7c478bd9Sstevel@tonic-gate 	 */
435*7c478bd9Sstevel@tonic-gate 	if ((def->iterationCount == 0) &&
436*7c478bd9Sstevel@tonic-gate 	    (def->iterationType != FRU_NOT_ITERATED)) {
437*7c478bd9Sstevel@tonic-gate 		if (xml) {
438*7c478bd9Sstevel@tonic-gate 			if (def->dataType == FDTYPE_Record) {
439*7c478bd9Sstevel@tonic-gate 				len = strlen("Index_") + strlen(def->name) + 1;
440*7c478bd9Sstevel@tonic-gate 				path = alloca(len);
441*7c478bd9Sstevel@tonic-gate 				(void) snprintf(path, len,
442*7c478bd9Sstevel@tonic-gate 				    "Index_%s", def->name);
443*7c478bd9Sstevel@tonic-gate 			}
444*7c478bd9Sstevel@tonic-gate 			else
445*7c478bd9Sstevel@tonic-gate 				path = "Index";
446*7c478bd9Sstevel@tonic-gate 		}
447*7c478bd9Sstevel@tonic-gate 		else
448*7c478bd9Sstevel@tonic-gate 			path = (char *)parent_path;
449*7c478bd9Sstevel@tonic-gate 	} else {
450*7c478bd9Sstevel@tonic-gate 		if (xml)
451*7c478bd9Sstevel@tonic-gate 			path = (char *)def->name;
452*7c478bd9Sstevel@tonic-gate 		else {
453*7c478bd9Sstevel@tonic-gate 			len = strlen(parent_path) + sizeof ("/") +
454*7c478bd9Sstevel@tonic-gate 			    strlen(def->name) +
455*7c478bd9Sstevel@tonic-gate 			    (def->iterationCount ? sizeof ("[255]") : 0);
456*7c478bd9Sstevel@tonic-gate 			path = alloca(len);
457*7c478bd9Sstevel@tonic-gate 			bytes = snprintf(path, len,
458*7c478bd9Sstevel@tonic-gate 			    "%s/%s", parent_path, def->name);
459*7c478bd9Sstevel@tonic-gate 		}
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	/*
463*7c478bd9Sstevel@tonic-gate 	 * Handle the various categories of data elements:  iteration,
464*7c478bd9Sstevel@tonic-gate 	 * record, and field
465*7c478bd9Sstevel@tonic-gate 	 */
466*7c478bd9Sstevel@tonic-gate 	if (def->iterationCount) {
467*7c478bd9Sstevel@tonic-gate 		int		iterlen = (def->payloadLen - NUM_ITER_BYTES)/
468*7c478bd9Sstevel@tonic-gate 						def->iterationCount,
469*7c478bd9Sstevel@tonic-gate 				n, valid = 1;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 		uint8_t		head, num;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 		fru_regdef_t	newdef;
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 		/*
477*7c478bd9Sstevel@tonic-gate 		 * Make a new element definition to describe the components
478*7c478bd9Sstevel@tonic-gate 		 * of the iteration
479*7c478bd9Sstevel@tonic-gate 		 */
480*7c478bd9Sstevel@tonic-gate 		(void) memcpy(&newdef, def, sizeof (newdef));
481*7c478bd9Sstevel@tonic-gate 		newdef.iterationCount = 0;
482*7c478bd9Sstevel@tonic-gate 		newdef.payloadLen = iterlen;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 		/*
485*7c478bd9Sstevel@tonic-gate 		 * Validate the contents of the iteration control bytes
486*7c478bd9Sstevel@tonic-gate 		 */
487*7c478bd9Sstevel@tonic-gate 		if (data[HEAD_ITER] >= def->iterationCount) {
488*7c478bd9Sstevel@tonic-gate 			valid = 0;
489*7c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration head:  %d "
490*7c478bd9Sstevel@tonic-gate 			    "(should be less than %d)\n"),
491*7c478bd9Sstevel@tonic-gate 			    path, data[HEAD_ITER], def->iterationCount);
492*7c478bd9Sstevel@tonic-gate 		}
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 		if (data[NUM_ITER] > def->iterationCount) {
495*7c478bd9Sstevel@tonic-gate 			valid = 0;
496*7c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration count:  %d "
497*7c478bd9Sstevel@tonic-gate 			    "(should not be greater than %d)\n"),
498*7c478bd9Sstevel@tonic-gate 			    path, data[NUM_ITER], def->iterationCount);
499*7c478bd9Sstevel@tonic-gate 		}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 		if (data[MAX_ITER] != def->iterationCount) {
502*7c478bd9Sstevel@tonic-gate 			valid = 0;
503*7c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Invalid iteration maximum:  %d "
504*7c478bd9Sstevel@tonic-gate 			    "(should equal %d)\n"),
505*7c478bd9Sstevel@tonic-gate 			    path, data[MAX_ITER], def->iterationCount);
506*7c478bd9Sstevel@tonic-gate 		}
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 		if (valid) {
509*7c478bd9Sstevel@tonic-gate 			head = data[HEAD_ITER];
510*7c478bd9Sstevel@tonic-gate 			num  = data[NUM_ITER];
511*7c478bd9Sstevel@tonic-gate 		} else {
512*7c478bd9Sstevel@tonic-gate 			head = 0;
513*7c478bd9Sstevel@tonic-gate 			num  = def->iterationCount;
514*7c478bd9Sstevel@tonic-gate 			error(gettext("%s:  Showing all iterations\n"), path);
515*7c478bd9Sstevel@tonic-gate 		}
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 		if (xml)
518*7c478bd9Sstevel@tonic-gate 			output("%*s<%s>\n", indent, "", path);
519*7c478bd9Sstevel@tonic-gate 		else
520*7c478bd9Sstevel@tonic-gate 			output("%*s%s (%d iterations)\n", indent, "", path,
521*7c478bd9Sstevel@tonic-gate 				num);
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 		/*
524*7c478bd9Sstevel@tonic-gate 		 * Print each component of the iteration
525*7c478bd9Sstevel@tonic-gate 		 */
526*7c478bd9Sstevel@tonic-gate 		for (i = head, n = 0, data += 4;
527*7c478bd9Sstevel@tonic-gate 				n < num;
528*7c478bd9Sstevel@tonic-gate 				i = ((i + 1) % def->iterationCount), n++) {
529*7c478bd9Sstevel@tonic-gate 			if (!xml) (void) sprintf((path + bytes), "[%d]", n);
530*7c478bd9Sstevel@tonic-gate 			print_element((data + i*iterlen), &newdef, path,
531*7c478bd9Sstevel@tonic-gate 					indent);
532*7c478bd9Sstevel@tonic-gate 		}
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 		if (xml) output("%*s</%s>\n", indent, "", path);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	} else if (def->dataType == FDTYPE_Record) {
537*7c478bd9Sstevel@tonic-gate 		const fru_regdef_t  *component;
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 		if (xml)
540*7c478bd9Sstevel@tonic-gate 			output("%*s<%s>\n", indent, "", path);
541*7c478bd9Sstevel@tonic-gate 		else
542*7c478bd9Sstevel@tonic-gate 			output("%*s%s\n", indent, "", path);
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 		/*
545*7c478bd9Sstevel@tonic-gate 		 * Print each component of the record
546*7c478bd9Sstevel@tonic-gate 		 */
547*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < def->enumCount;
548*7c478bd9Sstevel@tonic-gate 				i++, data += component->payloadLen) {
549*7c478bd9Sstevel@tonic-gate 			component = fru_reg_lookup_def_by_name(
550*7c478bd9Sstevel@tonic-gate 				def->enumTable[i].text);
551*7c478bd9Sstevel@tonic-gate 			assert(component != NULL);
552*7c478bd9Sstevel@tonic-gate 			print_element(data, component, path, indent);
553*7c478bd9Sstevel@tonic-gate 		}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 		if (xml) output("%*s</%s>\n", indent, "", path);
556*7c478bd9Sstevel@tonic-gate 	} else if (xml) {
557*7c478bd9Sstevel@tonic-gate 		/*
558*7c478bd9Sstevel@tonic-gate 		 * Base case:  print the field formatted for XML
559*7c478bd9Sstevel@tonic-gate 		 */
560*7c478bd9Sstevel@tonic-gate 		char  *format = ((def == &unknown)
561*7c478bd9Sstevel@tonic-gate 		    ? "%*s<UNKNOWN tag=\"%s\" value=\""
562*7c478bd9Sstevel@tonic-gate 		    : "%*s<%s value=\"");
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 		output(format, indent, "", path);
565*7c478bd9Sstevel@tonic-gate 		print_field(data, def);
566*7c478bd9Sstevel@tonic-gate 		/*CSTYLED*/
567*7c478bd9Sstevel@tonic-gate 		output("\"/>\n");	/* \" confuses cstyle */
568*7c478bd9Sstevel@tonic-gate 	} else {
569*7c478bd9Sstevel@tonic-gate 		/*
570*7c478bd9Sstevel@tonic-gate 		 * Base case:  print the field
571*7c478bd9Sstevel@tonic-gate 		 */
572*7c478bd9Sstevel@tonic-gate 		output("%*s%s: ", indent, "", path);
573*7c478bd9Sstevel@tonic-gate 		print_field(data, def);
574*7c478bd9Sstevel@tonic-gate 		output("\n");
575*7c478bd9Sstevel@tonic-gate 	}
576*7c478bd9Sstevel@tonic-gate }
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate /*
579*7c478bd9Sstevel@tonic-gate  * Print the contents of a packet (i.e., a tagged data element)
580*7c478bd9Sstevel@tonic-gate  */
581*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
582*7c478bd9Sstevel@tonic-gate static int
583*7c478bd9Sstevel@tonic-gate print_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args)
584*7c478bd9Sstevel@tonic-gate {
585*7c478bd9Sstevel@tonic-gate 	int			tag_type = get_tag_type(tag);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	size_t			payload_length = 0;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	const fru_regdef_t	*def;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	/*
593*7c478bd9Sstevel@tonic-gate 	 * Build a definition for unrecognized tags (e.g., not in libfrureg)
594*7c478bd9Sstevel@tonic-gate 	 */
595*7c478bd9Sstevel@tonic-gate 	if ((tag_type == -1) ||
596*7c478bd9Sstevel@tonic-gate 	    ((payload_length = get_payload_length(tag)) != length)) {
597*7c478bd9Sstevel@tonic-gate 		def = &unknown;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 		unknown.tagType    = -1;
600*7c478bd9Sstevel@tonic-gate 		unknown.tagDense   = -1;
601*7c478bd9Sstevel@tonic-gate 		unknown.payloadLen = length;
602*7c478bd9Sstevel@tonic-gate 		unknown.dataLength = unknown.payloadLen;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 		if (tag_type == -1)
605*7c478bd9Sstevel@tonic-gate 			(void) snprintf(tagname, sizeof (tagname), "INVALID");
606*7c478bd9Sstevel@tonic-gate 		else
607*7c478bd9Sstevel@tonic-gate 			(void) snprintf(tagname, sizeof (tagname),
608*7c478bd9Sstevel@tonic-gate 			    "%s_%u_%u_%u", get_tagtype_str(tag_type),
609*7c478bd9Sstevel@tonic-gate 			    get_tag_dense(tag), payload_length, length);
610*7c478bd9Sstevel@tonic-gate 	} else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) {
611*7c478bd9Sstevel@tonic-gate 		def = &unknown;
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 		unknown.tagType    = tag_type;
614*7c478bd9Sstevel@tonic-gate 		unknown.tagDense   = get_tag_dense(tag);
615*7c478bd9Sstevel@tonic-gate 		unknown.payloadLen = payload_length;
616*7c478bd9Sstevel@tonic-gate 		unknown.dataLength = unknown.payloadLen;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 		(void) snprintf(tagname, sizeof (tagname), "%s_%u_%u",
619*7c478bd9Sstevel@tonic-gate 		    get_tagtype_str(unknown.tagType),
620*7c478bd9Sstevel@tonic-gate 		    unknown.tagDense, payload_length);
621*7c478bd9Sstevel@tonic-gate 	}
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	/*
625*7c478bd9Sstevel@tonic-gate 	 * Print the defined element
626*7c478bd9Sstevel@tonic-gate 	 */
627*7c478bd9Sstevel@tonic-gate 	print_element(payload, def, "", INDENT);
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
630*7c478bd9Sstevel@tonic-gate }
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate /*
633*7c478bd9Sstevel@tonic-gate  * Print a segment's name and the contents of each data element in the segment
634*7c478bd9Sstevel@tonic-gate  */
635*7c478bd9Sstevel@tonic-gate static int
636*7c478bd9Sstevel@tonic-gate print_packets_in_segment(fru_seghdl_t segment, void *args)
637*7c478bd9Sstevel@tonic-gate {
638*7c478bd9Sstevel@tonic-gate 	char	*name;
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	int	status;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	if ((status = fru_get_segment_name(segment, &name)) != FRU_SUCCESS) {
644*7c478bd9Sstevel@tonic-gate 		saved_status = status;
645*7c478bd9Sstevel@tonic-gate 		name = "";
646*7c478bd9Sstevel@tonic-gate 		error(gettext("Error getting segment name:  %s\n"),
647*7c478bd9Sstevel@tonic-gate 		    fru_strerror(status));
648*7c478bd9Sstevel@tonic-gate 	}
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	if (xml)
652*7c478bd9Sstevel@tonic-gate 		output("%*s<Segment name=\"%s\">\n", INDENT, "", name);
653*7c478bd9Sstevel@tonic-gate 	else
654*7c478bd9Sstevel@tonic-gate 		output("%*sSEGMENT: %s\n", INDENT, "", name);
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	/* Iterate over the packets in the segment, printing the contents */
657*7c478bd9Sstevel@tonic-gate 	if ((status = fru_for_each_packet(segment, print_packet, args))
658*7c478bd9Sstevel@tonic-gate 	    != FRU_SUCCESS) {
659*7c478bd9Sstevel@tonic-gate 		saved_status = status;
660*7c478bd9Sstevel@tonic-gate 		error(gettext("Error processing data in segment \"%s\":  %s\n"),
661*7c478bd9Sstevel@tonic-gate 			name, fru_strerror(status));
662*7c478bd9Sstevel@tonic-gate 	}
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	if (xml) output("%*s</Segment>\n", INDENT, "");
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	free(name);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
669*7c478bd9Sstevel@tonic-gate }
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
672*7c478bd9Sstevel@tonic-gate static void
673*7c478bd9Sstevel@tonic-gate print_node_path(fru_node_t fru_type, const char *path, const char *name,
674*7c478bd9Sstevel@tonic-gate     end_node_fp_t *end_node, void **end_args)
675*7c478bd9Sstevel@tonic-gate {
676*7c478bd9Sstevel@tonic-gate 	output("%s%s\n", path,
677*7c478bd9Sstevel@tonic-gate 	    ((fru_type == FRU_NODE_CONTAINER) ? " (container)"
678*7c478bd9Sstevel@tonic-gate 		: ((fru_type == FRU_NODE_FRU) ? " (fru)" : "")));
679*7c478bd9Sstevel@tonic-gate }
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate /*
682*7c478bd9Sstevel@tonic-gate  * Close the XML element for a "location" node
683*7c478bd9Sstevel@tonic-gate  */
684*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
685*7c478bd9Sstevel@tonic-gate static void
686*7c478bd9Sstevel@tonic-gate end_location_xml(fru_nodehdl_t node, const char *path, const char *name,
687*7c478bd9Sstevel@tonic-gate     void *args)
688*7c478bd9Sstevel@tonic-gate {
689*7c478bd9Sstevel@tonic-gate 	assert(args != NULL);
690*7c478bd9Sstevel@tonic-gate 	output("</Location> <!-- %s -->\n", args);
691*7c478bd9Sstevel@tonic-gate }
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate /*
694*7c478bd9Sstevel@tonic-gate  * Close the XML element for a "fru" node
695*7c478bd9Sstevel@tonic-gate  */
696*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
697*7c478bd9Sstevel@tonic-gate static void
698*7c478bd9Sstevel@tonic-gate end_fru_xml(fru_nodehdl_t node, const char *path, const char *name, void *args)
699*7c478bd9Sstevel@tonic-gate {
700*7c478bd9Sstevel@tonic-gate 	assert(args != NULL);
701*7c478bd9Sstevel@tonic-gate 	output("</Fru> <!-- %s -->\n", args);
702*7c478bd9Sstevel@tonic-gate }
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate /*
705*7c478bd9Sstevel@tonic-gate  * Close the XML element for a "container" node
706*7c478bd9Sstevel@tonic-gate  */
707*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
708*7c478bd9Sstevel@tonic-gate static void
709*7c478bd9Sstevel@tonic-gate end_container_xml(fru_nodehdl_t node, const char *path, const char *name,
710*7c478bd9Sstevel@tonic-gate     void *args)
711*7c478bd9Sstevel@tonic-gate {
712*7c478bd9Sstevel@tonic-gate 	assert(args != NULL);
713*7c478bd9Sstevel@tonic-gate 	output("</Container> <!-- %s -->\n", args);
714*7c478bd9Sstevel@tonic-gate }
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate /*
717*7c478bd9Sstevel@tonic-gate  * Introduce a node in XML and set the appropriate node-closing function
718*7c478bd9Sstevel@tonic-gate  */
719*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
720*7c478bd9Sstevel@tonic-gate static void
721*7c478bd9Sstevel@tonic-gate print_node_xml(fru_node_t fru_type, const char *path, const char *name,
722*7c478bd9Sstevel@tonic-gate     end_node_fp_t *end_node, void **end_args)
723*7c478bd9Sstevel@tonic-gate {
724*7c478bd9Sstevel@tonic-gate 	switch (fru_type) {
725*7c478bd9Sstevel@tonic-gate 	case FRU_NODE_FRU:
726*7c478bd9Sstevel@tonic-gate 		output("<Fru name=\"%s\">\n", name);
727*7c478bd9Sstevel@tonic-gate 		*end_node = end_fru_xml;
728*7c478bd9Sstevel@tonic-gate 		break;
729*7c478bd9Sstevel@tonic-gate 	case FRU_NODE_CONTAINER:
730*7c478bd9Sstevel@tonic-gate 		output("<Container name=\"%s\">\n", name);
731*7c478bd9Sstevel@tonic-gate 		*end_node = end_container_xml;
732*7c478bd9Sstevel@tonic-gate 		break;
733*7c478bd9Sstevel@tonic-gate 	default:
734*7c478bd9Sstevel@tonic-gate 		output("<Location name=\"%s\">\n", name);
735*7c478bd9Sstevel@tonic-gate 		*end_node = end_location_xml;
736*7c478bd9Sstevel@tonic-gate 		break;
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	*end_args = (void *) name;
740*7c478bd9Sstevel@tonic-gate }
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate /*
743*7c478bd9Sstevel@tonic-gate  * Print node info and, where appropriate, node contents
744*7c478bd9Sstevel@tonic-gate  */
745*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
746*7c478bd9Sstevel@tonic-gate static fru_errno_t
747*7c478bd9Sstevel@tonic-gate process_node(fru_nodehdl_t node, const char *path, const char *name,
748*7c478bd9Sstevel@tonic-gate 		void *args, end_node_fp_t *end_node, void **end_args)
749*7c478bd9Sstevel@tonic-gate {
750*7c478bd9Sstevel@tonic-gate 	int		status;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	fru_node_t	fru_type = FRU_NODE_UNKNOWN;
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 	if ((status = fru_get_node_type(node, &fru_type)) != FRU_SUCCESS) {
756*7c478bd9Sstevel@tonic-gate 		saved_status = status;
757*7c478bd9Sstevel@tonic-gate 		error(gettext("Error getting node type:  %s\n"),
758*7c478bd9Sstevel@tonic-gate 			fru_strerror(status));
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	if (containers_only) {
762*7c478bd9Sstevel@tonic-gate 		if (fru_type != FRU_NODE_CONTAINER)
763*7c478bd9Sstevel@tonic-gate 			return (FRU_SUCCESS);
764*7c478bd9Sstevel@tonic-gate 		name = path;
765*7c478bd9Sstevel@tonic-gate 	}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	/* Introduce the node */
768*7c478bd9Sstevel@tonic-gate 	assert(print_node != NULL);
769*7c478bd9Sstevel@tonic-gate 	print_node(fru_type, path, name, end_node, end_args);
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	if (list_only)
772*7c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	/* Print the contents of each packet in each segment of a container */
775*7c478bd9Sstevel@tonic-gate 	if (fru_type == FRU_NODE_CONTAINER) {
776*7c478bd9Sstevel@tonic-gate 		if (xml) output("<ContainerData>\n");
777*7c478bd9Sstevel@tonic-gate 		if ((status =
778*7c478bd9Sstevel@tonic-gate 			fru_for_each_segment(node, print_packets_in_segment,
779*7c478bd9Sstevel@tonic-gate 						NULL))
780*7c478bd9Sstevel@tonic-gate 		    != FRU_SUCCESS) {
781*7c478bd9Sstevel@tonic-gate 			saved_status = status;
782*7c478bd9Sstevel@tonic-gate 			error(gettext("Error  processing node \"%s\":  %s\n"),
783*7c478bd9Sstevel@tonic-gate 				name, fru_strerror(status));
784*7c478bd9Sstevel@tonic-gate 		}
785*7c478bd9Sstevel@tonic-gate 		if (xml) output("</ContainerData>\n");
786*7c478bd9Sstevel@tonic-gate 	}
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
789*7c478bd9Sstevel@tonic-gate }
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate /*
792*7c478bd9Sstevel@tonic-gate  * Process the node if its path matches the search path in "args"
793*7c478bd9Sstevel@tonic-gate  */
794*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
795*7c478bd9Sstevel@tonic-gate static fru_errno_t
796*7c478bd9Sstevel@tonic-gate process_matching_node(fru_nodehdl_t node, const char *path, const char *name,
797*7c478bd9Sstevel@tonic-gate     void *args, end_node_fp_t *end_node, void **end_args)
798*7c478bd9Sstevel@tonic-gate {
799*7c478bd9Sstevel@tonic-gate 	int  status;
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	if (!fru_pathmatch(path, args))
803*7c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	status = process_node(node, path, path, args, end_node, end_args);
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	return ((status == FRU_SUCCESS) ? FRU_WALK_TERMINATE : status);
808*7c478bd9Sstevel@tonic-gate }
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate /*
811*7c478bd9Sstevel@tonic-gate  * Write the trailer required for well-formed DTD-compliant XML
812*7c478bd9Sstevel@tonic-gate  */
813*7c478bd9Sstevel@tonic-gate static void
814*7c478bd9Sstevel@tonic-gate terminate_xml()
815*7c478bd9Sstevel@tonic-gate {
816*7c478bd9Sstevel@tonic-gate 	errno = 0;
817*7c478bd9Sstevel@tonic-gate 	if (ftell(errlog) > 0) {
818*7c478bd9Sstevel@tonic-gate 		char  c;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 		output("<ErrorLog>\n");
821*7c478bd9Sstevel@tonic-gate 		rewind(errlog);
822*7c478bd9Sstevel@tonic-gate 		if (!errno)
823*7c478bd9Sstevel@tonic-gate 			while ((c = getc(errlog)) != EOF)
824*7c478bd9Sstevel@tonic-gate 				xputchar(c);
825*7c478bd9Sstevel@tonic-gate 		output("</ErrorLog>\n");
826*7c478bd9Sstevel@tonic-gate 	}
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	if (errno) {
829*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
830*7c478bd9Sstevel@tonic-gate 		errlog = NULL;
831*7c478bd9Sstevel@tonic-gate 		error(gettext("Error copying error messages to \"ErrorLog\""),
832*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	output("</FRUID_XML_Tree>\n");
836*7c478bd9Sstevel@tonic-gate }
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate /*
839*7c478bd9Sstevel@tonic-gate  * Print available FRU ID information
840*7c478bd9Sstevel@tonic-gate  */
841*7c478bd9Sstevel@tonic-gate int
842*7c478bd9Sstevel@tonic-gate prtfru(const char *searchpath, int containers_only_flag, int list_only_flag,
843*7c478bd9Sstevel@tonic-gate 	int xml_flag)
844*7c478bd9Sstevel@tonic-gate {
845*7c478bd9Sstevel@tonic-gate 	fru_errno_t    status;
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	fru_nodehdl_t  frutree = 0;
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	/* Copy parameter flags to global flags */
851*7c478bd9Sstevel@tonic-gate 	containers_only	= containers_only_flag;
852*7c478bd9Sstevel@tonic-gate 	list_only	= list_only_flag;
853*7c478bd9Sstevel@tonic-gate 	xml		= xml_flag;
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	/* Help arrange for correct, efficient interleaving of output */
857*7c478bd9Sstevel@tonic-gate 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	/* Initialize for XML--or not */
861*7c478bd9Sstevel@tonic-gate 	if (xml) {
862*7c478bd9Sstevel@tonic-gate 		safeputchar = xputchar;
863*7c478bd9Sstevel@tonic-gate 		safeputs    = xputs;
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate 		print_node  = print_node_xml;
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 		if ((errlog = tmpfile()) == NULL) {
868*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
869*7c478bd9Sstevel@tonic-gate 			    "Error creating error log file:  %s\n",
870*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
871*7c478bd9Sstevel@tonic-gate 			return (1);
872*7c478bd9Sstevel@tonic-gate 		}
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 		/* Output the XML preamble */
875*7c478bd9Sstevel@tonic-gate 		output("<?xml version=\"1.0\" ?>\n"
876*7c478bd9Sstevel@tonic-gate 		    "<!--\n"
877*7c478bd9Sstevel@tonic-gate 		    " Copyright 2000-2002 Sun Microsystems, Inc.  "
878*7c478bd9Sstevel@tonic-gate 		    "All rights reserved.\n"
879*7c478bd9Sstevel@tonic-gate 		    " Use is subject to license terms.\n"
880*7c478bd9Sstevel@tonic-gate 		    "-->\n\n"
881*7c478bd9Sstevel@tonic-gate 		    "<!DOCTYPE FRUID_XML_Tree SYSTEM \"prtfrureg.dtd\">\n\n"
882*7c478bd9Sstevel@tonic-gate 		    "<FRUID_XML_Tree>\n");
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 		/* Arrange to always properly terminate XML */
885*7c478bd9Sstevel@tonic-gate 		if (atexit(terminate_xml))
886*7c478bd9Sstevel@tonic-gate 			error(gettext("Warning:  XML will not be terminated:  "
887*7c478bd9Sstevel@tonic-gate 					"%s\n"), strerror(errno));
888*7c478bd9Sstevel@tonic-gate 	} else
889*7c478bd9Sstevel@tonic-gate 		print_node = print_node_path;
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	/* Get the root node */
893*7c478bd9Sstevel@tonic-gate 	if ((status = fru_get_root(&frutree)) == FRU_NODENOTFOUND) {
894*7c478bd9Sstevel@tonic-gate 		error(gettext("This system does not provide FRU ID data\n"));
895*7c478bd9Sstevel@tonic-gate 		return (1);
896*7c478bd9Sstevel@tonic-gate 	} else if (status != FRU_SUCCESS) {
897*7c478bd9Sstevel@tonic-gate 		error(gettext("Unable to access FRU ID data:  %s\n"),
898*7c478bd9Sstevel@tonic-gate 			fru_strerror(status));
899*7c478bd9Sstevel@tonic-gate 		return (1);
900*7c478bd9Sstevel@tonic-gate 	}
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	/* Process the tree */
903*7c478bd9Sstevel@tonic-gate 	if (searchpath == NULL) {
904*7c478bd9Sstevel@tonic-gate 		status = fru_walk_tree(frutree, "", process_node, NULL);
905*7c478bd9Sstevel@tonic-gate 	} else {
906*7c478bd9Sstevel@tonic-gate 		status = fru_walk_tree(frutree, "", process_matching_node,
907*7c478bd9Sstevel@tonic-gate 					(void *)searchpath);
908*7c478bd9Sstevel@tonic-gate 		if (status == FRU_WALK_TERMINATE) {
909*7c478bd9Sstevel@tonic-gate 			status = FRU_SUCCESS;
910*7c478bd9Sstevel@tonic-gate 		} else if (status == FRU_SUCCESS) {
911*7c478bd9Sstevel@tonic-gate 			error(gettext("\"%s\" not found\n"), searchpath);
912*7c478bd9Sstevel@tonic-gate 			return (1);
913*7c478bd9Sstevel@tonic-gate 		}
914*7c478bd9Sstevel@tonic-gate 	}
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	if (status != FRU_SUCCESS)
917*7c478bd9Sstevel@tonic-gate 		error(gettext("Error processing FRU tree:  %s\n"),
918*7c478bd9Sstevel@tonic-gate 			fru_strerror(status));
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	return (((status == FRU_SUCCESS) && (saved_status == 0)) ? 0 : 1);
921*7c478bd9Sstevel@tonic-gate }
922