10eb822a1Scindi /*
20eb822a1Scindi  * CDDL HEADER START
30eb822a1Scindi  *
40eb822a1Scindi  * The contents of this file are subject to the terms of the
50eb822a1Scindi  * Common Development and Distribution License (the "License").
60eb822a1Scindi  * You may not use this file except in compliance with the License.
70eb822a1Scindi  *
80eb822a1Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90eb822a1Scindi  * or http://www.opensolaris.org/os/licensing.
100eb822a1Scindi  * See the License for the specific language governing permissions
110eb822a1Scindi  * and limitations under the License.
120eb822a1Scindi  *
130eb822a1Scindi  * When distributing Covered Code, include this CDDL HEADER in each
140eb822a1Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150eb822a1Scindi  * If applicable, add the following below this CDDL HEADER, with the
160eb822a1Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
170eb822a1Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
180eb822a1Scindi  *
190eb822a1Scindi  * CDDL HEADER END
200eb822a1Scindi  */
210eb822a1Scindi 
220eb822a1Scindi /*
23eae2e508Skrishnae  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240eb822a1Scindi  * Use is subject to license terms.
250eb822a1Scindi  */
261e95bfe1SRob Johnston /*
271e95bfe1SRob Johnston  * Copyright (c) 2019, Joyent, Inc. All rights reserved.
281e95bfe1SRob Johnston  */
290eb822a1Scindi 
300eb822a1Scindi #include <stdio.h>
310eb822a1Scindi #include <strings.h>
320eb822a1Scindi #include <time.h>
330eb822a1Scindi #include <sys/types.h>
340eb822a1Scindi #include <sys/fm/protocol.h>
350eb822a1Scindi #include <sys/utsname.h>
360eb822a1Scindi 
370eb822a1Scindi #include <topo_parse.h>
380eb822a1Scindi #include <topo_prop.h>
390eb822a1Scindi #include <topo_tree.h>
400eb822a1Scindi 
411e95bfe1SRob Johnston /*
421e95bfe1SRob Johnston  * In the XML representation of the topo snapshot, 32-bit integer values are
431e95bfe1SRob Johnston  * represented as base-10 values.
441e95bfe1SRob Johnston  *
451e95bfe1SRob Johnston  * 10 bytes for base-10 value + 1 for sign + nul
461e95bfe1SRob Johnston  */
471e95bfe1SRob Johnston #define	INT32BUFSZ	12
48ebee07ffSRob Johnston /*
49ebee07ffSRob Johnston  * Buffer that is large enough to hold the string representation of any signed
50ebee07ffSRob Johnston  * or unsigned 64-bit integer.
51ebee07ffSRob Johnston  *
52ebee07ffSRob Johnston  * 2 bytes for "0x" + 16 bytes for the base-16 value + nul
53ebee07ffSRob Johnston  * or
54ebee07ffSRob Johnston  * 19 bytes for base-10 value + 1 for sign + nul
55ebee07ffSRob Johnston  */
56ebee07ffSRob Johnston #define	INT64BUFSZ	21
570eb822a1Scindi #define	XML_VERSION	"1.0"
580eb822a1Scindi 
590eb822a1Scindi static int txml_print_range(topo_hdl_t *, FILE *, tnode_t *, int);
600eb822a1Scindi 
610eb822a1Scindi void
print_header(FILE * fp)620eb822a1Scindi print_header(FILE *fp)
630eb822a1Scindi {
640eb822a1Scindi 	char buf[32];
650eb822a1Scindi 	time_t tod = time(NULL);
660eb822a1Scindi 	struct utsname uts;
670eb822a1Scindi 
680eb822a1Scindi 	(void) fprintf(fp, "<?xml version=\"%s\"?>\n", XML_VERSION);
690eb822a1Scindi 	(void) fprintf(fp, "<!DOCTYPE topology SYSTEM \"%s\">\n",
700eb822a1Scindi 	    TOPO_DTD_PATH);
710eb822a1Scindi 
720eb822a1Scindi 	(void) uname(&uts);
730eb822a1Scindi 	(void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
740eb822a1Scindi 	(void) fprintf(fp, "<!--\n");
750eb822a1Scindi 	(void) fprintf(fp, " This topology map file was generated on "
760eb822a1Scindi 	    "%-15s for %s\n", buf, uts.nodename);
770eb822a1Scindi 	(void) fprintf(fp, "<-->\n\n");
780eb822a1Scindi }
790eb822a1Scindi 
800eb822a1Scindi void
begin_element(FILE * fp,const char * ename,...)810eb822a1Scindi begin_element(FILE *fp, const char *ename, ...)
820eb822a1Scindi {
830eb822a1Scindi 	char *name, *value;
840eb822a1Scindi 	va_list ap;
850eb822a1Scindi 
860eb822a1Scindi 	(void) fprintf(fp, "<%s ", ename);
870eb822a1Scindi 	va_start(ap, ename);
880eb822a1Scindi 	name = va_arg(ap, char *);
890eb822a1Scindi 	while (name != NULL) {
900eb822a1Scindi 		value = va_arg(ap, char *);
910eb822a1Scindi 		(void) fprintf(fp, "%s='%s' ", name, value);
920eb822a1Scindi 		name = va_arg(ap, char *);
930eb822a1Scindi 	}
940eb822a1Scindi 	(void) fprintf(fp, ">\n");
950eb822a1Scindi }
960eb822a1Scindi 
970eb822a1Scindi void
begin_end_element(FILE * fp,const char * ename,...)980eb822a1Scindi begin_end_element(FILE *fp, const char *ename, ...)
990eb822a1Scindi {
1000eb822a1Scindi 	char *name, *value;
1010eb822a1Scindi 	va_list ap;
1020eb822a1Scindi 
1030eb822a1Scindi 	(void) fprintf(fp, "<%s ", ename);
1040eb822a1Scindi 	va_start(ap, ename);
1050eb822a1Scindi 	name = va_arg(ap, char *);
1060eb822a1Scindi 	while (name != NULL) {
1070eb822a1Scindi 		value = va_arg(ap, char *);
1080eb822a1Scindi 		(void) fprintf(fp, "%s='%s' ", name, value);
1090eb822a1Scindi 		name = va_arg(ap, char *);
1100eb822a1Scindi 	}
1110eb822a1Scindi 	(void) fprintf(fp, "/>\n");
1120eb822a1Scindi }
1130eb822a1Scindi 
1140eb822a1Scindi void
end_element(FILE * fp,const char * ename)1150eb822a1Scindi end_element(FILE *fp, const char *ename)
1160eb822a1Scindi {
1170eb822a1Scindi 	(void) fprintf(fp, "</%s>\n", ename);
1180eb822a1Scindi }
1190eb822a1Scindi 
1200eb822a1Scindi static void
txml_print_prop(topo_hdl_t * thp,FILE * fp,tnode_t * node,const char * pgname,topo_propval_t * pv)121825ba0f2Srobj txml_print_prop(topo_hdl_t *thp, FILE *fp, tnode_t *node, const char *pgname,
122825ba0f2Srobj     topo_propval_t *pv)
1230eb822a1Scindi {
1240eb822a1Scindi 	int err;
125ebee07ffSRob Johnston 	uint_t nelem;
126ebee07ffSRob Johnston 	char vbuf[INT64BUFSZ];
1270eb822a1Scindi 
1280eb822a1Scindi 	switch (pv->tp_type) {
1290eb822a1Scindi 		case TOPO_TYPE_INT32: {
1300eb822a1Scindi 			int32_t val;
131ebee07ffSRob Johnston 
132825ba0f2Srobj 			if (topo_prop_get_int32(node, pgname, pv->tp_name, &val,
133ebee07ffSRob Johnston 			    &err) != 0)
134825ba0f2Srobj 				return;
135ebee07ffSRob Johnston 
136ebee07ffSRob Johnston 			(void) snprintf(vbuf, INT64BUFSZ, "%d", val);
137ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
138ebee07ffSRob Johnston 			    Int32, Value, vbuf, NULL);
1390eb822a1Scindi 			break;
1400eb822a1Scindi 		}
1410eb822a1Scindi 		case TOPO_TYPE_UINT32: {
1420eb822a1Scindi 			uint32_t val;
143ebee07ffSRob Johnston 
144825ba0f2Srobj 			if (topo_prop_get_uint32(node, pgname, pv->tp_name,
145ebee07ffSRob Johnston 			    &val, &err) != 0)
146825ba0f2Srobj 				return;
147ebee07ffSRob Johnston 
148ebee07ffSRob Johnston 			(void) snprintf(vbuf, INT64BUFSZ, "0x%x", val);
149ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
150ebee07ffSRob Johnston 			    UInt32, Value, vbuf, NULL);
1510eb822a1Scindi 			break;
1520eb822a1Scindi 		}
1530eb822a1Scindi 		case TOPO_TYPE_INT64: {
1540eb822a1Scindi 			int64_t val;
155ebee07ffSRob Johnston 
156825ba0f2Srobj 			if (topo_prop_get_int64(node, pgname, pv->tp_name, &val,
157ebee07ffSRob Johnston 			    &err) != 0)
158825ba0f2Srobj 				return;
159ebee07ffSRob Johnston 
160ebee07ffSRob Johnston 			(void) snprintf(vbuf, INT64BUFSZ, "%" PRId64, val);
161ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
162ebee07ffSRob Johnston 			    Int64, Value, vbuf, NULL);
1630eb822a1Scindi 			break;
1640eb822a1Scindi 		}
1650eb822a1Scindi 		case TOPO_TYPE_UINT64: {
1660eb822a1Scindi 			uint64_t val;
167ebee07ffSRob Johnston 
168825ba0f2Srobj 			if (topo_prop_get_uint64(node, pgname, pv->tp_name,
169ebee07ffSRob Johnston 			    &val, &err) != 0)
170825ba0f2Srobj 				return;
171ebee07ffSRob Johnston 
172ebee07ffSRob Johnston 			(void) snprintf(vbuf, INT64BUFSZ, "0x%" PRIx64, val);
173ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
174ebee07ffSRob Johnston 			    UInt64, Value, vbuf, NULL);
175ebee07ffSRob Johnston 			break;
176ebee07ffSRob Johnston 		}
177ebee07ffSRob Johnston 		case TOPO_TYPE_DOUBLE: {
178ebee07ffSRob Johnston 			double val;
179ebee07ffSRob Johnston 			char *dblstr = NULL;
180ebee07ffSRob Johnston 
181ebee07ffSRob Johnston 			if (topo_prop_get_double(node, pgname, pv->tp_name,
182ebee07ffSRob Johnston 			    &val, &err) != 0)
183ebee07ffSRob Johnston 				return;
184ebee07ffSRob Johnston 
185ebee07ffSRob Johnston 			/*
186ebee07ffSRob Johnston 			 * The %a format specifier allows floating point values
187ebee07ffSRob Johnston 			 * to be serialized without losing precision.
188ebee07ffSRob Johnston 			 */
189ebee07ffSRob Johnston 			if (asprintf(&dblstr, "%a", val) < 0)
190ebee07ffSRob Johnston 				return;
191ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
192ebee07ffSRob Johnston 			    Double, Value, dblstr, NULL);
193ebee07ffSRob Johnston 			free(dblstr);
1940eb822a1Scindi 			break;
1950eb822a1Scindi 		}
1960eb822a1Scindi 		case TOPO_TYPE_STRING: {
197ebee07ffSRob Johnston 			char *strbuf = NULL;
198ebee07ffSRob Johnston 
199825ba0f2Srobj 			if (topo_prop_get_string(node, pgname, pv->tp_name,
200ebee07ffSRob Johnston 			    &strbuf, &err) != 0)
201825ba0f2Srobj 				return;
202ebee07ffSRob Johnston 
203ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
204ebee07ffSRob Johnston 			    String, Value, strbuf, NULL);
205ebee07ffSRob Johnston 			topo_hdl_strfree(thp, strbuf);
2060eb822a1Scindi 			break;
2070eb822a1Scindi 		}
2080eb822a1Scindi 		case TOPO_TYPE_FMRI: {
209ebee07ffSRob Johnston 			nvlist_t *val = NULL;
210ebee07ffSRob Johnston 			char *fmristr = NULL;
2110eb822a1Scindi 
212825ba0f2Srobj 			if (topo_prop_get_fmri(node, pgname, pv->tp_name, &val,
213ebee07ffSRob Johnston 			    &err) != 0 ||
214ebee07ffSRob Johnston 			    topo_fmri_nvl2str(thp, val, &fmristr, &err) != 0) {
215ebee07ffSRob Johnston 				nvlist_free(val);
2160eb822a1Scindi 				return;
217ebee07ffSRob Johnston 			}
218ebee07ffSRob Johnston 			nvlist_free(val);
219ebee07ffSRob Johnston 			begin_end_element(fp, Propval, Name, pv->tp_name, Type,
220ebee07ffSRob Johnston 			    FMRI, Value, fmristr, NULL);
221ebee07ffSRob Johnston 			topo_hdl_strfree(thp, fmristr);
222ebee07ffSRob Johnston 			break;
223ebee07ffSRob Johnston 		}
224ebee07ffSRob Johnston 		case TOPO_TYPE_INT32_ARRAY: {
225ebee07ffSRob Johnston 			int32_t *val;
226ebee07ffSRob Johnston 
227ebee07ffSRob Johnston 			if (topo_prop_get_int32_array(node, pgname,
228ebee07ffSRob Johnston 			    pv->tp_name, &val, &nelem, &err) != 0)
229ebee07ffSRob Johnston 				return;
230ebee07ffSRob Johnston 
231ebee07ffSRob Johnston 			begin_element(fp, Propval, Name, pv->tp_name, Type,
232ebee07ffSRob Johnston 			    Int32_Arr, NULL);
233ebee07ffSRob Johnston 
234ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
235ebee07ffSRob Johnston 				(void) snprintf(vbuf, INT64BUFSZ, "%d", val[i]);
236ebee07ffSRob Johnston 				begin_end_element(fp, Propitem, Value, vbuf,
237ebee07ffSRob Johnston 				    NULL);
238ebee07ffSRob Johnston 			}
239ebee07ffSRob Johnston 
240ebee07ffSRob Johnston 			topo_hdl_free(thp, val, nelem * sizeof (int32_t));
241ebee07ffSRob Johnston 			end_element(fp, Propval);
2420eb822a1Scindi 			break;
2430eb822a1Scindi 		}
244eae2e508Skrishnae 		case TOPO_TYPE_UINT32_ARRAY: {
245eae2e508Skrishnae 			uint32_t *val;
246ebee07ffSRob Johnston 
247825ba0f2Srobj 			if (topo_prop_get_uint32_array(node, pgname,
248825ba0f2Srobj 			    pv->tp_name, &val, &nelem, &err) != 0)
249825ba0f2Srobj 				return;
250eae2e508Skrishnae 
251ebee07ffSRob Johnston 			begin_element(fp, Propval, Name, pv->tp_name, Type,
252ebee07ffSRob Johnston 			    UInt32_Arr, NULL);
253ebee07ffSRob Johnston 
254ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
255ebee07ffSRob Johnston 				(void) snprintf(vbuf, INT64BUFSZ, "0x%x",
256ebee07ffSRob Johnston 				    val[i]);
257ebee07ffSRob Johnston 				begin_end_element(fp, Propitem, Value, vbuf,
258ebee07ffSRob Johnston 				    NULL);
259eae2e508Skrishnae 			}
260ebee07ffSRob Johnston 
261ebee07ffSRob Johnston 			topo_hdl_free(thp, val, nelem * sizeof (uint32_t));
262ebee07ffSRob Johnston 			end_element(fp, Propval);
263eae2e508Skrishnae 			break;
264eae2e508Skrishnae 		}
265ebee07ffSRob Johnston 		case TOPO_TYPE_INT64_ARRAY: {
266ebee07ffSRob Johnston 			int64_t *val;
2670eb822a1Scindi 
268ebee07ffSRob Johnston 			if (topo_prop_get_int64_array(node, pgname,
269ebee07ffSRob Johnston 			    pv->tp_name, &val, &nelem, &err) != 0)
270ebee07ffSRob Johnston 				return;
271ebee07ffSRob Johnston 
272ebee07ffSRob Johnston 			begin_element(fp, Propval, Name, pv->tp_name, Type,
273ebee07ffSRob Johnston 			    Int64_Arr, NULL);
274ebee07ffSRob Johnston 
275ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
276ebee07ffSRob Johnston 				(void) snprintf(vbuf, INT64BUFSZ, "%" PRId64,
277ebee07ffSRob Johnston 				    val[i]);
278ebee07ffSRob Johnston 				begin_end_element(fp, Propitem, Value, vbuf,
279ebee07ffSRob Johnston 				    NULL);
280ebee07ffSRob Johnston 			}
281ebee07ffSRob Johnston 
282ebee07ffSRob Johnston 			topo_hdl_free(thp, val, nelem * sizeof (int64_t));
283ebee07ffSRob Johnston 			end_element(fp, Propval);
284ebee07ffSRob Johnston 			break;
285ebee07ffSRob Johnston 		}
286ebee07ffSRob Johnston 		case TOPO_TYPE_UINT64_ARRAY: {
287ebee07ffSRob Johnston 			uint64_t *val;
288ebee07ffSRob Johnston 
289ebee07ffSRob Johnston 			if (topo_prop_get_uint64_array(node, pgname,
290ebee07ffSRob Johnston 			    pv->tp_name, &val, &nelem, &err) != 0)
291ebee07ffSRob Johnston 				return;
292ebee07ffSRob Johnston 
293ebee07ffSRob Johnston 			begin_element(fp, Propval, Name, pv->tp_name, Type,
294ebee07ffSRob Johnston 			    UInt64_Arr, NULL);
2950eb822a1Scindi 
296ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
297ebee07ffSRob Johnston 				(void) snprintf(vbuf, INT64BUFSZ, "0x%" PRIx64,
298ebee07ffSRob Johnston 				    val[i]);
299ebee07ffSRob Johnston 				begin_end_element(fp, Propitem, Value, vbuf,
300ebee07ffSRob Johnston 				    NULL);
301ebee07ffSRob Johnston 			}
302ebee07ffSRob Johnston 
303ebee07ffSRob Johnston 			topo_hdl_free(thp, val, nelem * sizeof (uint64_t));
304ebee07ffSRob Johnston 			end_element(fp, Propval);
305ebee07ffSRob Johnston 			break;
306ebee07ffSRob Johnston 		}
307ebee07ffSRob Johnston 		case TOPO_TYPE_STRING_ARRAY: {
308ebee07ffSRob Johnston 			char **val;
309ebee07ffSRob Johnston 
310ebee07ffSRob Johnston 			if (topo_prop_get_string_array(node, pgname,
311ebee07ffSRob Johnston 			    pv->tp_name, &val, &nelem, &err) != 0)
312ebee07ffSRob Johnston 				return;
313d6770490Srobj 
314ebee07ffSRob Johnston 			begin_element(fp, Propval, Name, pv->tp_name, Type,
315ebee07ffSRob Johnston 			    String_Arr, NULL);
316d6770490Srobj 
317ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
318ebee07ffSRob Johnston 				begin_end_element(fp, Propitem, Value, val[i],
319ebee07ffSRob Johnston 				    NULL);
320ebee07ffSRob Johnston 			}
321e2336878SRob Johnston 			topo_hdl_strfreev(thp, val, nelem);
322ebee07ffSRob Johnston 
323ebee07ffSRob Johnston 			end_element(fp, Propval);
324ebee07ffSRob Johnston 			break;
325ebee07ffSRob Johnston 		}
326ebee07ffSRob Johnston 		case TOPO_TYPE_FMRI_ARRAY: {
327ebee07ffSRob Johnston 			nvlist_t **val;
328ebee07ffSRob Johnston 			char *fmristr = NULL;
329ebee07ffSRob Johnston 			int ret;
330ebee07ffSRob Johnston 
331ebee07ffSRob Johnston 			if (topo_prop_get_fmri_array(node, pgname,
332ebee07ffSRob Johnston 			    pv->tp_name, &val, &nelem, &err) != 0)
333ebee07ffSRob Johnston 				return;
334ebee07ffSRob Johnston 
335ebee07ffSRob Johnston 			begin_element(fp, Propval, Name, pv->tp_name, Type,
336ebee07ffSRob Johnston 			    FMRI_Arr, NULL);
337ebee07ffSRob Johnston 
338ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
339ebee07ffSRob Johnston 				if ((ret = topo_fmri_nvl2str(thp, val[i],
340ebee07ffSRob Johnston 				    &fmristr, &err)) != 0)
341ebee07ffSRob Johnston 					break;
342ebee07ffSRob Johnston 				begin_end_element(fp, Propitem, Value, fmristr,
343ebee07ffSRob Johnston 				    NULL);
344ebee07ffSRob Johnston 				topo_hdl_strfree(thp, fmristr);
345ebee07ffSRob Johnston 			}
346ebee07ffSRob Johnston 			for (uint_t i = 0; i < nelem; i++) {
347ebee07ffSRob Johnston 				nvlist_free(val[i]);
348ebee07ffSRob Johnston 			}
349ebee07ffSRob Johnston 			topo_hdl_free(thp, val, nelem * sizeof (nvlist_t *));
350ebee07ffSRob Johnston 			end_element(fp, Propval);
351ebee07ffSRob Johnston 			break;
352ebee07ffSRob Johnston 		}
353ebee07ffSRob Johnston 		default:
354ebee07ffSRob Johnston 			return;
355ebee07ffSRob Johnston 	}
3560eb822a1Scindi }
3570eb822a1Scindi 
3580eb822a1Scindi static void
txml_print_pgroup(topo_hdl_t * thp,FILE * fp,tnode_t * node,topo_pgroup_t * pg)359825ba0f2Srobj txml_print_pgroup(topo_hdl_t *thp, FILE *fp, tnode_t *node, topo_pgroup_t *pg)
3600eb822a1Scindi {
3610eb822a1Scindi 	topo_ipgroup_info_t *pip = pg->tpg_info;
3620eb822a1Scindi 	topo_proplist_t *plp;
3630eb822a1Scindi 	const char *namestab, *datastab;
3640eb822a1Scindi 	char version[INT32BUFSZ];
3650eb822a1Scindi 
3660eb822a1Scindi 	namestab = topo_stability2name(pip->tpi_namestab);
3670eb822a1Scindi 	datastab = topo_stability2name(pip->tpi_datastab);
3680eb822a1Scindi 	(void) snprintf(version, INT32BUFSZ, "%d", pip->tpi_version);
3690eb822a1Scindi 	begin_element(fp, Propgrp, Name, pip->tpi_name, Namestab,
3700eb822a1Scindi 	    namestab, Datastab, datastab, Version, version, NULL);
3710eb822a1Scindi 	for (plp = topo_list_next(&pg->tpg_pvals); plp != NULL;
3720eb822a1Scindi 	    plp = topo_list_next(plp)) {
373825ba0f2Srobj 		txml_print_prop(thp, fp, node, pip->tpi_name, plp->tp_pval);
3740eb822a1Scindi 	}
3750eb822a1Scindi 	end_element(fp, Propgrp);
3760eb822a1Scindi }
3770eb822a1Scindi 
3780eb822a1Scindi static void
txml_print_dependents(topo_hdl_t * thp,FILE * fp,tnode_t * node)3790eb822a1Scindi txml_print_dependents(topo_hdl_t *thp, FILE *fp, tnode_t *node)
3800eb822a1Scindi {
3810eb822a1Scindi 	if (topo_list_next(&node->tn_children) == NULL)
3820eb822a1Scindi 		return;
3830eb822a1Scindi 
3840eb822a1Scindi 	if (txml_print_range(thp, fp, node, 1) == 1)
3850eb822a1Scindi 		end_element(fp, Dependents);
3860eb822a1Scindi }
3870eb822a1Scindi 
3880eb822a1Scindi static void
txml_print_node(topo_hdl_t * thp,FILE * fp,tnode_t * node)3890eb822a1Scindi txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node)
3900eb822a1Scindi {
3910eb822a1Scindi 	char inst[INT32BUFSZ];
3920eb822a1Scindi 	topo_pgroup_t *pg;
3930eb822a1Scindi 
3940eb822a1Scindi 	(void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance);
395ebee07ffSRob Johnston 	/*
396ebee07ffSRob Johnston 	 * The "static" attribute for the "node" element controls whether the
397ebee07ffSRob Johnston 	 * node gets enumerated, if it doesn't already exist.  Setting it to
398ebee07ffSRob Johnston 	 * true causes the node to not be created.  The primary use-case for
399ebee07ffSRob Johnston 	 * setting it to true is when want to use XML to override a property
400ebee07ffSRob Johnston 	 * value on a topo node that was already created by an enumerator
401ebee07ffSRob Johnston 	 * module.  In this case we're trying to serialize the whole topology
402ebee07ffSRob Johnston 	 * in a fashion such that we could reconstitute it from the generated
403ebee07ffSRob Johnston 	 * XML. In which case, we relly need it to create all the nodes becuase
404ebee07ffSRob Johnston 	 * no enumerator modules will be running.  Hence, we set static to
405ebee07ffSRob Johnston 	 * false.
406ebee07ffSRob Johnston 	 */
407ebee07ffSRob Johnston 	begin_element(fp, Node, Instance, inst, Static, False, NULL);
4080eb822a1Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
4090eb822a1Scindi 	    pg = topo_list_next(pg)) {
410825ba0f2Srobj 		txml_print_pgroup(thp, fp, node, pg);
4110eb822a1Scindi 	}
4120eb822a1Scindi 	txml_print_dependents(thp, fp, node);
4130eb822a1Scindi 	end_element(fp, Node);
4140eb822a1Scindi 
4150eb822a1Scindi }
4160eb822a1Scindi 
4170eb822a1Scindi static int
txml_print_range(topo_hdl_t * thp,FILE * fp,tnode_t * node,int dependent)4180eb822a1Scindi txml_print_range(topo_hdl_t *thp, FILE *fp, tnode_t *node, int dependent)
4190eb822a1Scindi {
4200eb822a1Scindi 	int i, create = 0, ret = 0;
4210eb822a1Scindi 	topo_nodehash_t *nhp;
4220eb822a1Scindi 	char min[INT32BUFSZ], max[INT32BUFSZ];
4230eb822a1Scindi 
4240eb822a1Scindi 	for (nhp = topo_list_next(&node->tn_children); nhp != NULL;
4250eb822a1Scindi 	    nhp = topo_list_next(nhp)) {
4260eb822a1Scindi 		(void) snprintf(min, INT32BUFSZ, "%d", nhp->th_range.tr_min);
4270eb822a1Scindi 		(void) snprintf(max, INT32BUFSZ, "%d", nhp->th_range.tr_max);
4280eb822a1Scindi 
4290eb822a1Scindi 		/*
4300eb822a1Scindi 		 * Some enumerators create empty ranges: make sure there
4310eb822a1Scindi 		 * are real nodes before creating this range
4320eb822a1Scindi 		 */
4330eb822a1Scindi 		for (i = 0; i < nhp->th_arrlen; ++i) {
4340eb822a1Scindi 			if (nhp->th_nodearr[i] != NULL)
4350eb822a1Scindi 				++create;
4360eb822a1Scindi 		}
4370eb822a1Scindi 		if (!create)
4380eb822a1Scindi 			continue;
4390eb822a1Scindi 
4400eb822a1Scindi 		if (dependent) {
4410eb822a1Scindi 			begin_element(fp, Dependents, Grouping, Children, NULL);
4420eb822a1Scindi 			dependent = 0;
4430eb822a1Scindi 			ret = 1;
4440eb822a1Scindi 		}
4450eb822a1Scindi 		begin_element(fp, Range, Name, nhp->th_name, Min, min, Max,
4460eb822a1Scindi 		    max, NULL);
4470eb822a1Scindi 		for (i = 0; i < nhp->th_arrlen; ++i) {
4480eb822a1Scindi 			if (nhp->th_nodearr[i] != NULL)
4490eb822a1Scindi 				txml_print_node(thp, fp, nhp->th_nodearr[i]);
4500eb822a1Scindi 		}
4510eb822a1Scindi 		end_element(fp, Range);
4520eb822a1Scindi 	}
4530eb822a1Scindi 
4540eb822a1Scindi 	return (ret);
4550eb822a1Scindi }
4560eb822a1Scindi 
4570eb822a1Scindi static void
txml_print_topology(topo_hdl_t * thp,FILE * fp,char * scheme,tnode_t * node)4580eb822a1Scindi txml_print_topology(topo_hdl_t *thp, FILE *fp, char *scheme, tnode_t *node)
4590eb822a1Scindi {
460*cb96e632SRobert Mustacchi 	const char *name = thp->th_product;
46112cc75c8Scindi 
46212cc75c8Scindi 	begin_element(fp, Topology, Name, name, Scheme, scheme,
4630eb822a1Scindi 	    NULL);
4640eb822a1Scindi 	(void) txml_print_range(thp, fp, node, 0);
4650eb822a1Scindi 	end_element(fp, Topology);
4660eb822a1Scindi }
4670eb822a1Scindi 
4680eb822a1Scindi int
topo_xml_print(topo_hdl_t * thp,FILE * fp,const char * scheme,int * err)4690eb822a1Scindi topo_xml_print(topo_hdl_t *thp,  FILE *fp, const char *scheme, int *err)
4700eb822a1Scindi {
4710eb822a1Scindi 	ttree_t *tp;
4720eb822a1Scindi 
4730eb822a1Scindi 	print_header(fp);
4740eb822a1Scindi 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
4750eb822a1Scindi 	    tp = topo_list_next(tp)) {
4760eb822a1Scindi 		if (strcmp(scheme, tp->tt_scheme) == 0) {
4770eb822a1Scindi 			txml_print_topology(thp, fp, tp->tt_scheme,
4780eb822a1Scindi 			    tp->tt_root);
4790eb822a1Scindi 			return (0);
4800eb822a1Scindi 		}
4810eb822a1Scindi 	}
4820eb822a1Scindi 
4830eb822a1Scindi 	*err = EINVAL;
4840eb822a1Scindi 	return (-1);
4850eb822a1Scindi }
486