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