xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c (revision d6770490b09260e2b0c0941b28951b2ec473a946)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <strings.h>
31 #include <time.h>
32 #include <sys/types.h>
33 #include <sys/fm/protocol.h>
34 #include <sys/utsname.h>
35 
36 #include <topo_parse.h>
37 #include <topo_prop.h>
38 #include <topo_tree.h>
39 
40 #define	INT32BUFSZ	sizeof (UINT32_MAX) + 1
41 /* 2 bytes for "0x" + 16 bytes for the hex value + 1 for sign + null */
42 #define	INT64BUFSZ	20
43 #define	XML_VERSION	"1.0"
44 
45 static int txml_print_range(topo_hdl_t *, FILE *, tnode_t *, int);
46 
47 void
48 print_header(FILE *fp)
49 {
50 	char buf[32];
51 	time_t tod = time(NULL);
52 	struct utsname uts;
53 
54 	(void) fprintf(fp, "<?xml version=\"%s\"?>\n", XML_VERSION);
55 	(void) fprintf(fp, "<!DOCTYPE topology SYSTEM \"%s\">\n",
56 	    TOPO_DTD_PATH);
57 
58 	(void) uname(&uts);
59 	(void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
60 	(void) fprintf(fp, "<!--\n");
61 	(void) fprintf(fp, " This topology map file was generated on "
62 	    "%-15s for %s\n", buf, uts.nodename);
63 	(void) fprintf(fp, "<-->\n\n");
64 }
65 
66 void
67 begin_element(FILE *fp, const char *ename, ...)
68 {
69 	char *name, *value;
70 	va_list ap;
71 
72 	(void) fprintf(fp, "<%s ", ename);
73 	va_start(ap, ename);
74 	name = va_arg(ap, char *);
75 	while (name != NULL) {
76 		value = va_arg(ap, char *);
77 		(void) fprintf(fp, "%s='%s' ", name, value);
78 		name = va_arg(ap, char *);
79 	}
80 	(void) fprintf(fp, ">\n");
81 }
82 
83 void
84 begin_end_element(FILE *fp, const char *ename, ...)
85 {
86 	char *name, *value;
87 	va_list ap;
88 
89 	(void) fprintf(fp, "<%s ", ename);
90 	va_start(ap, ename);
91 	name = va_arg(ap, char *);
92 	while (name != NULL) {
93 		value = va_arg(ap, char *);
94 		(void) fprintf(fp, "%s='%s' ", name, value);
95 		name = va_arg(ap, char *);
96 	}
97 	(void) fprintf(fp, "/>\n");
98 }
99 
100 void
101 end_element(FILE *fp, const char *ename)
102 {
103 	(void) fprintf(fp, "</%s>\n", ename);
104 }
105 
106 static void
107 txml_print_prop(topo_hdl_t *thp, FILE *fp, tnode_t *node, const char *pgname,
108     topo_propval_t *pv)
109 {
110 	int err;
111 	char *fmri = NULL;
112 	char vbuf[INT64BUFSZ], tbuf[32], *pval = NULL, *aval = NULL;
113 
114 	switch (pv->tp_type) {
115 		case TOPO_TYPE_INT32: {
116 			int32_t val;
117 			if (topo_prop_get_int32(node, pgname, pv->tp_name, &val,
118 			    &err) == 0) {
119 				(void) snprintf(vbuf, INT64BUFSZ, "%d", val);
120 				(void) snprintf(tbuf, 10, "%s", Int32);
121 				pval = vbuf;
122 			} else
123 				return;
124 			break;
125 		}
126 		case TOPO_TYPE_UINT32: {
127 			uint32_t val;
128 			if (topo_prop_get_uint32(node, pgname, pv->tp_name,
129 			    &val, &err) == 0) {
130 				(void) snprintf(vbuf, INT64BUFSZ, "0x%x", val);
131 				(void) snprintf(tbuf, 10, "%s", UInt32);
132 				pval = vbuf;
133 			} else
134 				return;
135 			break;
136 		}
137 		case TOPO_TYPE_INT64: {
138 			int64_t val;
139 			if (topo_prop_get_int64(node, pgname, pv->tp_name, &val,
140 			    &err) == 0) {
141 				(void) snprintf(vbuf, INT64BUFSZ, "0x%llx",
142 				    (longlong_t)val);
143 				(void) snprintf(tbuf, 10, "%s", Int64);
144 				pval = vbuf;
145 			} else
146 				return;
147 			break;
148 		}
149 		case TOPO_TYPE_UINT64: {
150 			uint64_t val;
151 			if (topo_prop_get_uint64(node, pgname, pv->tp_name,
152 			    &val, &err) == 0) {
153 				(void) snprintf(vbuf, INT64BUFSZ, "0x%llx",
154 				    (u_longlong_t)val);
155 				(void) snprintf(tbuf, 10, "%s", UInt64);
156 				pval = vbuf;
157 			} else
158 				return;
159 			break;
160 		}
161 		case TOPO_TYPE_STRING: {
162 			if (topo_prop_get_string(node, pgname, pv->tp_name,
163 			    &pval, &err) != 0)
164 				return;
165 			(void) snprintf(tbuf, 10, "%s", "string");
166 			break;
167 		}
168 		case TOPO_TYPE_FMRI: {
169 			nvlist_t *val;
170 
171 			if (topo_prop_get_fmri(node, pgname, pv->tp_name, &val,
172 			    &err) == 0) {
173 				if (topo_fmri_nvl2str(thp, val, &fmri, &err)
174 				    == 0) {
175 					nvlist_free(val);
176 					pval = fmri;
177 				} else {
178 					nvlist_free(val);
179 					return;
180 				}
181 			} else
182 				return;
183 			(void) snprintf(tbuf, 10, "%s", FMRI);
184 			break;
185 		}
186 		case TOPO_TYPE_UINT32_ARRAY: {
187 			uint32_t *val;
188 			uint_t nelem, i;
189 			if (topo_prop_get_uint32_array(node, pgname,
190 			    pv->tp_name, &val, &nelem, &err) != 0)
191 				return;
192 
193 			if (nelem > 0) {
194 				aval = calloc((nelem*9-1), sizeof (uchar_t));
195 
196 				(void) sprintf(aval, "0x%x", val[0]);
197 				for (i = 1; i < nelem; i++) {
198 					(void) sprintf(vbuf, " 0x%x", val[i]);
199 					(void) strcat(aval, vbuf);
200 				}
201 				topo_hdl_free(thp, val,
202 				    nelem * sizeof (uint32_t));
203 				(void) snprintf(tbuf, 10, "%s", UInt32_Arr);
204 				pval = aval;
205 			}
206 			break;
207 		}
208 		default:
209 			return;
210 	}
211 
212 	begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf,
213 	    Value, pval, NULL);
214 
215 	if (pval != NULL && pv->tp_type == TOPO_TYPE_STRING)
216 		topo_hdl_strfree(thp, pval);
217 
218 	if (fmri != NULL)
219 		topo_hdl_strfree(thp, fmri);
220 
221 	if (aval != NULL)
222 		free(aval);
223 }
224 
225 static void
226 txml_print_pgroup(topo_hdl_t *thp, FILE *fp, tnode_t *node, topo_pgroup_t *pg)
227 {
228 	topo_ipgroup_info_t *pip = pg->tpg_info;
229 	topo_proplist_t *plp;
230 	const char *namestab, *datastab;
231 	char version[INT32BUFSZ];
232 
233 	namestab = topo_stability2name(pip->tpi_namestab);
234 	datastab = topo_stability2name(pip->tpi_datastab);
235 	(void) snprintf(version, INT32BUFSZ, "%d", pip->tpi_version);
236 	begin_element(fp, Propgrp, Name, pip->tpi_name, Namestab,
237 	    namestab, Datastab, datastab, Version, version, NULL);
238 	for (plp = topo_list_next(&pg->tpg_pvals); plp != NULL;
239 	    plp = topo_list_next(plp)) {
240 		txml_print_prop(thp, fp, node, pip->tpi_name, plp->tp_pval);
241 	}
242 	end_element(fp, Propgrp);
243 }
244 
245 static void
246 txml_print_dependents(topo_hdl_t *thp, FILE *fp, tnode_t *node)
247 {
248 	if (topo_list_next(&node->tn_children) == NULL)
249 		return;
250 
251 	if (txml_print_range(thp, fp, node, 1) == 1)
252 		end_element(fp, Dependents);
253 }
254 
255 static void
256 txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node)
257 {
258 	char inst[INT32BUFSZ];
259 	topo_pgroup_t *pg;
260 
261 	(void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance);
262 	begin_element(fp, Node, Instance, inst, Static, True, NULL);
263 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
264 	    pg = topo_list_next(pg)) {
265 		txml_print_pgroup(thp, fp, node, pg);
266 	}
267 	txml_print_dependents(thp, fp, node);
268 	end_element(fp, Node);
269 
270 }
271 
272 static int
273 txml_print_range(topo_hdl_t *thp, FILE *fp, tnode_t *node, int dependent)
274 {
275 	int i, create = 0, ret = 0;
276 	topo_nodehash_t *nhp;
277 	char min[INT32BUFSZ], max[INT32BUFSZ];
278 
279 	for (nhp = topo_list_next(&node->tn_children); nhp != NULL;
280 	    nhp = topo_list_next(nhp)) {
281 		(void) snprintf(min, INT32BUFSZ, "%d", nhp->th_range.tr_min);
282 		(void) snprintf(max, INT32BUFSZ, "%d", nhp->th_range.tr_max);
283 
284 		/*
285 		 * Some enumerators create empty ranges: make sure there
286 		 * are real nodes before creating this range
287 		 */
288 		for (i = 0; i < nhp->th_arrlen; ++i) {
289 			if (nhp->th_nodearr[i] != NULL)
290 				++create;
291 		}
292 		if (!create)
293 			continue;
294 
295 		if (dependent) {
296 			begin_element(fp, Dependents, Grouping, Children, NULL);
297 			dependent = 0;
298 			ret = 1;
299 		}
300 		begin_element(fp, Range, Name, nhp->th_name, Min, min, Max,
301 		    max, NULL);
302 		for (i = 0; i < nhp->th_arrlen; ++i) {
303 			if (nhp->th_nodearr[i] != NULL)
304 				txml_print_node(thp, fp, nhp->th_nodearr[i]);
305 		}
306 		end_element(fp, Range);
307 	}
308 
309 	return (ret);
310 }
311 
312 static void
313 txml_print_topology(topo_hdl_t *thp, FILE *fp, char *scheme, tnode_t *node)
314 {
315 	char *name;
316 
317 	if (thp->th_product != NULL)
318 		name = thp->th_product;
319 	else
320 		name = thp->th_platform;
321 
322 	begin_element(fp, Topology, Name, name, Scheme, scheme,
323 	    NULL);
324 	(void) txml_print_range(thp, fp, node, 0);
325 	end_element(fp, Topology);
326 
327 }
328 
329 int
330 topo_xml_print(topo_hdl_t *thp,  FILE *fp, const char *scheme, int *err)
331 {
332 	ttree_t *tp;
333 
334 	print_header(fp);
335 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
336 	    tp = topo_list_next(tp)) {
337 		if (strcmp(scheme, tp->tt_scheme) == 0) {
338 			txml_print_topology(thp, fp, tp->tt_scheme,
339 			    tp->tt_root);
340 			return (0);
341 		}
342 	}
343 
344 	*err = EINVAL;
345 	return (-1);
346 }
347