1*c5591576SRob Johnston /*
2*c5591576SRob Johnston  * This file and its contents are supplied under the terms of the
3*c5591576SRob Johnston  * Common Development and Distribution License ("CDDL"), version 1.0.
4*c5591576SRob Johnston  * You may only use this file in accordance with the terms of version
5*c5591576SRob Johnston  * 1.0 of the CDDL.
6*c5591576SRob Johnston  *
7*c5591576SRob Johnston  * A full copy of the text of the CDDL should have accompanied this
8*c5591576SRob Johnston  * source.  A copy of the CDDL is also available via the Internet at
9*c5591576SRob Johnston  * http://www.illumos.org/license/CDDL.
10*c5591576SRob Johnston  */
11*c5591576SRob Johnston 
12*c5591576SRob Johnston /*
13*c5591576SRob Johnston  * Copyright 2020 Joyent, Inc.
14*c5591576SRob Johnston  */
15*c5591576SRob Johnston 
16*c5591576SRob Johnston /*
17*c5591576SRob Johnston  * This file implements the following two routines for serializing and
18*c5591576SRob Johnston  * deserializing digraphs to/from XML, respectively:
19*c5591576SRob Johnston  *
20*c5591576SRob Johnston  * topo_digraph_serialize()
21*c5591576SRob Johnston  * topo_digraph_deserialize()
22*c5591576SRob Johnston  *
23*c5591576SRob Johnston  * Refer to the following file for the XML schema being used:
24*c5591576SRob Johnston  * usr/src/lib/fm/topo/maps/common/digraph-topology.dtd.1
25*c5591576SRob Johnston  */
26*c5591576SRob Johnston #include <time.h>
27*c5591576SRob Johnston #include <sys/utsname.h>
28*c5591576SRob Johnston #include <libxml/parser.h>
29*c5591576SRob Johnston #include <libtopo.h>
30*c5591576SRob Johnston 
31*c5591576SRob Johnston #include <topo_digraph.h>
32*c5591576SRob Johnston #include <topo_digraph_xml.h>
33*c5591576SRob Johnston 
34*c5591576SRob Johnston #define	__STDC_FORMAT_MACROS
35*c5591576SRob Johnston #include <inttypes.h>
36*c5591576SRob Johnston 
37*c5591576SRob Johnston extern int xmlattr_to_int(topo_mod_t *, xmlNodePtr, const char *, uint64_t *);
38*c5591576SRob Johnston static int serialize_nvpair(topo_hdl_t *thp, FILE *, uint_t, const char *,
39*c5591576SRob Johnston     nvpair_t *);
40*c5591576SRob Johnston 
41*c5591576SRob Johnston static void
tdg_xml_nvstring(FILE * fp,uint_t pad,const char * name,const char * value)42*c5591576SRob Johnston tdg_xml_nvstring(FILE *fp, uint_t pad, const char *name, const char *value)
43*c5591576SRob Johnston {
44*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%s' />\n", pad, "",
45*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_STRING,
46*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
47*c5591576SRob Johnston }
48*c5591576SRob Johnston 
49*c5591576SRob Johnston static void
tdg_xml_nvlist(FILE * fp,uint_t pad,const char * name)50*c5591576SRob Johnston tdg_xml_nvlist(FILE *fp, uint_t pad, const char *name)
51*c5591576SRob Johnston {
52*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s'>\n", pad, "",
53*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_NVLIST);
54*c5591576SRob Johnston }
55*c5591576SRob Johnston 
56*c5591576SRob Johnston static void
tdg_xml_nvuint8(FILE * fp,uint_t pad,const char * name,const uint8_t value)57*c5591576SRob Johnston tdg_xml_nvuint8(FILE *fp, uint_t pad, const char *name, const uint8_t value)
58*c5591576SRob Johnston {
59*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%u' />\n", pad, "",
60*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_UINT8,
61*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
62*c5591576SRob Johnston }
63*c5591576SRob Johnston 
64*c5591576SRob Johnston static void
tdg_xml_nvint8(FILE * fp,uint_t pad,const char * name,const uint8_t value)65*c5591576SRob Johnston tdg_xml_nvint8(FILE *fp, uint_t pad, const char *name, const uint8_t value)
66*c5591576SRob Johnston {
67*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%d' />\n", pad, "",
68*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_INT8,
69*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
70*c5591576SRob Johnston }
71*c5591576SRob Johnston 
72*c5591576SRob Johnston static void
tdg_xml_nvuint16(FILE * fp,uint_t pad,const char * name,const uint8_t value)73*c5591576SRob Johnston tdg_xml_nvuint16(FILE *fp, uint_t pad, const char *name, const uint8_t value)
74*c5591576SRob Johnston {
75*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%u' />\n", pad, "",
76*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_UINT16,
77*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
78*c5591576SRob Johnston }
79*c5591576SRob Johnston 
80*c5591576SRob Johnston static void
tdg_xml_nvint16(FILE * fp,uint_t pad,const char * name,const uint8_t value)81*c5591576SRob Johnston tdg_xml_nvint16(FILE *fp, uint_t pad, const char *name, const uint8_t value)
82*c5591576SRob Johnston {
83*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%d' />\n", pad, "",
84*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_INT16,
85*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
86*c5591576SRob Johnston }
87*c5591576SRob Johnston 
88*c5591576SRob Johnston static void
tdg_xml_nvuint32(FILE * fp,uint_t pad,const char * name,const uint32_t value)89*c5591576SRob Johnston tdg_xml_nvuint32(FILE *fp, uint_t pad, const char *name, const uint32_t value)
90*c5591576SRob Johnston {
91*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%u' />\n", pad, "",
92*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_UINT32,
93*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
94*c5591576SRob Johnston }
95*c5591576SRob Johnston 
96*c5591576SRob Johnston static void
tdg_xml_nvint32(FILE * fp,uint_t pad,const char * name,const int32_t value)97*c5591576SRob Johnston tdg_xml_nvint32(FILE *fp, uint_t pad, const char *name, const int32_t value)
98*c5591576SRob Johnston {
99*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%d' />\n", pad, "",
100*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_UINT32,
101*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
102*c5591576SRob Johnston }
103*c5591576SRob Johnston 
104*c5591576SRob Johnston static void
tdg_xml_nvuint64(FILE * fp,uint_t pad,const char * name,const uint64_t value)105*c5591576SRob Johnston tdg_xml_nvuint64(FILE *fp, uint_t pad, const char *name, const uint64_t value)
106*c5591576SRob Johnston {
107*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='0x%" PRIx64 "' />\n",
108*c5591576SRob Johnston 	    pad, "", TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE,
109*c5591576SRob Johnston 	    TDG_XML_UINT64, TDG_XML_VALUE, value);
110*c5591576SRob Johnston }
111*c5591576SRob Johnston 
112*c5591576SRob Johnston static void
tdg_xml_nvint64(FILE * fp,uint_t pad,const char * name,const int64_t value)113*c5591576SRob Johnston tdg_xml_nvint64(FILE *fp, uint_t pad, const char *name, const int64_t value)
114*c5591576SRob Johnston {
115*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%" PRIi64 "' />\n", pad,
116*c5591576SRob Johnston 	    "", TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE,
117*c5591576SRob Johnston 	    TDG_XML_UINT64, TDG_XML_VALUE, value);
118*c5591576SRob Johnston }
119*c5591576SRob Johnston 
120*c5591576SRob Johnston static void
tdg_xml_nvdbl(FILE * fp,uint_t pad,const char * name,const double value)121*c5591576SRob Johnston tdg_xml_nvdbl(FILE *fp, uint_t pad, const char *name, const double value)
122*c5591576SRob Johnston {
123*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s' %s='%lf' />\n", pad, ""
124*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, TDG_XML_UINT64,
125*c5591576SRob Johnston 	    TDG_XML_VALUE, value);
126*c5591576SRob Johnston }
127*c5591576SRob Johnston 
128*c5591576SRob Johnston static void
tdg_xml_nvarray(FILE * fp,uint_t pad,const char * name,const char * type)129*c5591576SRob Johnston tdg_xml_nvarray(FILE *fp, uint_t pad, const char *name, const char *type)
130*c5591576SRob Johnston {
131*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s'>\n", pad, "",
132*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE, type);
133*c5591576SRob Johnston }
134*c5591576SRob Johnston 
135*c5591576SRob Johnston static void
tdg_xml_nvint32arr(FILE * fp,uint_t pad,const char * name,int32_t * val,uint_t nelems)136*c5591576SRob Johnston tdg_xml_nvint32arr(FILE *fp, uint_t pad, const char *name, int32_t *val,
137*c5591576SRob Johnston     uint_t nelems)
138*c5591576SRob Johnston {
139*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s'>\n", pad, "",
140*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE,
141*c5591576SRob Johnston 	    TDG_XML_INT32_ARR);
142*c5591576SRob Johnston 
143*c5591576SRob Johnston 	for (uint_t i = 0; i < nelems; i++) {
144*c5591576SRob Johnston 		(void) fprintf(fp, "%*s<%s %s='%d' />\n", (pad + 2), "",
145*c5591576SRob Johnston 		    TDG_XML_NVPAIR, TDG_XML_VALUE, val[i]);
146*c5591576SRob Johnston 	}
147*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s>\n", pad, "", TDG_XML_NVPAIR);
148*c5591576SRob Johnston }
149*c5591576SRob Johnston 
150*c5591576SRob Johnston static void
tdg_xml_nvuint32arr(FILE * fp,uint_t pad,const char * name,uint32_t * val,uint_t nelems)151*c5591576SRob Johnston tdg_xml_nvuint32arr(FILE *fp, uint_t pad, const char *name, uint32_t *val,
152*c5591576SRob Johnston     uint_t nelems)
153*c5591576SRob Johnston {
154*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s'>\n", pad, "",
155*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE,
156*c5591576SRob Johnston 	    TDG_XML_UINT32_ARR);
157*c5591576SRob Johnston 
158*c5591576SRob Johnston 	for (uint_t i = 0; i < nelems; i++) {
159*c5591576SRob Johnston 		(void) fprintf(fp, "%*s<%s %s='%d' />\n", (pad + 2), "",
160*c5591576SRob Johnston 		    TDG_XML_NVPAIR, TDG_XML_VALUE, val[i]);
161*c5591576SRob Johnston 	}
162*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s>\n", pad, "", TDG_XML_NVPAIR);
163*c5591576SRob Johnston }
164*c5591576SRob Johnston 
165*c5591576SRob Johnston static void
tdg_xml_nvint64arr(FILE * fp,uint_t pad,const char * name,int64_t * val,uint_t nelems)166*c5591576SRob Johnston tdg_xml_nvint64arr(FILE *fp, uint_t pad, const char *name, int64_t *val,
167*c5591576SRob Johnston     uint_t nelems)
168*c5591576SRob Johnston {
169*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s'>\n", pad, "",
170*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE,
171*c5591576SRob Johnston 	    TDG_XML_INT64_ARR);
172*c5591576SRob Johnston 
173*c5591576SRob Johnston 	for (uint_t i = 0; i < nelems; i++) {
174*c5591576SRob Johnston 		(void) fprintf(fp, "%*s<%s %s='%" PRIi64 "' />\n", (pad + 2),
175*c5591576SRob Johnston 		    "", TDG_XML_NVPAIR, TDG_XML_VALUE, val[i]);
176*c5591576SRob Johnston 	}
177*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s>\n", pad, "", TDG_XML_NVPAIR);
178*c5591576SRob Johnston }
179*c5591576SRob Johnston 
180*c5591576SRob Johnston static void
tdg_xml_nvuint64arr(FILE * fp,uint_t pad,const char * name,uint64_t * val,uint_t nelems)181*c5591576SRob Johnston tdg_xml_nvuint64arr(FILE *fp, uint_t pad, const char *name, uint64_t *val,
182*c5591576SRob Johnston     uint_t nelems)
183*c5591576SRob Johnston {
184*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' %s='%s'>\n", pad, "",
185*c5591576SRob Johnston 	    TDG_XML_NVPAIR, TDG_XML_NAME, name, TDG_XML_TYPE,
186*c5591576SRob Johnston 	    TDG_XML_UINT64_ARR);
187*c5591576SRob Johnston 
188*c5591576SRob Johnston 	for (uint_t i = 0; i < nelems; i++) {
189*c5591576SRob Johnston 		(void) fprintf(fp, "%*s<%s %s='0x%" PRIx64 "' />\n", (pad + 2),
190*c5591576SRob Johnston 		    "", TDG_XML_NVPAIR, TDG_XML_VALUE, val[i]);
191*c5591576SRob Johnston 	}
192*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s>\n", pad, "", TDG_XML_NVPAIR);
193*c5591576SRob Johnston }
194*c5591576SRob Johnston 
195*c5591576SRob Johnston static int
serialize_nvpair_nvlist(topo_hdl_t * thp,FILE * fp,uint_t pad,const char * name,nvlist_t * nvl)196*c5591576SRob Johnston serialize_nvpair_nvlist(topo_hdl_t *thp, FILE *fp, uint_t pad,
197*c5591576SRob Johnston     const char *name, nvlist_t *nvl)
198*c5591576SRob Johnston {
199*c5591576SRob Johnston 	nvpair_t *elem = NULL;
200*c5591576SRob Johnston 
201*c5591576SRob Johnston 	tdg_xml_nvlist(fp, pad, name);
202*c5591576SRob Johnston 
203*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s>\n", pad, "", TDG_XML_NVLIST);
204*c5591576SRob Johnston 
205*c5591576SRob Johnston 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
206*c5591576SRob Johnston 		char *nvname = nvpair_name(elem);
207*c5591576SRob Johnston 
208*c5591576SRob Johnston 		if (serialize_nvpair(thp, fp, (pad + 2), nvname, elem) != 0) {
209*c5591576SRob Johnston 			/* errno set */
210*c5591576SRob Johnston 			return (-1);
211*c5591576SRob Johnston 		}
212*c5591576SRob Johnston 	}
213*c5591576SRob Johnston 
214*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s>\n", pad, "", TDG_XML_NVLIST);
215*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s> <!-- %s -->\n", pad, "", TDG_XML_NVPAIR,
216*c5591576SRob Johnston 	    name);
217*c5591576SRob Johnston 
218*c5591576SRob Johnston 	return (0);
219*c5591576SRob Johnston }
220*c5591576SRob Johnston 
221*c5591576SRob Johnston static int
serialize_nvpair(topo_hdl_t * thp,FILE * fp,uint_t pad,const char * pname,nvpair_t * nvp)222*c5591576SRob Johnston serialize_nvpair(topo_hdl_t *thp, FILE *fp, uint_t pad, const char *pname,
223*c5591576SRob Johnston     nvpair_t *nvp)
224*c5591576SRob Johnston {
225*c5591576SRob Johnston 	data_type_t type = nvpair_type(nvp);
226*c5591576SRob Johnston 
227*c5591576SRob Johnston 	switch (type) {
228*c5591576SRob Johnston 		case DATA_TYPE_INT8: {
229*c5591576SRob Johnston 			int8_t val;
230*c5591576SRob Johnston 
231*c5591576SRob Johnston 			if (nvpair_value_int8(nvp, &val) != 0)
232*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
233*c5591576SRob Johnston 
234*c5591576SRob Johnston 			tdg_xml_nvint8(fp, pad, pname, val);
235*c5591576SRob Johnston 			break;
236*c5591576SRob Johnston 		}
237*c5591576SRob Johnston 		case DATA_TYPE_UINT8: {
238*c5591576SRob Johnston 			uint8_t val;
239*c5591576SRob Johnston 
240*c5591576SRob Johnston 			if (nvpair_value_uint8(nvp, &val) != 0)
241*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
242*c5591576SRob Johnston 
243*c5591576SRob Johnston 			tdg_xml_nvuint8(fp, pad, pname, val);
244*c5591576SRob Johnston 			break;
245*c5591576SRob Johnston 		}
246*c5591576SRob Johnston 		case DATA_TYPE_INT16: {
247*c5591576SRob Johnston 			int16_t val;
248*c5591576SRob Johnston 
249*c5591576SRob Johnston 			if (nvpair_value_int16(nvp, &val) != 0)
250*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
251*c5591576SRob Johnston 
252*c5591576SRob Johnston 			tdg_xml_nvint16(fp, pad, pname, val);
253*c5591576SRob Johnston 			break;
254*c5591576SRob Johnston 		}
255*c5591576SRob Johnston 		case DATA_TYPE_UINT16: {
256*c5591576SRob Johnston 			uint16_t val;
257*c5591576SRob Johnston 
258*c5591576SRob Johnston 			if (nvpair_value_uint16(nvp, &val) != 0)
259*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
260*c5591576SRob Johnston 
261*c5591576SRob Johnston 			tdg_xml_nvuint16(fp, pad, pname, val);
262*c5591576SRob Johnston 			break;
263*c5591576SRob Johnston 		}
264*c5591576SRob Johnston 		case DATA_TYPE_INT32: {
265*c5591576SRob Johnston 			int32_t val;
266*c5591576SRob Johnston 
267*c5591576SRob Johnston 			if (nvpair_value_int32(nvp, &val) != 0)
268*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
269*c5591576SRob Johnston 
270*c5591576SRob Johnston 			tdg_xml_nvint32(fp, pad, pname, val);
271*c5591576SRob Johnston 			break;
272*c5591576SRob Johnston 		}
273*c5591576SRob Johnston 		case DATA_TYPE_UINT32: {
274*c5591576SRob Johnston 			uint32_t val;
275*c5591576SRob Johnston 
276*c5591576SRob Johnston 			if (nvpair_value_uint32(nvp, &val) != 0)
277*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
278*c5591576SRob Johnston 
279*c5591576SRob Johnston 			tdg_xml_nvuint32(fp, pad, pname, val);
280*c5591576SRob Johnston 			break;
281*c5591576SRob Johnston 		}
282*c5591576SRob Johnston 		case DATA_TYPE_INT64: {
283*c5591576SRob Johnston 			int64_t val;
284*c5591576SRob Johnston 
285*c5591576SRob Johnston 			if (nvpair_value_int64(nvp, &val) != 0)
286*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
287*c5591576SRob Johnston 
288*c5591576SRob Johnston 			tdg_xml_nvint64(fp, pad, pname, val);
289*c5591576SRob Johnston 			break;
290*c5591576SRob Johnston 		}
291*c5591576SRob Johnston 		case DATA_TYPE_UINT64: {
292*c5591576SRob Johnston 			uint64_t val;
293*c5591576SRob Johnston 
294*c5591576SRob Johnston 			if (nvpair_value_uint64(nvp, &val) != 0)
295*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
296*c5591576SRob Johnston 
297*c5591576SRob Johnston 			tdg_xml_nvuint64(fp, pad, pname, val);
298*c5591576SRob Johnston 			break;
299*c5591576SRob Johnston 		}
300*c5591576SRob Johnston 		case DATA_TYPE_DOUBLE: {
301*c5591576SRob Johnston 			double val;
302*c5591576SRob Johnston 
303*c5591576SRob Johnston 			if (nvpair_value_double(nvp, &val) != 0)
304*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
305*c5591576SRob Johnston 
306*c5591576SRob Johnston 			tdg_xml_nvdbl(fp, pad, pname, val);
307*c5591576SRob Johnston 			break;
308*c5591576SRob Johnston 		}
309*c5591576SRob Johnston 		case DATA_TYPE_STRING: {
310*c5591576SRob Johnston 			char *val;
311*c5591576SRob Johnston 
312*c5591576SRob Johnston 			if (nvpair_value_string(nvp, &val) != 0)
313*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
314*c5591576SRob Johnston 
315*c5591576SRob Johnston 			tdg_xml_nvstring(fp, pad, pname, val);
316*c5591576SRob Johnston 			break;
317*c5591576SRob Johnston 		}
318*c5591576SRob Johnston 		case DATA_TYPE_NVLIST: {
319*c5591576SRob Johnston 			nvlist_t *nvl;
320*c5591576SRob Johnston 
321*c5591576SRob Johnston 			if (nvpair_value_nvlist(nvp, &nvl) != 0)
322*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
323*c5591576SRob Johnston 
324*c5591576SRob Johnston 			if (serialize_nvpair_nvlist(thp, fp, pad + 2, pname,
325*c5591576SRob Johnston 			    nvl) != 0) {
326*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
327*c5591576SRob Johnston 			}
328*c5591576SRob Johnston 			break;
329*c5591576SRob Johnston 		}
330*c5591576SRob Johnston 		case DATA_TYPE_INT32_ARRAY: {
331*c5591576SRob Johnston 			uint_t nelems;
332*c5591576SRob Johnston 			int32_t *val;
333*c5591576SRob Johnston 
334*c5591576SRob Johnston 			if (nvpair_value_int32_array(nvp, &val, &nelems) != 0)
335*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
336*c5591576SRob Johnston 
337*c5591576SRob Johnston 			tdg_xml_nvint32arr(fp, pad + 2, pname, val, nelems);
338*c5591576SRob Johnston 
339*c5591576SRob Johnston 			break;
340*c5591576SRob Johnston 		}
341*c5591576SRob Johnston 		case DATA_TYPE_UINT32_ARRAY: {
342*c5591576SRob Johnston 			uint_t nelems;
343*c5591576SRob Johnston 			uint32_t *val;
344*c5591576SRob Johnston 
345*c5591576SRob Johnston 			if (nvpair_value_uint32_array(nvp, &val, &nelems) != 0)
346*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
347*c5591576SRob Johnston 
348*c5591576SRob Johnston 			tdg_xml_nvuint32arr(fp, pad + 2, pname,  val, nelems);
349*c5591576SRob Johnston 
350*c5591576SRob Johnston 			break;
351*c5591576SRob Johnston 		}
352*c5591576SRob Johnston 		case DATA_TYPE_INT64_ARRAY: {
353*c5591576SRob Johnston 			uint_t nelems;
354*c5591576SRob Johnston 			int64_t *val;
355*c5591576SRob Johnston 
356*c5591576SRob Johnston 			if (nvpair_value_int64_array(nvp, &val, &nelems) != 0)
357*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
358*c5591576SRob Johnston 
359*c5591576SRob Johnston 			tdg_xml_nvint64arr(fp, pad + 2, pname,  val, nelems);
360*c5591576SRob Johnston 
361*c5591576SRob Johnston 			break;
362*c5591576SRob Johnston 		}
363*c5591576SRob Johnston 		case DATA_TYPE_UINT64_ARRAY: {
364*c5591576SRob Johnston 			uint_t nelems;
365*c5591576SRob Johnston 			uint64_t *val;
366*c5591576SRob Johnston 
367*c5591576SRob Johnston 			if (nvpair_value_uint64_array(nvp, &val, &nelems) != 0)
368*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
369*c5591576SRob Johnston 
370*c5591576SRob Johnston 			tdg_xml_nvuint64arr(fp, pad + 2, pname,  val, nelems);
371*c5591576SRob Johnston 
372*c5591576SRob Johnston 			break;
373*c5591576SRob Johnston 		}
374*c5591576SRob Johnston 		case DATA_TYPE_STRING_ARRAY: {
375*c5591576SRob Johnston 			uint_t nelems;
376*c5591576SRob Johnston 			char **val;
377*c5591576SRob Johnston 
378*c5591576SRob Johnston 			if (nvpair_value_string_array(nvp, &val, &nelems) != 0)
379*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
380*c5591576SRob Johnston 
381*c5591576SRob Johnston 			tdg_xml_nvarray(fp, pad, pname, TDG_XML_STRING_ARR);
382*c5591576SRob Johnston 			for (uint_t i = 0; i < nelems; i++) {
383*c5591576SRob Johnston 				(void) fprintf(fp, "%*s<%s %s='%s' />\n",
384*c5591576SRob Johnston 				    (pad + 2), "", TDG_XML_NVPAIR,
385*c5591576SRob Johnston 				    TDG_XML_VALUE, val[i]);
386*c5591576SRob Johnston 			}
387*c5591576SRob Johnston 			(void) fprintf(fp, "%*s</%s>\n", (pad + 2), "",
388*c5591576SRob Johnston 			    TDG_XML_NVPAIR);
389*c5591576SRob Johnston 
390*c5591576SRob Johnston 			break;
391*c5591576SRob Johnston 		}
392*c5591576SRob Johnston 		case DATA_TYPE_NVLIST_ARRAY: {
393*c5591576SRob Johnston 			uint_t nelems;
394*c5591576SRob Johnston 			nvlist_t **val;
395*c5591576SRob Johnston 
396*c5591576SRob Johnston 			if (nvpair_value_nvlist_array(nvp, &val, &nelems) != 0)
397*c5591576SRob Johnston 				return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
398*c5591576SRob Johnston 
399*c5591576SRob Johnston 			tdg_xml_nvarray(fp, pad, pname, TDG_XML_NVLIST_ARR);
400*c5591576SRob Johnston 			for (uint_t i = 0; i < nelems; i++) {
401*c5591576SRob Johnston 				nvpair_t *elem = NULL;
402*c5591576SRob Johnston 
403*c5591576SRob Johnston 				(void) fprintf(fp, "%*s<%s>\n", (pad + 2), "",
404*c5591576SRob Johnston 				    TDG_XML_NVLIST);
405*c5591576SRob Johnston 
406*c5591576SRob Johnston 				while ((elem = nvlist_next_nvpair(val[i],
407*c5591576SRob Johnston 				    elem)) != NULL) {
408*c5591576SRob Johnston 					char *nvname = nvpair_name(elem);
409*c5591576SRob Johnston 
410*c5591576SRob Johnston 					if (serialize_nvpair(thp, fp,
411*c5591576SRob Johnston 					    (pad + 4), nvname, elem) != 0) {
412*c5591576SRob Johnston 						/* errno set */
413*c5591576SRob Johnston 						return (-1);
414*c5591576SRob Johnston 					}
415*c5591576SRob Johnston 				}
416*c5591576SRob Johnston 
417*c5591576SRob Johnston 				(void) fprintf(fp, "%*s</%s>\n", (pad + 2), "",
418*c5591576SRob Johnston 				    TDG_XML_NVLIST);
419*c5591576SRob Johnston 			}
420*c5591576SRob Johnston 			(void) fprintf(fp, "%*s</%s>\n", pad, "",
421*c5591576SRob Johnston 			    TDG_XML_NVPAIR);
422*c5591576SRob Johnston 
423*c5591576SRob Johnston 			break;
424*c5591576SRob Johnston 		}
425*c5591576SRob Johnston 		default:
426*c5591576SRob Johnston 			topo_dprintf(thp, TOPO_DBG_XML, "Invalid nvpair data "
427*c5591576SRob Johnston 			    "type: %d\n", type);
428*c5591576SRob Johnston 			(void) topo_hdl_seterrno(thp, ETOPO_MOD_XENUM);
429*c5591576SRob Johnston 			return (-1);
430*c5591576SRob Johnston 	}
431*c5591576SRob Johnston 	return (0);
432*c5591576SRob Johnston }
433*c5591576SRob Johnston 
434*c5591576SRob Johnston static int
serialize_edge(topo_hdl_t * thp,topo_edge_t * edge,boolean_t last_edge,void * arg)435*c5591576SRob Johnston serialize_edge(topo_hdl_t *thp, topo_edge_t *edge, boolean_t last_edge,
436*c5591576SRob Johnston     void *arg)
437*c5591576SRob Johnston {
438*c5591576SRob Johnston 	nvlist_t *fmri = NULL;
439*c5591576SRob Johnston 	char *fmristr;
440*c5591576SRob Johnston 	int err;
441*c5591576SRob Johnston 	tnode_t *tn;
442*c5591576SRob Johnston 	FILE *fp = (FILE *)arg;
443*c5591576SRob Johnston 
444*c5591576SRob Johnston 	tn = topo_vertex_node(edge->tve_vertex);
445*c5591576SRob Johnston 	if (topo_node_resource(tn, &fmri, &err) != 0 ||
446*c5591576SRob Johnston 	    topo_fmri_nvl2str(thp, fmri, &fmristr, &err) != 0) {
447*c5591576SRob Johnston 		/* errno set */
448*c5591576SRob Johnston 		nvlist_free(fmri);
449*c5591576SRob Johnston 		return (TOPO_WALK_ERR);
450*c5591576SRob Johnston 	}
451*c5591576SRob Johnston 	nvlist_free(fmri);
452*c5591576SRob Johnston 
453*c5591576SRob Johnston 	(void) fprintf(fp, "%*s<%s %s='%s' />\n", 4, "", TDG_XML_EDGE,
454*c5591576SRob Johnston 	    TDG_XML_FMRI, fmristr);
455*c5591576SRob Johnston 	topo_hdl_strfree(thp, fmristr);
456*c5591576SRob Johnston 
457*c5591576SRob Johnston 	return (TOPO_WALK_NEXT);
458*c5591576SRob Johnston }
459*c5591576SRob Johnston 
460*c5591576SRob Johnston /*
461*c5591576SRob Johnston  * Some node property values aren't available unless we go through the libtopo
462*c5591576SRob Johnston  * API's topo_prop_get_* routines. We do that here to make sure the nodes have
463*c5591576SRob Johnston  * all of their properties populated, then we vector off to type-specific
464*c5591576SRob Johnston  * XML serialization functions.
465*c5591576SRob Johnston  */
466*c5591576SRob Johnston static int
serialize_property(topo_hdl_t * thp,FILE * fp,uint_t pad,tnode_t * tn,topo_propval_t * pv,const char * pgname)467*c5591576SRob Johnston serialize_property(topo_hdl_t *thp, FILE *fp, uint_t pad, tnode_t *tn,
468*c5591576SRob Johnston     topo_propval_t *pv, const char *pgname)
469*c5591576SRob Johnston {
470*c5591576SRob Johnston 	topo_type_t type = pv->tp_type;
471*c5591576SRob Johnston 	const char *pname = pv->tp_name;
472*c5591576SRob Johnston 	int err;
473*c5591576SRob Johnston 	char *name = TDG_XML_PROP_VALUE;
474*c5591576SRob Johnston 
475*c5591576SRob Johnston 	switch (type) {
476*c5591576SRob Johnston 		case TOPO_TYPE_INT32: {
477*c5591576SRob Johnston 			int32_t val;
478*c5591576SRob Johnston 
479*c5591576SRob Johnston 			if (topo_prop_get_int32(tn, pgname, pname, &val,
480*c5591576SRob Johnston 			    &err) != 0)
481*c5591576SRob Johnston 				return (-1);
482*c5591576SRob Johnston 
483*c5591576SRob Johnston 			tdg_xml_nvint32(fp, pad, name, val);
484*c5591576SRob Johnston 			break;
485*c5591576SRob Johnston 		}
486*c5591576SRob Johnston 		case TOPO_TYPE_UINT32: {
487*c5591576SRob Johnston 			uint32_t val;
488*c5591576SRob Johnston 
489*c5591576SRob Johnston 			if (topo_prop_get_uint32(tn, pgname, pname, &val,
490*c5591576SRob Johnston 			    &err) != 0)
491*c5591576SRob Johnston 				return (-1);
492*c5591576SRob Johnston 
493*c5591576SRob Johnston 			tdg_xml_nvuint32(fp, pad, name, val);
494*c5591576SRob Johnston 			break;
495*c5591576SRob Johnston 		}
496*c5591576SRob Johnston 		case TOPO_TYPE_INT64: {
497*c5591576SRob Johnston 			int64_t val;
498*c5591576SRob Johnston 
499*c5591576SRob Johnston 			if (topo_prop_get_int64(tn, pgname, pname, &val,
500*c5591576SRob Johnston 			    &err) != 0)
501*c5591576SRob Johnston 				return (-1);
502*c5591576SRob Johnston 
503*c5591576SRob Johnston 			tdg_xml_nvint64(fp, pad, name, val);
504*c5591576SRob Johnston 			break;
505*c5591576SRob Johnston 		}
506*c5591576SRob Johnston 		case TOPO_TYPE_UINT64: {
507*c5591576SRob Johnston 			uint64_t val;
508*c5591576SRob Johnston 
509*c5591576SRob Johnston 			if (topo_prop_get_uint64(tn, pgname, pname, &val,
510*c5591576SRob Johnston 			    &err) != 0)
511*c5591576SRob Johnston 				return (-1);
512*c5591576SRob Johnston 
513*c5591576SRob Johnston 			tdg_xml_nvuint64(fp, pad, name, val);
514*c5591576SRob Johnston 			break;
515*c5591576SRob Johnston 		}
516*c5591576SRob Johnston 		case TOPO_TYPE_STRING: {
517*c5591576SRob Johnston 			char *val;
518*c5591576SRob Johnston 
519*c5591576SRob Johnston 			if (topo_prop_get_string(tn, pgname, pname, &val,
520*c5591576SRob Johnston 			    &err) != 0)
521*c5591576SRob Johnston 				return (-1);
522*c5591576SRob Johnston 
523*c5591576SRob Johnston 			tdg_xml_nvstring(fp, pad, name, val);
524*c5591576SRob Johnston 
525*c5591576SRob Johnston 			topo_hdl_strfree(thp, val);
526*c5591576SRob Johnston 			break;
527*c5591576SRob Johnston 		}
528*c5591576SRob Johnston 		case TOPO_TYPE_FMRI: {
529*c5591576SRob Johnston 			nvlist_t *nvl;
530*c5591576SRob Johnston 
531*c5591576SRob Johnston 			if (topo_prop_get_fmri(tn, pgname, pname, &nvl,
532*c5591576SRob Johnston 			    &err) != 0)
533*c5591576SRob Johnston 				return (-1);
534*c5591576SRob Johnston 
535*c5591576SRob Johnston 			if (serialize_nvpair_nvlist(thp, fp, pad + 2, name,
536*c5591576SRob Johnston 			    nvl) != 0) {
537*c5591576SRob Johnston 				nvlist_free(nvl);
538*c5591576SRob Johnston 				return (-1);
539*c5591576SRob Johnston 			}
540*c5591576SRob Johnston 
541*c5591576SRob Johnston 			nvlist_free(nvl);
542*c5591576SRob Johnston 			break;
543*c5591576SRob Johnston 		}
544*c5591576SRob Johnston 		case TOPO_TYPE_INT32_ARRAY: {
545*c5591576SRob Johnston 			uint_t nelems;
546*c5591576SRob Johnston 			int32_t *val;
547*c5591576SRob Johnston 
548*c5591576SRob Johnston 			if (topo_prop_get_int32_array(tn, pgname, pname, &val,
549*c5591576SRob Johnston 			    &nelems, &err) != 0)
550*c5591576SRob Johnston 				return (-1);
551*c5591576SRob Johnston 
552*c5591576SRob Johnston 			tdg_xml_nvint32arr(fp, pad, pname, val, nelems);
553*c5591576SRob Johnston 			topo_hdl_free(thp, val, (sizeof (int32_t) * nelems));
554*c5591576SRob Johnston 			break;
555*c5591576SRob Johnston 		}
556*c5591576SRob Johnston 		case TOPO_TYPE_UINT32_ARRAY: {
557*c5591576SRob Johnston 			uint_t nelems;
558*c5591576SRob Johnston 			uint32_t *val;
559*c5591576SRob Johnston 
560*c5591576SRob Johnston 			if (topo_prop_get_uint32_array(tn, pgname, pname, &val,
561*c5591576SRob Johnston 			    &nelems, &err) != 0)
562*c5591576SRob Johnston 				return (-1);
563*c5591576SRob Johnston 
564*c5591576SRob Johnston 			tdg_xml_nvuint32arr(fp, pad, pname,  val, nelems);
565*c5591576SRob Johnston 			topo_hdl_free(thp, val, (sizeof (uint32_t) * nelems));
566*c5591576SRob Johnston 			break;
567*c5591576SRob Johnston 		}
568*c5591576SRob Johnston 		case TOPO_TYPE_INT64_ARRAY: {
569*c5591576SRob Johnston 			uint_t nelems;
570*c5591576SRob Johnston 			int64_t *val;
571*c5591576SRob Johnston 
572*c5591576SRob Johnston 			if (topo_prop_get_int64_array(tn, pgname, pname, &val,
573*c5591576SRob Johnston 			    &nelems, &err) != 0)
574*c5591576SRob Johnston 				return (-1);
575*c5591576SRob Johnston 
576*c5591576SRob Johnston 			tdg_xml_nvint64arr(fp, pad, pname,  val, nelems);
577*c5591576SRob Johnston 			topo_hdl_free(thp, val, (sizeof (int64_t) * nelems));
578*c5591576SRob Johnston 			break;
579*c5591576SRob Johnston 		}
580*c5591576SRob Johnston 		case TOPO_TYPE_UINT64_ARRAY: {
581*c5591576SRob Johnston 			uint_t nelems;
582*c5591576SRob Johnston 			uint64_t *val;
583*c5591576SRob Johnston 
584*c5591576SRob Johnston 			if (topo_prop_get_uint64_array(tn, pgname, pname, &val,
585*c5591576SRob Johnston 			    &nelems, &err) != 0)
586*c5591576SRob Johnston 				return (-1);
587*c5591576SRob Johnston 
588*c5591576SRob Johnston 			tdg_xml_nvuint64arr(fp, pad, pname,  val, nelems);
589*c5591576SRob Johnston 			topo_hdl_free(thp, val, (sizeof (uint64_t) * nelems));
590*c5591576SRob Johnston 			break;
591*c5591576SRob Johnston 		}
592*c5591576SRob Johnston 		default:
593*c5591576SRob Johnston 			topo_dprintf(thp, TOPO_DBG_XML, "Invalid nvpair data "
594*c5591576SRob Johnston 			    "type: %d\n", type);
595*c5591576SRob Johnston 			(void) topo_hdl_seterrno(thp, ETOPO_MOD_XENUM);
596*c5591576SRob Johnston 			return (-1);
597*c5591576SRob Johnston 	}
598*c5591576SRob Johnston 	return (0);
599*c5591576SRob Johnston }
600*c5591576SRob Johnston 
601*c5591576SRob Johnston static int
serialize_pgroups(topo_hdl_t * thp,FILE * fp,tnode_t * tn)602*c5591576SRob Johnston serialize_pgroups(topo_hdl_t *thp, FILE *fp, tnode_t *tn)
603*c5591576SRob Johnston {
604*c5591576SRob Johnston 	topo_pgroup_t *pg;
605*c5591576SRob Johnston 	uint_t npgs = 0;
606*c5591576SRob Johnston 
607*c5591576SRob Johnston 	for (pg = topo_list_next(&tn->tn_pgroups); pg != NULL;
608*c5591576SRob Johnston 	    pg = topo_list_next(pg)) {
609*c5591576SRob Johnston 
610*c5591576SRob Johnston 		npgs++;
611*c5591576SRob Johnston 	}
612*c5591576SRob Johnston 
613*c5591576SRob Johnston 	tdg_xml_nvarray(fp, 2, TDG_XML_PGROUPS, TDG_XML_NVLIST_ARR);
614*c5591576SRob Johnston 
615*c5591576SRob Johnston 	for (pg = topo_list_next(&tn->tn_pgroups); pg != NULL;
616*c5591576SRob Johnston 	    pg = topo_list_next(pg)) {
617*c5591576SRob Johnston 
618*c5591576SRob Johnston 		topo_proplist_t *pvl;
619*c5591576SRob Johnston 		uint_t nprops = 0;
620*c5591576SRob Johnston 
621*c5591576SRob Johnston 		(void) fprintf(fp, "%*s<%s>\n", 4, "", TDG_XML_NVLIST);
622*c5591576SRob Johnston 		tdg_xml_nvstring(fp, 6, TOPO_PROP_GROUP_NAME,
623*c5591576SRob Johnston 		    pg->tpg_info->tpi_name);
624*c5591576SRob Johnston 
625*c5591576SRob Johnston 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
626*c5591576SRob Johnston 		    pvl = topo_list_next(pvl))
627*c5591576SRob Johnston 			nprops++;
628*c5591576SRob Johnston 
629*c5591576SRob Johnston 		tdg_xml_nvarray(fp, 6, TDG_XML_PVALS, TDG_XML_NVLIST_ARR);
630*c5591576SRob Johnston 
631*c5591576SRob Johnston 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
632*c5591576SRob Johnston 		    pvl = topo_list_next(pvl)) {
633*c5591576SRob Johnston 
634*c5591576SRob Johnston 			topo_propval_t *pv = pvl->tp_pval;
635*c5591576SRob Johnston 
636*c5591576SRob Johnston 			(void) fprintf(fp, "%*s<%s>\n", 8, "", TDG_XML_NVLIST);
637*c5591576SRob Johnston 			tdg_xml_nvstring(fp, 10, TDG_XML_PROP_NAME,
638*c5591576SRob Johnston 			    pv->tp_name);
639*c5591576SRob Johnston 			tdg_xml_nvuint32(fp, 10, TDG_XML_PROP_TYPE,
640*c5591576SRob Johnston 			    pv->tp_type);
641*c5591576SRob Johnston 
642*c5591576SRob Johnston 			if (serialize_property(thp, fp, 10, tn, pv,
643*c5591576SRob Johnston 			    pg->tpg_info->tpi_name) != 0) {
644*c5591576SRob Johnston 				/* errno set */
645*c5591576SRob Johnston 				return (-1);
646*c5591576SRob Johnston 			}
647*c5591576SRob Johnston 			(void) fprintf(fp, "%*s</%s>\n", 8, "",
648*c5591576SRob Johnston 			    TDG_XML_NVLIST);
649*c5591576SRob Johnston 		}
650*c5591576SRob Johnston 
651*c5591576SRob Johnston 		(void) fprintf(fp, "%*s</%s> <!-- %s -->\n", 6, "",
652*c5591576SRob Johnston 		    TDG_XML_NVPAIR, TDG_XML_PVALS);
653*c5591576SRob Johnston 		(void) fprintf(fp, "%*s</%s>\n", 4, "", TDG_XML_NVLIST);
654*c5591576SRob Johnston 	}
655*c5591576SRob Johnston 	(void) fprintf(fp, "%*s</%s> <!-- %s -->\n", 2, "", TDG_XML_NVPAIR,
656*c5591576SRob Johnston 	    TDG_XML_PGROUPS);
657*c5591576SRob Johnston 
658*c5591576SRob Johnston 	return (0);
659*c5591576SRob Johnston }
660*c5591576SRob Johnston 
661*c5591576SRob Johnston static int
serialize_vertex(topo_hdl_t * thp,topo_vertex_t * vtx,boolean_t last_vtx,void * arg)662*c5591576SRob Johnston serialize_vertex(topo_hdl_t *thp, topo_vertex_t *vtx, boolean_t last_vtx,
663*c5591576SRob Johnston     void *arg)
664*c5591576SRob Johnston {
665*c5591576SRob Johnston 	nvlist_t *fmri = NULL;
666*c5591576SRob Johnston 	char *fmristr;
667*c5591576SRob Johnston 	tnode_t *tn;
668*c5591576SRob Johnston 	int err;
669*c5591576SRob Johnston 	FILE *fp = (FILE *)arg;
670*c5591576SRob Johnston 
671*c5591576SRob Johnston 	tn = topo_vertex_node(vtx);
672*c5591576SRob Johnston 	if (topo_node_resource(tn, &fmri, &err) != 0 ||
673*c5591576SRob Johnston 	    topo_fmri_nvl2str(thp, fmri, &fmristr, &err) != 0) {
674*c5591576SRob Johnston 		/* errno set */
675*c5591576SRob Johnston 		nvlist_free(fmri);
676*c5591576SRob Johnston 		return (TOPO_WALK_ERR);
677*c5591576SRob Johnston 	}
678*c5591576SRob Johnston 	nvlist_free(fmri);
679*c5591576SRob Johnston 
680*c5591576SRob Johnston 	(void) fprintf(fp, "<%s %s='%s' %s='0x%" PRIx64 "' %s='%s'>\n",
681*c5591576SRob Johnston 	    TDG_XML_VERTEX, TDG_XML_NAME, topo_node_name(tn),
682*c5591576SRob Johnston 	    TDG_XML_INSTANCE, topo_node_instance(tn),
683*c5591576SRob Johnston 	    TDG_XML_FMRI, fmristr);
684*c5591576SRob Johnston 
685*c5591576SRob Johnston 	topo_hdl_strfree(thp, fmristr);
686*c5591576SRob Johnston 
687*c5591576SRob Johnston 	if (serialize_pgroups(thp, fp, tn) != 0) {
688*c5591576SRob Johnston 		/* errno set */
689*c5591576SRob Johnston 		return (TOPO_WALK_ERR);
690*c5591576SRob Johnston 	}
691*c5591576SRob Johnston 
692*c5591576SRob Johnston 	if (vtx->tvt_noutgoing != 0) {
693*c5591576SRob Johnston 		(void) fprintf(fp, "  <%s>\n", TDG_XML_OUTEDGES);
694*c5591576SRob Johnston 
695*c5591576SRob Johnston 		if (topo_edge_iter(thp, vtx, serialize_edge, fp) != 0) {
696*c5591576SRob Johnston 			topo_dprintf(thp, TOPO_DBG_XML, "failed to iterate "
697*c5591576SRob Johnston 			    "edges on %s=%" PRIx64 "\n", topo_node_name(tn),
698*c5591576SRob Johnston 			    topo_node_instance(tn));
699*c5591576SRob Johnston 			/* errno set */
700*c5591576SRob Johnston 			return (TOPO_WALK_ERR);
701*c5591576SRob Johnston 		}
702*c5591576SRob Johnston 		(void) fprintf(fp, "  </%s>\n", TDG_XML_OUTEDGES);
703*c5591576SRob Johnston 	}
704*c5591576SRob Johnston 	(void) fprintf(fp, "</%s>\n\n", TDG_XML_VERTEX);
705*c5591576SRob Johnston 
706*c5591576SRob Johnston 	return (TOPO_WALK_NEXT);
707*c5591576SRob Johnston }
708*c5591576SRob Johnston 
709*c5591576SRob Johnston /*
710*c5591576SRob Johnston  * This function takes a topo_digraph_t and serializes it to XML.
711*c5591576SRob Johnston  *
712*c5591576SRob Johnston  * The schema is described in detail in:
713*c5591576SRob Johnston  * usr/src/lib/fm/topo/maps/common/digraph-topology.dtd.1
714*c5591576SRob Johnston  *
715*c5591576SRob Johnston  * On success, this function writes the XML to the specified file and
716*c5591576SRob Johnston  * returns 0.
717*c5591576SRob Johnston  *
718*c5591576SRob Johnston  * On failure, this function returns -1.
719*c5591576SRob Johnston  */
720*c5591576SRob Johnston int
topo_digraph_serialize(topo_hdl_t * thp,topo_digraph_t * tdg,FILE * fp)721*c5591576SRob Johnston topo_digraph_serialize(topo_hdl_t *thp, topo_digraph_t *tdg, FILE *fp)
722*c5591576SRob Johnston {
723*c5591576SRob Johnston 	struct utsname uts = { 0 };
724*c5591576SRob Johnston 	time_t utc_time;
725*c5591576SRob Johnston 	char tstamp[64];
726*c5591576SRob Johnston 	int ret;
727*c5591576SRob Johnston 
728*c5591576SRob Johnston 	if ((ret = uname(&uts)) < 0) {
729*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "uname failed (ret = %d)\n",
730*c5591576SRob Johnston 		    ret);
731*c5591576SRob Johnston 		return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
732*c5591576SRob Johnston 	}
733*c5591576SRob Johnston 
734*c5591576SRob Johnston 	if (time(&utc_time) < 0) {
735*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "uname failed (%s)\n",
736*c5591576SRob Johnston 		    strerror(errno));
737*c5591576SRob Johnston 		return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
738*c5591576SRob Johnston 	}
739*c5591576SRob Johnston 
740*c5591576SRob Johnston 	/*
741*c5591576SRob Johnston 	 * strftime returns 0 if the size of the result is larger than the
742*c5591576SRob Johnston 	 * buffer size passed in to it.  We've sized tstamp to be pretty
743*c5591576SRob Johnston 	 * large, so this really shouldn't happen.
744*c5591576SRob Johnston 	 */
745*c5591576SRob Johnston 	if (strftime(tstamp, sizeof (tstamp), "%Y-%m-%dT%H:%M:%SZ",
746*c5591576SRob Johnston 	    gmtime(&utc_time)) == 0) {
747*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "strftime failed\n");
748*c5591576SRob Johnston 		return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
749*c5591576SRob Johnston 	}
750*c5591576SRob Johnston 
751*c5591576SRob Johnston 	(void) fprintf(fp, "<?xml version=\"1.0\"?>\n");
752*c5591576SRob Johnston 	(void) fprintf(fp, "<!DOCTYPE topology SYSTEM \"%s\">\n", TDG_DTD);
753*c5591576SRob Johnston 	(void) fprintf(fp, "<%s %s='%s' %s='%s' %s='%s' %s='%s' %s='%s'>\n",
754*c5591576SRob Johnston 	    TDG_XML_TOPO_DIGRAPH, TDG_XML_SCHEME, tdg->tdg_scheme,
755*c5591576SRob Johnston 	    TDG_XML_NODENAME, uts.nodename, TDG_XML_OSVERSION, uts.version,
756*c5591576SRob Johnston 	    TDG_XML_PRODUCT, thp->th_product, TDG_XML_TSTAMP, tstamp);
757*c5591576SRob Johnston 	(void) fprintf(fp, "<%s>\n", TDG_XML_VERTICES);
758*c5591576SRob Johnston 
759*c5591576SRob Johnston 	if (topo_vertex_iter(thp, tdg, serialize_vertex, fp) != 0) {
760*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "\nfailed to iterate "
761*c5591576SRob Johnston 		    "vertices\n");
762*c5591576SRob Johnston 		/* errno set */
763*c5591576SRob Johnston 		return (-1);
764*c5591576SRob Johnston 	}
765*c5591576SRob Johnston 
766*c5591576SRob Johnston 	(void) fprintf(fp, "</%s>\n", TDG_XML_VERTICES);
767*c5591576SRob Johnston 	(void) fprintf(fp, "</%s>\n", TDG_XML_TOPO_DIGRAPH);
768*c5591576SRob Johnston 
769*c5591576SRob Johnston 	if (ferror(fp) != 0) {
770*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "An unknown error ocurrred "
771*c5591576SRob Johnston 		    "while writing out the serialize topology.");
772*c5591576SRob Johnston 		return (topo_hdl_seterrno(thp, ETOPO_UNKNOWN));
773*c5591576SRob Johnston 	}
774*c5591576SRob Johnston 	return (0);
775*c5591576SRob Johnston }
776*c5591576SRob Johnston 
777*c5591576SRob Johnston static xmlNodePtr
get_child_by_name(xmlNodePtr xn,xmlChar * name)778*c5591576SRob Johnston get_child_by_name(xmlNodePtr xn, xmlChar *name)
779*c5591576SRob Johnston {
780*c5591576SRob Johnston 	for (xmlNodePtr cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
781*c5591576SRob Johnston 		if (xmlStrcmp(cn->name, name) == 0)
782*c5591576SRob Johnston 			return (cn);
783*c5591576SRob Johnston 
784*c5591576SRob Johnston 	return (NULL);
785*c5591576SRob Johnston }
786*c5591576SRob Johnston 
787*c5591576SRob Johnston static void
dump_xml_node(topo_hdl_t * thp,xmlNodePtr xn)788*c5591576SRob Johnston dump_xml_node(topo_hdl_t *thp, xmlNodePtr xn)
789*c5591576SRob Johnston {
790*c5591576SRob Johnston 	topo_dprintf(thp, TOPO_DBG_XML, "node: %s", (char *)xn->name);
791*c5591576SRob Johnston 	for (xmlAttrPtr attr = xn->properties; attr != NULL; attr = attr->next)
792*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "attribute: %s",
793*c5591576SRob Johnston 		    (char *)attr->name);
794*c5591576SRob Johnston 
795*c5591576SRob Johnston 	for (xmlNodePtr cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
796*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "\tchild node: %s",
797*c5591576SRob Johnston 		    (char *)cn->name);
798*c5591576SRob Johnston }
799*c5591576SRob Johnston 
800*c5591576SRob Johnston struct edge_cb_arg {
801*c5591576SRob Johnston 	const char	*from_fmri;
802*c5591576SRob Johnston 	const char	*to_fmri;
803*c5591576SRob Johnston 	topo_vertex_t	*from_vtx;
804*c5591576SRob Johnston 	topo_vertex_t	*to_vtx;
805*c5591576SRob Johnston };
806*c5591576SRob Johnston 
807*c5591576SRob Johnston static int
edge_cb(topo_hdl_t * thp,topo_vertex_t * vtx,boolean_t last_vtx,void * arg)808*c5591576SRob Johnston edge_cb(topo_hdl_t *thp, topo_vertex_t *vtx, boolean_t last_vtx, void *arg)
809*c5591576SRob Johnston {
810*c5591576SRob Johnston 	struct edge_cb_arg *cbarg = arg;
811*c5591576SRob Johnston 	tnode_t *tn;
812*c5591576SRob Johnston 	nvlist_t *fmri = NULL;
813*c5591576SRob Johnston 	char *fmristr = NULL;
814*c5591576SRob Johnston 	int err;
815*c5591576SRob Johnston 
816*c5591576SRob Johnston 	tn = topo_vertex_node(vtx);
817*c5591576SRob Johnston 	if (topo_node_resource(tn, &fmri, &err) != 0 ||
818*c5591576SRob Johnston 	    topo_fmri_nvl2str(thp, fmri, &fmristr, &err) != 0) {
819*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "failed to convert FMRI for "
820*c5591576SRob Johnston 		    "%s=%" PRIx64 " to a string\n", topo_node_name(tn),
821*c5591576SRob Johnston 		    topo_node_instance(tn));
822*c5591576SRob Johnston 		if (thp->th_debug & TOPO_DBG_XML)
823*c5591576SRob Johnston 			nvlist_print(stdout, fmri);
824*c5591576SRob Johnston 		nvlist_free(fmri);
825*c5591576SRob Johnston 		return (TOPO_WALK_ERR);
826*c5591576SRob Johnston 	}
827*c5591576SRob Johnston 	nvlist_free(fmri);
828*c5591576SRob Johnston 
829*c5591576SRob Johnston 	if (strcmp(fmristr, cbarg->from_fmri) == 0)
830*c5591576SRob Johnston 		cbarg->from_vtx = vtx;
831*c5591576SRob Johnston 	else if (strcmp(fmristr, cbarg->to_fmri) == 0)
832*c5591576SRob Johnston 		cbarg->to_vtx = vtx;
833*c5591576SRob Johnston 
834*c5591576SRob Johnston 	topo_hdl_strfree(thp, fmristr);
835*c5591576SRob Johnston 	if (cbarg->from_vtx != NULL && cbarg->to_vtx != NULL)
836*c5591576SRob Johnston 		return (TOPO_WALK_TERMINATE);
837*c5591576SRob Johnston 	else
838*c5591576SRob Johnston 		return (TOPO_WALK_NEXT);
839*c5591576SRob Johnston }
840*c5591576SRob Johnston 
841*c5591576SRob Johnston static int
deserialize_edges(topo_hdl_t * thp,topo_mod_t * mod,topo_digraph_t * tdg,xmlChar * from_fmri,xmlNodePtr xn)842*c5591576SRob Johnston deserialize_edges(topo_hdl_t *thp, topo_mod_t *mod, topo_digraph_t *tdg,
843*c5591576SRob Johnston     xmlChar *from_fmri, xmlNodePtr xn)
844*c5591576SRob Johnston {
845*c5591576SRob Johnston 	for (xmlNodePtr cn = xn->xmlChildrenNode; cn != NULL;
846*c5591576SRob Johnston 	    cn = cn->next) {
847*c5591576SRob Johnston 		xmlChar *fmri;
848*c5591576SRob Johnston 		struct edge_cb_arg cbarg = { 0 };
849*c5591576SRob Johnston 
850*c5591576SRob Johnston 		if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_EDGE) != 0)
851*c5591576SRob Johnston 			continue;
852*c5591576SRob Johnston 
853*c5591576SRob Johnston 		if ((fmri = xmlGetProp(cn, (xmlChar *)TDG_XML_FMRI)) == NULL) {
854*c5591576SRob Johnston 			topo_dprintf(thp, TOPO_DBG_XML,
855*c5591576SRob Johnston 			    "error parsing %s element", (char *)cn->name);
856*c5591576SRob Johnston 			dump_xml_node(thp, cn);
857*c5591576SRob Johnston 			return (-1);
858*c5591576SRob Johnston 		}
859*c5591576SRob Johnston 		cbarg.from_fmri = (char *)from_fmri;
860*c5591576SRob Johnston 		cbarg.to_fmri = (char *)fmri;
861*c5591576SRob Johnston 
862*c5591576SRob Johnston 		if (topo_vertex_iter(mod->tm_hdl, tdg, edge_cb, &cbarg) != 0) {
863*c5591576SRob Johnston 			xmlFree(fmri);
864*c5591576SRob Johnston 			return (-1);
865*c5591576SRob Johnston 		}
866*c5591576SRob Johnston 		xmlFree(fmri);
867*c5591576SRob Johnston 
868*c5591576SRob Johnston 		if (cbarg.from_vtx == NULL || cbarg.to_vtx == NULL) {
869*c5591576SRob Johnston 			return (-1);
870*c5591576SRob Johnston 		}
871*c5591576SRob Johnston 		if (topo_edge_new(mod, cbarg.from_vtx, cbarg.to_vtx) != 0) {
872*c5591576SRob Johnston 			return (-1);
873*c5591576SRob Johnston 		}
874*c5591576SRob Johnston 	}
875*c5591576SRob Johnston 
876*c5591576SRob Johnston 	return (0);
877*c5591576SRob Johnston }
878*c5591576SRob Johnston 
879*c5591576SRob Johnston static int
add_edges(topo_hdl_t * thp,topo_mod_t * mod,topo_digraph_t * tdg,xmlNodePtr xn)880*c5591576SRob Johnston add_edges(topo_hdl_t *thp, topo_mod_t *mod, topo_digraph_t *tdg,
881*c5591576SRob Johnston     xmlNodePtr xn)
882*c5591576SRob Johnston {
883*c5591576SRob Johnston 	int ret = -1;
884*c5591576SRob Johnston 	nvlist_t *props = NULL;
885*c5591576SRob Johnston 	xmlChar *name = NULL, *fmri = NULL;
886*c5591576SRob Johnston 	xmlNodePtr cn;
887*c5591576SRob Johnston 	uint64_t inst;
888*c5591576SRob Johnston 
889*c5591576SRob Johnston 	if ((name = xmlGetProp(xn, (xmlChar *)TDG_XML_NAME)) == NULL ||
890*c5591576SRob Johnston 	    (fmri = xmlGetProp(xn, (xmlChar *)TDG_XML_FMRI)) == NULL ||
891*c5591576SRob Johnston 	    xmlattr_to_int(mod, xn, TDG_XML_INSTANCE, &inst) != 0) {
892*c5591576SRob Johnston 		goto fail;
893*c5591576SRob Johnston 	}
894*c5591576SRob Johnston 
895*c5591576SRob Johnston 	if ((cn = get_child_by_name(xn, (xmlChar *)TDG_XML_OUTEDGES)) !=
896*c5591576SRob Johnston 	    NULL) {
897*c5591576SRob Johnston 		if (deserialize_edges(thp, mod, tdg, fmri, cn) != 0)
898*c5591576SRob Johnston 			goto fail;
899*c5591576SRob Johnston 	}
900*c5591576SRob Johnston 	ret = 0;
901*c5591576SRob Johnston 
902*c5591576SRob Johnston fail:
903*c5591576SRob Johnston 	if (ret != 0) {
904*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "%s: error parsing %s element",
905*c5591576SRob Johnston 		    __func__, TDG_XML_VERTEX);
906*c5591576SRob Johnston 		dump_xml_node(thp, xn);
907*c5591576SRob Johnston 	}
908*c5591576SRob Johnston 	nvlist_free(props);
909*c5591576SRob Johnston 	if (name != NULL)
910*c5591576SRob Johnston 		xmlFree(name);
911*c5591576SRob Johnston 	if (fmri != NULL)
912*c5591576SRob Johnston 		xmlFree(fmri);
913*c5591576SRob Johnston 
914*c5591576SRob Johnston 	return (ret);
915*c5591576SRob Johnston }
916*c5591576SRob Johnston 
917*c5591576SRob Johnston static topo_pgroup_info_t pginfo = {
918*c5591576SRob Johnston 	NULL,
919*c5591576SRob Johnston 	TOPO_STABILITY_PRIVATE,
920*c5591576SRob Johnston 	TOPO_STABILITY_PRIVATE,
921*c5591576SRob Johnston 	1
922*c5591576SRob Johnston };
923*c5591576SRob Johnston 
924*c5591576SRob Johnston static int
add_props(topo_hdl_t * thp,topo_vertex_t * vtx,nvlist_t * pgroups)925*c5591576SRob Johnston add_props(topo_hdl_t *thp, topo_vertex_t *vtx, nvlist_t *pgroups)
926*c5591576SRob Johnston {
927*c5591576SRob Johnston 	tnode_t *tn;
928*c5591576SRob Johnston 	nvlist_t **pgs;
929*c5591576SRob Johnston 	uint_t npgs = 0;
930*c5591576SRob Johnston 
931*c5591576SRob Johnston 	tn = topo_vertex_node(vtx);
932*c5591576SRob Johnston 	if (nvlist_lookup_nvlist_array(pgroups, TDG_XML_PGROUPS, &pgs,
933*c5591576SRob Johnston 	    &npgs) != 0) {
934*c5591576SRob Johnston 		goto fail;
935*c5591576SRob Johnston 	}
936*c5591576SRob Johnston 
937*c5591576SRob Johnston 	for (uint_t i = 0; i < npgs; i++) {
938*c5591576SRob Johnston 		char *pgname;
939*c5591576SRob Johnston 		nvlist_t **props;
940*c5591576SRob Johnston 		uint_t nprops;
941*c5591576SRob Johnston 		int err;
942*c5591576SRob Johnston 
943*c5591576SRob Johnston 		if (nvlist_lookup_string(pgs[i], TDG_XML_PGROUP_NAME,
944*c5591576SRob Johnston 		    &pgname) != 0 ||
945*c5591576SRob Johnston 		    nvlist_lookup_nvlist_array(pgs[i], TDG_XML_PVALS, &props,
946*c5591576SRob Johnston 		    &nprops) != 0) {
947*c5591576SRob Johnston 			goto fail;
948*c5591576SRob Johnston 		}
949*c5591576SRob Johnston 		pginfo.tpi_name = pgname;
950*c5591576SRob Johnston 
951*c5591576SRob Johnston 		if (topo_pgroup_create(tn, &pginfo, &err) != 0) {
952*c5591576SRob Johnston 			topo_dprintf(thp, TOPO_DBG_XML, "failed to create "
953*c5591576SRob Johnston 			    "pgroup: %s", pgname);
954*c5591576SRob Johnston 			goto fail;
955*c5591576SRob Johnston 		}
956*c5591576SRob Johnston 		for (uint_t j = 0; j < nprops; j++) {
957*c5591576SRob Johnston 			if (topo_prop_setprop(tn, pgname, props[j],
958*c5591576SRob Johnston 			    TOPO_PROP_IMMUTABLE, props[j], &err) != 0) {
959*c5591576SRob Johnston 				topo_dprintf(thp, TOPO_DBG_XML, "failed to "
960*c5591576SRob Johnston 				    "set properties in pgroup: %s", pgname);
961*c5591576SRob Johnston 				goto fail;
962*c5591576SRob Johnston 			}
963*c5591576SRob Johnston 		}
964*c5591576SRob Johnston 	}
965*c5591576SRob Johnston 	return (0);
966*c5591576SRob Johnston fail:
967*c5591576SRob Johnston 	topo_dprintf(thp, TOPO_DBG_XML, "%s: error decoding properties for "
968*c5591576SRob Johnston 	    "%s=%" PRIx64, __func__, topo_node_name(tn),
969*c5591576SRob Johnston 	    topo_node_instance(tn));
970*c5591576SRob Johnston 	if (thp->th_debug & TOPO_DBG_XML)
971*c5591576SRob Johnston 		nvlist_print(stdout, pgroups);
972*c5591576SRob Johnston 
973*c5591576SRob Johnston 	return (-1);
974*c5591576SRob Johnston }
975*c5591576SRob Johnston 
976*c5591576SRob Johnston static void
free_nvlist_array(topo_hdl_t * thp,nvlist_t ** nvlarr,uint_t nelems)977*c5591576SRob Johnston free_nvlist_array(topo_hdl_t *thp, nvlist_t **nvlarr, uint_t nelems)
978*c5591576SRob Johnston {
979*c5591576SRob Johnston 	for (uint_t i = 0; i < nelems; i++) {
980*c5591576SRob Johnston 		if (nvlarr[i] != NULL)
981*c5591576SRob Johnston 			nvlist_free(nvlarr[i]);
982*c5591576SRob Johnston 	}
983*c5591576SRob Johnston 	topo_hdl_free(thp, nvlarr, nelems * sizeof (nvlist_t *));
984*c5591576SRob Johnston }
985*c5591576SRob Johnston 
986*c5591576SRob Johnston static boolean_t
is_overflow(topo_hdl_t * thp,uint64_t val,uint_t nbits)987*c5591576SRob Johnston is_overflow(topo_hdl_t *thp, uint64_t val, uint_t nbits)
988*c5591576SRob Johnston {
989*c5591576SRob Johnston 	if ((val >> nbits) != 0) {
990*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "value exceeds %u bits", nbits);
991*c5591576SRob Johnston 		return (B_TRUE);
992*c5591576SRob Johnston 	}
993*c5591576SRob Johnston 	return (B_FALSE);
994*c5591576SRob Johnston }
995*c5591576SRob Johnston 
996*c5591576SRob Johnston /*
997*c5591576SRob Johnston  * Recursive function for parsing nvpair XML elements, which can contain
998*c5591576SRob Johnston  * nested nvlist and nvpair elements.
999*c5591576SRob Johnston  */
1000*c5591576SRob Johnston static int
deserialize_nvpair(topo_hdl_t * thp,topo_mod_t * mod,nvlist_t * nvl,xmlNodePtr xn)1001*c5591576SRob Johnston deserialize_nvpair(topo_hdl_t *thp, topo_mod_t *mod, nvlist_t *nvl,
1002*c5591576SRob Johnston     xmlNodePtr xn)
1003*c5591576SRob Johnston {
1004*c5591576SRob Johnston 	int ret = -1;
1005*c5591576SRob Johnston 	xmlChar *name = NULL, *type = NULL, *sval = NULL;
1006*c5591576SRob Johnston 	uint64_t val;
1007*c5591576SRob Johnston 
1008*c5591576SRob Johnston 	if ((name = xmlGetProp(xn, (xmlChar *)TDG_XML_NAME)) == NULL ||
1009*c5591576SRob Johnston 	    (type = xmlGetProp(xn, (xmlChar *)TDG_XML_TYPE)) == NULL) {
1010*c5591576SRob Johnston 		goto fail;
1011*c5591576SRob Johnston 	}
1012*c5591576SRob Johnston 
1013*c5591576SRob Johnston 	if (xmlStrcmp(type, (xmlChar *)TDG_XML_NVLIST) == 0) {
1014*c5591576SRob Johnston 		nvlist_t *cnvl = NULL;
1015*c5591576SRob Johnston 
1016*c5591576SRob Johnston 		if (topo_hdl_nvalloc(thp, &cnvl, NV_UNIQUE_NAME) != 0) {
1017*c5591576SRob Johnston 			goto fail;
1018*c5591576SRob Johnston 		}
1019*c5591576SRob Johnston 
1020*c5591576SRob Johnston 		for (xmlNodePtr cn = xn->xmlChildrenNode;
1021*c5591576SRob Johnston 		    cn != NULL; cn = cn->next) {
1022*c5591576SRob Johnston 
1023*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVLIST) != 0)
1024*c5591576SRob Johnston 				continue;
1025*c5591576SRob Johnston 
1026*c5591576SRob Johnston 			for (xmlNodePtr gcn = cn->xmlChildrenNode;
1027*c5591576SRob Johnston 			    gcn != NULL; gcn = gcn->next) {
1028*c5591576SRob Johnston 
1029*c5591576SRob Johnston 				if (xmlStrcmp(gcn->name,
1030*c5591576SRob Johnston 				    (xmlChar *)TDG_XML_NVPAIR) != 0)
1031*c5591576SRob Johnston 					continue;
1032*c5591576SRob Johnston 				if (deserialize_nvpair(thp, mod, cnvl, gcn) !=
1033*c5591576SRob Johnston 				    0) {
1034*c5591576SRob Johnston 					nvlist_free(cnvl);
1035*c5591576SRob Johnston 					goto fail;
1036*c5591576SRob Johnston 				}
1037*c5591576SRob Johnston 			}
1038*c5591576SRob Johnston 			if (nvlist_add_nvlist(nvl, (char *)name, cnvl) != 0) {
1039*c5591576SRob Johnston 				nvlist_free(cnvl);
1040*c5591576SRob Johnston 				goto fail;
1041*c5591576SRob Johnston 			}
1042*c5591576SRob Johnston 			nvlist_free(cnvl);
1043*c5591576SRob Johnston 			break;
1044*c5591576SRob Johnston 		}
1045*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_INT8) == 0) {
1046*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1047*c5591576SRob Johnston 		    is_overflow(thp, val, 8) ||
1048*c5591576SRob Johnston 		    nvlist_add_int8(nvl, (char *)name, (int8_t)val) != 0) {
1049*c5591576SRob Johnston 			goto fail;
1050*c5591576SRob Johnston 		}
1051*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_INT16) == 0) {
1052*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1053*c5591576SRob Johnston 		    is_overflow(thp, val, 16) ||
1054*c5591576SRob Johnston 		    nvlist_add_int16(nvl, (char *)name, (int16_t)val) != 0) {
1055*c5591576SRob Johnston 			goto fail;
1056*c5591576SRob Johnston 		}
1057*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_INT32) == 0) {
1058*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1059*c5591576SRob Johnston 		    is_overflow(thp, val, 32) ||
1060*c5591576SRob Johnston 		    nvlist_add_int32(nvl, (char *)name, (int32_t)val) != 0) {
1061*c5591576SRob Johnston 			goto fail;
1062*c5591576SRob Johnston 		}
1063*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_INT64) == 0) {
1064*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1065*c5591576SRob Johnston 		    nvlist_add_int64(nvl, (char *)name, (int64_t)val) != 0) {
1066*c5591576SRob Johnston 			goto fail;
1067*c5591576SRob Johnston 		}
1068*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_UINT8) == 0) {
1069*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1070*c5591576SRob Johnston 		    is_overflow(thp, val, 8) ||
1071*c5591576SRob Johnston 		    nvlist_add_uint8(nvl, (char *)name, (uint8_t)val) != 0) {
1072*c5591576SRob Johnston 			goto fail;
1073*c5591576SRob Johnston 		}
1074*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_UINT16) == 0) {
1075*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1076*c5591576SRob Johnston 		    is_overflow(thp, val, 16) ||
1077*c5591576SRob Johnston 		    nvlist_add_uint16(nvl, (char *)name, (uint16_t)val) != 0) {
1078*c5591576SRob Johnston 			goto fail;
1079*c5591576SRob Johnston 		}
1080*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_UINT32) == 0) {
1081*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1082*c5591576SRob Johnston 		    is_overflow(thp, val, 32) ||
1083*c5591576SRob Johnston 		    nvlist_add_uint32(nvl, (char *)name, (uint32_t)val) != 0) {
1084*c5591576SRob Johnston 			goto fail;
1085*c5591576SRob Johnston 		}
1086*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_UINT64) == 0) {
1087*c5591576SRob Johnston 		if (xmlattr_to_int(mod, xn, TDG_XML_VALUE, &val) != 0 ||
1088*c5591576SRob Johnston 		    nvlist_add_uint64(nvl, (char *)name, (uint64_t)val) != 0) {
1089*c5591576SRob Johnston 			goto fail;
1090*c5591576SRob Johnston 		}
1091*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_STRING) == 0) {
1092*c5591576SRob Johnston 		if ((sval = xmlGetProp(xn, (xmlChar *)TDG_XML_VALUE)) == NULL ||
1093*c5591576SRob Johnston 		    nvlist_add_string(nvl, (char *)name, (char *)sval) != 0) {
1094*c5591576SRob Johnston 			goto fail;
1095*c5591576SRob Johnston 		}
1096*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_NVLIST_ARR) == 0) {
1097*c5591576SRob Johnston 		uint64_t nelem = 0;
1098*c5591576SRob Johnston 		nvlist_t **nvlarr = NULL;
1099*c5591576SRob Johnston 		uint_t i = 0;
1100*c5591576SRob Johnston 		xmlNodePtr cn = xn->xmlChildrenNode;
1101*c5591576SRob Johnston 
1102*c5591576SRob Johnston 		/*
1103*c5591576SRob Johnston 		 * Count the number of child nvlist elements
1104*c5591576SRob Johnston 		 */
1105*c5591576SRob Johnston 		while (cn != NULL) {
1106*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVLIST) ==
1107*c5591576SRob Johnston 			    0) {
1108*c5591576SRob Johnston 				nelem++;
1109*c5591576SRob Johnston 			}
1110*c5591576SRob Johnston 			cn = cn->next;
1111*c5591576SRob Johnston 		}
1112*c5591576SRob Johnston 
1113*c5591576SRob Johnston 		if ((nvlarr = topo_hdl_zalloc(thp,
1114*c5591576SRob Johnston 		    (nelem * sizeof (nvlist_t *)))) == NULL) {
1115*c5591576SRob Johnston 			goto fail;
1116*c5591576SRob Johnston 		}
1117*c5591576SRob Johnston 
1118*c5591576SRob Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1119*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVLIST) !=
1120*c5591576SRob Johnston 			    0)
1121*c5591576SRob Johnston 				continue;
1122*c5591576SRob Johnston 
1123*c5591576SRob Johnston 			if (topo_hdl_nvalloc(thp, &nvlarr[i],
1124*c5591576SRob Johnston 			    NV_UNIQUE_NAME) != 0) {
1125*c5591576SRob Johnston 				free_nvlist_array(thp, nvlarr, nelem);
1126*c5591576SRob Johnston 				goto fail;
1127*c5591576SRob Johnston 			}
1128*c5591576SRob Johnston 
1129*c5591576SRob Johnston 			for (xmlNodePtr gcn = cn->xmlChildrenNode;
1130*c5591576SRob Johnston 			    gcn != NULL; gcn = gcn->next) {
1131*c5591576SRob Johnston 				if (xmlStrcmp(gcn->name,
1132*c5591576SRob Johnston 				    (xmlChar *)TDG_XML_NVPAIR) != 0)
1133*c5591576SRob Johnston 					continue;
1134*c5591576SRob Johnston 				if (deserialize_nvpair(thp, mod, nvlarr[i],
1135*c5591576SRob Johnston 				    gcn) != 0) {
1136*c5591576SRob Johnston 					free_nvlist_array(thp, nvlarr, nelem);
1137*c5591576SRob Johnston 					goto fail;
1138*c5591576SRob Johnston 				}
1139*c5591576SRob Johnston 			}
1140*c5591576SRob Johnston 			i++;
1141*c5591576SRob Johnston 		}
1142*c5591576SRob Johnston 		if (nvlist_add_nvlist_array(nvl, (char *)name, nvlarr,
1143*c5591576SRob Johnston 		    nelem) != 0) {
1144*c5591576SRob Johnston 			free_nvlist_array(thp, nvlarr, nelem);
1145*c5591576SRob Johnston 			goto fail;
1146*c5591576SRob Johnston 		}
1147*c5591576SRob Johnston 		free_nvlist_array(thp, nvlarr, nelem);
1148*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_UINT32_ARR) == 0) {
1149*c5591576SRob Johnston 		uint64_t nelem = 0;
1150*c5591576SRob Johnston 		uint32_t *arr = NULL;
1151*c5591576SRob Johnston 		uint_t i = 0;
1152*c5591576SRob Johnston 		xmlNodePtr cn = xn->xmlChildrenNode;
1153*c5591576SRob Johnston 
1154*c5591576SRob Johnston 		/*
1155*c5591576SRob Johnston 		 * Count the number of child nvpair elements
1156*c5591576SRob Johnston 		 */
1157*c5591576SRob Johnston 		while (cn != NULL) {
1158*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) ==
1159*c5591576SRob Johnston 			    0) {
1160*c5591576SRob Johnston 				nelem++;
1161*c5591576SRob Johnston 			}
1162*c5591576SRob Johnston 			cn = cn->next;
1163*c5591576SRob Johnston 		}
1164*c5591576SRob Johnston 
1165*c5591576SRob Johnston 		if ((arr = topo_hdl_zalloc(thp,
1166*c5591576SRob Johnston 		    (nelem * sizeof (uint32_t)))) == NULL) {
1167*c5591576SRob Johnston 			goto fail;
1168*c5591576SRob Johnston 		}
1169*c5591576SRob Johnston 
1170*c5591576SRob Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1171*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) != 0)
1172*c5591576SRob Johnston 				continue;
1173*c5591576SRob Johnston 
1174*c5591576SRob Johnston 			if (xmlattr_to_int(mod, cn, TDG_XML_VALUE, &val) != 0) {
1175*c5591576SRob Johnston 				topo_hdl_free(thp, arr,
1176*c5591576SRob Johnston 				    (nelem * sizeof (uint32_t)));
1177*c5591576SRob Johnston 				goto fail;
1178*c5591576SRob Johnston 			}
1179*c5591576SRob Johnston 
1180*c5591576SRob Johnston 			arr[i] = val;
1181*c5591576SRob Johnston 			i++;
1182*c5591576SRob Johnston 		}
1183*c5591576SRob Johnston 		if (nvlist_add_uint32_array(nvl, (char *)name, arr,
1184*c5591576SRob Johnston 		    nelem) != 0) {
1185*c5591576SRob Johnston 			topo_hdl_free(thp, arr, (nelem * sizeof (uint32_t)));
1186*c5591576SRob Johnston 			goto fail;
1187*c5591576SRob Johnston 		}
1188*c5591576SRob Johnston 		topo_hdl_free(thp, arr, (nelem * sizeof (uint32_t)));
1189*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_INT32_ARR) == 0) {
1190*c5591576SRob Johnston 		uint64_t nelem = 0;
1191*c5591576SRob Johnston 		int32_t *arr = NULL;
1192*c5591576SRob Johnston 		uint_t i = 0;
1193*c5591576SRob Johnston 		xmlNodePtr cn = xn->xmlChildrenNode;
1194*c5591576SRob Johnston 
1195*c5591576SRob Johnston 		/*
1196*c5591576SRob Johnston 		 * Count the number of child nvpair elements
1197*c5591576SRob Johnston 		 */
1198*c5591576SRob Johnston 		while (cn != NULL) {
1199*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) ==
1200*c5591576SRob Johnston 			    0) {
1201*c5591576SRob Johnston 				nelem++;
1202*c5591576SRob Johnston 			}
1203*c5591576SRob Johnston 			cn = cn->next;
1204*c5591576SRob Johnston 		}
1205*c5591576SRob Johnston 
1206*c5591576SRob Johnston 		if ((arr = topo_hdl_zalloc(thp,
1207*c5591576SRob Johnston 		    (nelem * sizeof (int32_t)))) == NULL) {
1208*c5591576SRob Johnston 			goto fail;
1209*c5591576SRob Johnston 		}
1210*c5591576SRob Johnston 
1211*c5591576SRob Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1212*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) != 0)
1213*c5591576SRob Johnston 				continue;
1214*c5591576SRob Johnston 
1215*c5591576SRob Johnston 			if (xmlattr_to_int(mod, cn, TDG_XML_VALUE, &val) != 0) {
1216*c5591576SRob Johnston 				topo_hdl_free(thp, arr,
1217*c5591576SRob Johnston 				    (nelem * sizeof (int32_t)));
1218*c5591576SRob Johnston 				goto fail;
1219*c5591576SRob Johnston 			}
1220*c5591576SRob Johnston 
1221*c5591576SRob Johnston 			arr[i] = val;
1222*c5591576SRob Johnston 			i++;
1223*c5591576SRob Johnston 		}
1224*c5591576SRob Johnston 		if (nvlist_add_int32_array(nvl, (char *)name, arr,
1225*c5591576SRob Johnston 		    nelem) != 0) {
1226*c5591576SRob Johnston 			topo_hdl_free(thp, arr, (nelem * sizeof (int32_t)));
1227*c5591576SRob Johnston 			goto fail;
1228*c5591576SRob Johnston 		}
1229*c5591576SRob Johnston 		topo_hdl_free(thp, arr, (nelem * sizeof (int32_t)));
1230*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_UINT64_ARR) == 0) {
1231*c5591576SRob Johnston 		uint64_t nelem = 0, *arr = NULL;
1232*c5591576SRob Johnston 		uint_t i = 0;
1233*c5591576SRob Johnston 		xmlNodePtr cn = xn->xmlChildrenNode;
1234*c5591576SRob Johnston 
1235*c5591576SRob Johnston 		/*
1236*c5591576SRob Johnston 		 * Count the number of child nvpair elements
1237*c5591576SRob Johnston 		 */
1238*c5591576SRob Johnston 		while (cn != NULL) {
1239*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) ==
1240*c5591576SRob Johnston 			    0) {
1241*c5591576SRob Johnston 				nelem++;
1242*c5591576SRob Johnston 			}
1243*c5591576SRob Johnston 			cn = cn->next;
1244*c5591576SRob Johnston 		}
1245*c5591576SRob Johnston 
1246*c5591576SRob Johnston 		if ((arr = topo_hdl_zalloc(thp,
1247*c5591576SRob Johnston 		    (nelem * sizeof (uint64_t)))) == NULL) {
1248*c5591576SRob Johnston 			goto fail;
1249*c5591576SRob Johnston 		}
1250*c5591576SRob Johnston 
1251*c5591576SRob Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1252*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) != 0)
1253*c5591576SRob Johnston 				continue;
1254*c5591576SRob Johnston 
1255*c5591576SRob Johnston 			if (xmlattr_to_int(mod, cn, TDG_XML_VALUE, &val) != 0) {
1256*c5591576SRob Johnston 				topo_hdl_free(thp, arr,
1257*c5591576SRob Johnston 				    (nelem * sizeof (uint64_t)));
1258*c5591576SRob Johnston 				goto fail;
1259*c5591576SRob Johnston 			}
1260*c5591576SRob Johnston 
1261*c5591576SRob Johnston 			arr[i] = val;
1262*c5591576SRob Johnston 			i++;
1263*c5591576SRob Johnston 		}
1264*c5591576SRob Johnston 		if (nvlist_add_uint64_array(nvl, (char *)name, arr,
1265*c5591576SRob Johnston 		    nelem) != 0) {
1266*c5591576SRob Johnston 			topo_hdl_free(thp, arr, (nelem * sizeof (uint64_t)));
1267*c5591576SRob Johnston 			goto fail;
1268*c5591576SRob Johnston 		}
1269*c5591576SRob Johnston 		topo_hdl_free(thp, arr, (nelem * sizeof (uint64_t)));
1270*c5591576SRob Johnston 	} else if (xmlStrcmp(type, (xmlChar *)TDG_XML_INT64_ARR) == 0) {
1271*c5591576SRob Johnston 		uint64_t nelem = 0;
1272*c5591576SRob Johnston 		int64_t *arr = NULL;
1273*c5591576SRob Johnston 		uint_t i = 0;
1274*c5591576SRob Johnston 		xmlNodePtr cn = xn->xmlChildrenNode;
1275*c5591576SRob Johnston 
1276*c5591576SRob Johnston 		/*
1277*c5591576SRob Johnston 		 * Count the number of child nvpair elements
1278*c5591576SRob Johnston 		 */
1279*c5591576SRob Johnston 		while (cn != NULL) {
1280*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) ==
1281*c5591576SRob Johnston 			    0) {
1282*c5591576SRob Johnston 				nelem++;
1283*c5591576SRob Johnston 			}
1284*c5591576SRob Johnston 			cn = cn->next;
1285*c5591576SRob Johnston 		}
1286*c5591576SRob Johnston 
1287*c5591576SRob Johnston 		if ((arr = topo_hdl_zalloc(thp,
1288*c5591576SRob Johnston 		    (nelem * sizeof (int64_t)))) == NULL) {
1289*c5591576SRob Johnston 			goto fail;
1290*c5591576SRob Johnston 		}
1291*c5591576SRob Johnston 
1292*c5591576SRob Johnston 		for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1293*c5591576SRob Johnston 			if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) != 0)
1294*c5591576SRob Johnston 				continue;
1295*c5591576SRob Johnston 
1296*c5591576SRob Johnston 			if (xmlattr_to_int(mod, cn, TDG_XML_VALUE, &val) != 0) {
1297*c5591576SRob Johnston 				topo_hdl_free(thp, arr,
1298*c5591576SRob Johnston 				    (nelem * sizeof (int64_t)));
1299*c5591576SRob Johnston 				goto fail;
1300*c5591576SRob Johnston 			}
1301*c5591576SRob Johnston 
1302*c5591576SRob Johnston 			arr[i] = val;
1303*c5591576SRob Johnston 			i++;
1304*c5591576SRob Johnston 		}
1305*c5591576SRob Johnston 		if (nvlist_add_int64_array(nvl, (char *)name, arr,
1306*c5591576SRob Johnston 		    nelem) != 0) {
1307*c5591576SRob Johnston 			topo_hdl_free(thp, arr, (nelem * sizeof (int64_t)));
1308*c5591576SRob Johnston 			goto fail;
1309*c5591576SRob Johnston 		}
1310*c5591576SRob Johnston 		topo_hdl_free(thp, arr, (nelem * sizeof (int64_t)));
1311*c5591576SRob Johnston 	}
1312*c5591576SRob Johnston 	ret = 0;
1313*c5591576SRob Johnston fail:
1314*c5591576SRob Johnston 	if (ret != 0) {
1315*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "%s: error parsing %s "
1316*c5591576SRob Johnston 		    "element: name: %s, type: %s, nvl: %p", __func__, xn->name,
1317*c5591576SRob Johnston 		    (name != NULL) ? (char *)name : "MISSING!",
1318*c5591576SRob Johnston 		    (type != NULL) ? (char *)type : "MISSING!", nvl);
1319*c5591576SRob Johnston 		dump_xml_node(thp, xn);
1320*c5591576SRob Johnston 	}
1321*c5591576SRob Johnston 	if (name != NULL)
1322*c5591576SRob Johnston 		xmlFree(name);
1323*c5591576SRob Johnston 	if (type != NULL)
1324*c5591576SRob Johnston 		xmlFree(type);
1325*c5591576SRob Johnston 	if (sval != NULL)
1326*c5591576SRob Johnston 		xmlFree(sval);
1327*c5591576SRob Johnston 
1328*c5591576SRob Johnston 	return (ret);
1329*c5591576SRob Johnston }
1330*c5591576SRob Johnston 
1331*c5591576SRob Johnston static int
deserialize_vertex(topo_hdl_t * thp,topo_mod_t * mod,topo_digraph_t * tdg,xmlNodePtr xn)1332*c5591576SRob Johnston deserialize_vertex(topo_hdl_t *thp, topo_mod_t *mod, topo_digraph_t *tdg,
1333*c5591576SRob Johnston     xmlNodePtr xn)
1334*c5591576SRob Johnston {
1335*c5591576SRob Johnston 	int ret = -1;
1336*c5591576SRob Johnston 	topo_vertex_t *vtx = NULL;
1337*c5591576SRob Johnston 	nvlist_t *props = NULL;
1338*c5591576SRob Johnston 	xmlChar *name = NULL, *fmri = NULL;
1339*c5591576SRob Johnston 	uint64_t inst;
1340*c5591576SRob Johnston 
1341*c5591576SRob Johnston 	if ((name = xmlGetProp(xn, (xmlChar *)TDG_XML_NAME)) == NULL ||
1342*c5591576SRob Johnston 	    (fmri = xmlGetProp(xn, (xmlChar *)TDG_XML_FMRI)) == NULL ||
1343*c5591576SRob Johnston 	    xmlattr_to_int(mod, xn, TDG_XML_INSTANCE, &inst) != 0) {
1344*c5591576SRob Johnston 		goto fail;
1345*c5591576SRob Johnston 	}
1346*c5591576SRob Johnston 
1347*c5591576SRob Johnston 	if ((vtx = topo_vertex_new(mod, (char *)name, inst)) == NULL) {
1348*c5591576SRob Johnston 		goto fail;
1349*c5591576SRob Johnston 	}
1350*c5591576SRob Johnston 
1351*c5591576SRob Johnston 	for (xmlNodePtr cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1352*c5591576SRob Johnston 		if (xmlStrcmp(cn->name, (xmlChar *)TDG_XML_NVPAIR) == 0) {
1353*c5591576SRob Johnston 			if (topo_hdl_nvalloc(thp, &props, NV_UNIQUE_NAME) != 0)
1354*c5591576SRob Johnston 				goto fail;
1355*c5591576SRob Johnston 			if (deserialize_nvpair(thp, mod, props, cn) != 0 ||
1356*c5591576SRob Johnston 			    add_props(thp, vtx, props) != 0)
1357*c5591576SRob Johnston 				goto fail;
1358*c5591576SRob Johnston 		}
1359*c5591576SRob Johnston 	}
1360*c5591576SRob Johnston 	ret = 0;
1361*c5591576SRob Johnston 
1362*c5591576SRob Johnston fail:
1363*c5591576SRob Johnston 	if (ret != 0) {
1364*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "%s: error parsing %s element",
1365*c5591576SRob Johnston 		    __func__, TDG_XML_VERTEX);
1366*c5591576SRob Johnston 		dump_xml_node(thp, xn);
1367*c5591576SRob Johnston 	}
1368*c5591576SRob Johnston 	nvlist_free(props);
1369*c5591576SRob Johnston 	if (name != NULL)
1370*c5591576SRob Johnston 		xmlFree(name);
1371*c5591576SRob Johnston 	if (fmri != NULL)
1372*c5591576SRob Johnston 		xmlFree(fmri);
1373*c5591576SRob Johnston 
1374*c5591576SRob Johnston 	return (ret);
1375*c5591576SRob Johnston }
1376*c5591576SRob Johnston 
1377*c5591576SRob Johnston /*
1378*c5591576SRob Johnston  * This function takes a buffer containing XML data describing a directed graph
1379*c5591576SRob Johnston  * topology.  This data is parsed to the original directed graph is rehydrated.
1380*c5591576SRob Johnston  *
1381*c5591576SRob Johnston  * On success, a pointer to a topo_digraph_t representing the graph is
1382*c5591576SRob Johnston  * returned.  The caller is responsible for destroying the graph via a call to
1383*c5591576SRob Johnston  * topo_digraph_destroy()
1384*c5591576SRob Johnston  *
1385*c5591576SRob Johnston  * On failure, NULL is returned.
1386*c5591576SRob Johnston  */
1387*c5591576SRob Johnston topo_digraph_t *
topo_digraph_deserialize(topo_hdl_t * thp,const char * xml,size_t sz)1388*c5591576SRob Johnston topo_digraph_deserialize(topo_hdl_t *thp, const char *xml, size_t sz)
1389*c5591576SRob Johnston {
1390*c5591576SRob Johnston 	xmlDocPtr doc;
1391*c5591576SRob Johnston 	xmlDtdPtr dtd = NULL;
1392*c5591576SRob Johnston 	xmlNodePtr root, vertices;
1393*c5591576SRob Johnston 	xmlChar *scheme = NULL;
1394*c5591576SRob Johnston 	topo_mod_t *mod;
1395*c5591576SRob Johnston 	topo_digraph_t *tdg, *ret = NULL;
1396*c5591576SRob Johnston 
1397*c5591576SRob Johnston 	if ((doc = xmlReadMemory(xml, sz, "", NULL, 0)) == NULL) {
1398*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "Failed to parse XML");
1399*c5591576SRob Johnston 		goto fail;
1400*c5591576SRob Johnston 	}
1401*c5591576SRob Johnston 
1402*c5591576SRob Johnston 	/*
1403*c5591576SRob Johnston 	 * As a sanity check, extract the DTD from the XML and verify it
1404*c5591576SRob Johnston 	 * matches the DTD for a digraph topology.
1405*c5591576SRob Johnston 	 */
1406*c5591576SRob Johnston 	if ((dtd = xmlGetIntSubset(doc)) == NULL) {
1407*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML,  "document has no DTD.\n");
1408*c5591576SRob Johnston 		goto fail;
1409*c5591576SRob Johnston 	}
1410*c5591576SRob Johnston 
1411*c5591576SRob Johnston 	if (strcmp((const char *)dtd->SystemID, TDG_DTD) != 0) {
1412*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "unexpected DTD: %s",
1413*c5591576SRob Johnston 		    dtd->SystemID);
1414*c5591576SRob Johnston 		goto fail;
1415*c5591576SRob Johnston 	}
1416*c5591576SRob Johnston 
1417*c5591576SRob Johnston 	/*
1418*c5591576SRob Johnston 	 * Verify the root element is what we're expecting and then grab the
1419*c5591576SRob Johnston 	 * FMRI scheme from its attributes.
1420*c5591576SRob Johnston 	 */
1421*c5591576SRob Johnston 	if ((root = xmlDocGetRootElement(doc)) == NULL) {
1422*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "document is empty.\n");
1423*c5591576SRob Johnston 		goto fail;
1424*c5591576SRob Johnston 	}
1425*c5591576SRob Johnston 
1426*c5591576SRob Johnston 	if (xmlStrcmp(root->name, (xmlChar *)TDG_XML_TOPO_DIGRAPH) != 0 ||
1427*c5591576SRob Johnston 	    (scheme = xmlGetProp(root, (xmlChar *)TDG_XML_SCHEME)) ==
1428*c5591576SRob Johnston 	    NULL) {
1429*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML,
1430*c5591576SRob Johnston 		    "failed to parse %s element", TDG_XML_TOPO_DIGRAPH);
1431*c5591576SRob Johnston 		goto fail;
1432*c5591576SRob Johnston 	}
1433*c5591576SRob Johnston 
1434*c5591576SRob Johnston 	/*
1435*c5591576SRob Johnston 	 * Load the topo module associated with this FMRI scheme.
1436*c5591576SRob Johnston 	 */
1437*c5591576SRob Johnston 	if ((mod = topo_mod_lookup(thp, (const char *)scheme, 1)) == NULL) {
1438*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "failed to load %s module",
1439*c5591576SRob Johnston 		    scheme);
1440*c5591576SRob Johnston 		goto fail;
1441*c5591576SRob Johnston 	}
1442*c5591576SRob Johnston 	/*
1443*c5591576SRob Johnston 	 * If we have a builtin module for this scheme, then there will
1444*c5591576SRob Johnston 	 * already be an empty digraph attached to the handle.  Otherwise,
1445*c5591576SRob Johnston 	 * create a new empty digraph and attach it to the handle.
1446*c5591576SRob Johnston 	 */
1447*c5591576SRob Johnston 	tdg = topo_digraph_get(mod->tm_hdl, mod->tm_info->tmi_scheme);
1448*c5591576SRob Johnston 	if (tdg == NULL) {
1449*c5591576SRob Johnston 		if ((tdg = topo_digraph_new(thp, mod, (const char *)scheme)) ==
1450*c5591576SRob Johnston 		    NULL) {
1451*c5591576SRob Johnston 			topo_dprintf(thp, TOPO_DBG_XML, "failed to create new "
1452*c5591576SRob Johnston 			    "digraph");
1453*c5591576SRob Johnston 			goto fail;
1454*c5591576SRob Johnston 		} else {
1455*c5591576SRob Johnston 			topo_list_append(&thp->th_digraphs, tdg);
1456*c5591576SRob Johnston 		}
1457*c5591576SRob Johnston 	}
1458*c5591576SRob Johnston 
1459*c5591576SRob Johnston 	/*
1460*c5591576SRob Johnston 	 * Iterate through the vertex XML elements to reconstruct the graph
1461*c5591576SRob Johnston 	 */
1462*c5591576SRob Johnston 	vertices = get_child_by_name(root, (xmlChar *)TDG_XML_VERTICES);
1463*c5591576SRob Johnston 	if (vertices == NULL ||
1464*c5591576SRob Johnston 	    xmlStrcmp(vertices->name, (xmlChar *)TDG_XML_VERTICES) != 0) {
1465*c5591576SRob Johnston 		topo_dprintf(thp, TOPO_DBG_XML, "failed to parse %s element",
1466*c5591576SRob Johnston 		    TDG_XML_VERTICES);
1467*c5591576SRob Johnston 		dump_xml_node(thp, root);
1468*c5591576SRob Johnston 		goto fail;
1469*c5591576SRob Johnston 	}
1470*c5591576SRob Johnston 
1471*c5591576SRob Johnston 	for (xmlNodePtr xn = vertices->xmlChildrenNode; xn != NULL;
1472*c5591576SRob Johnston 	    xn = xn->next) {
1473*c5591576SRob Johnston 		if (xmlStrcmp(xn->name, (xmlChar *)TDG_XML_VERTEX) != 0)
1474*c5591576SRob Johnston 			continue;
1475*c5591576SRob Johnston 		if (deserialize_vertex(thp, mod, tdg, xn) != 0)
1476*c5591576SRob Johnston 			goto fail;
1477*c5591576SRob Johnston 	}
1478*c5591576SRob Johnston 
1479*c5591576SRob Johnston 	/*
1480*c5591576SRob Johnston 	 * Now that all of the vertices have been created, go back through
1481*c5591576SRob Johnston 	 * the vertex XML elements and add the edges.
1482*c5591576SRob Johnston 	 */
1483*c5591576SRob Johnston 	for (xmlNodePtr xn = vertices->xmlChildrenNode; xn != NULL;
1484*c5591576SRob Johnston 	    xn = xn->next) {
1485*c5591576SRob Johnston 		if (xmlStrcmp(xn->name, (xmlChar *)TDG_XML_VERTEX) != 0)
1486*c5591576SRob Johnston 			continue;
1487*c5591576SRob Johnston 		if (add_edges(thp, mod, tdg, xn) != 0)
1488*c5591576SRob Johnston 			goto fail;
1489*c5591576SRob Johnston 	}
1490*c5591576SRob Johnston 
1491*c5591576SRob Johnston 	ret = tdg;
1492*c5591576SRob Johnston 
1493*c5591576SRob Johnston fail:
1494*c5591576SRob Johnston 	if (scheme != NULL)
1495*c5591576SRob Johnston 		xmlFree(scheme);
1496*c5591576SRob Johnston 
1497*c5591576SRob Johnston 	if (doc != NULL)
1498*c5591576SRob Johnston 		xmlFreeDoc(doc);
1499*c5591576SRob Johnston 
1500*c5591576SRob Johnston 	(void) topo_hdl_seterrno(thp, ETOPO_MOD_XENUM);
1501*c5591576SRob Johnston 	return (ret);
1502*c5591576SRob Johnston }
1503