xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c (revision 825ba0f20a74fd9c5d0d1ce2c195da2cc88a7f77)
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;
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 					pval = fmri;
176 				else
177 					return;
178 			} else
179 				return;
180 			(void) snprintf(tbuf, 10, "%s", FMRI);
181 			break;
182 		}
183 		case TOPO_TYPE_UINT32_ARRAY: {
184 			uint32_t *val;
185 			uint_t nelem, i;
186 			if (topo_prop_get_uint32_array(node, pgname,
187 			    pv->tp_name, &val, &nelem, &err) != 0)
188 				return;
189 
190 			if (nelem > 0) {
191 				aval = calloc((nelem*9-1), sizeof (uchar_t));
192 
193 				(void) sprintf(aval, "0x%x", val[0]);
194 				for (i = 1; i < nelem; i++) {
195 					(void) sprintf(vbuf, " 0x%x", val[i]);
196 					(void) strcat(aval, vbuf);
197 				}
198 				(void) snprintf(tbuf, 10, "%s", UInt32_Arr);
199 				pval = aval;
200 			}
201 			break;
202 		}
203 	}
204 
205 	begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf,
206 	    Value, pval, NULL);
207 
208 	if (fmri != NULL)
209 		topo_hdl_strfree(thp, fmri);
210 }
211 
212 static void
213 txml_print_pgroup(topo_hdl_t *thp, FILE *fp, tnode_t *node, topo_pgroup_t *pg)
214 {
215 	topo_ipgroup_info_t *pip = pg->tpg_info;
216 	topo_proplist_t *plp;
217 	const char *namestab, *datastab;
218 	char version[INT32BUFSZ];
219 
220 	namestab = topo_stability2name(pip->tpi_namestab);
221 	datastab = topo_stability2name(pip->tpi_datastab);
222 	(void) snprintf(version, INT32BUFSZ, "%d", pip->tpi_version);
223 	begin_element(fp, Propgrp, Name, pip->tpi_name, Namestab,
224 	    namestab, Datastab, datastab, Version, version, NULL);
225 	for (plp = topo_list_next(&pg->tpg_pvals); plp != NULL;
226 	    plp = topo_list_next(plp)) {
227 		txml_print_prop(thp, fp, node, pip->tpi_name, plp->tp_pval);
228 	}
229 	end_element(fp, Propgrp);
230 }
231 
232 static void
233 txml_print_dependents(topo_hdl_t *thp, FILE *fp, tnode_t *node)
234 {
235 	if (topo_list_next(&node->tn_children) == NULL)
236 		return;
237 
238 	if (txml_print_range(thp, fp, node, 1) == 1)
239 		end_element(fp, Dependents);
240 }
241 
242 static void
243 txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node)
244 {
245 	char inst[INT32BUFSZ];
246 	topo_pgroup_t *pg;
247 
248 	(void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance);
249 	begin_element(fp, Node, Instance, inst, Static, True, NULL);
250 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
251 	    pg = topo_list_next(pg)) {
252 		txml_print_pgroup(thp, fp, node, pg);
253 	}
254 	txml_print_dependents(thp, fp, node);
255 	end_element(fp, Node);
256 
257 }
258 
259 static int
260 txml_print_range(topo_hdl_t *thp, FILE *fp, tnode_t *node, int dependent)
261 {
262 	int i, create = 0, ret = 0;
263 	topo_nodehash_t *nhp;
264 	char min[INT32BUFSZ], max[INT32BUFSZ];
265 
266 	for (nhp = topo_list_next(&node->tn_children); nhp != NULL;
267 	    nhp = topo_list_next(nhp)) {
268 		(void) snprintf(min, INT32BUFSZ, "%d", nhp->th_range.tr_min);
269 		(void) snprintf(max, INT32BUFSZ, "%d", nhp->th_range.tr_max);
270 
271 		/*
272 		 * Some enumerators create empty ranges: make sure there
273 		 * are real nodes before creating this range
274 		 */
275 		for (i = 0; i < nhp->th_arrlen; ++i) {
276 			if (nhp->th_nodearr[i] != NULL)
277 				++create;
278 		}
279 		if (!create)
280 			continue;
281 
282 		if (dependent) {
283 			begin_element(fp, Dependents, Grouping, Children, NULL);
284 			dependent = 0;
285 			ret = 1;
286 		}
287 		begin_element(fp, Range, Name, nhp->th_name, Min, min, Max,
288 		    max, NULL);
289 		for (i = 0; i < nhp->th_arrlen; ++i) {
290 			if (nhp->th_nodearr[i] != NULL)
291 				txml_print_node(thp, fp, nhp->th_nodearr[i]);
292 		}
293 		end_element(fp, Range);
294 	}
295 
296 	return (ret);
297 }
298 
299 static void
300 txml_print_topology(topo_hdl_t *thp, FILE *fp, char *scheme, tnode_t *node)
301 {
302 	char *name;
303 
304 	if (thp->th_product != NULL)
305 		name = thp->th_product;
306 	else
307 		name = thp->th_platform;
308 
309 	begin_element(fp, Topology, Name, name, Scheme, scheme,
310 	    NULL);
311 	(void) txml_print_range(thp, fp, node, 0);
312 	end_element(fp, Topology);
313 
314 }
315 
316 int
317 topo_xml_print(topo_hdl_t *thp,  FILE *fp, const char *scheme, int *err)
318 {
319 	ttree_t *tp;
320 
321 	print_header(fp);
322 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
323 	    tp = topo_list_next(tp)) {
324 		if (strcmp(scheme, tp->tt_scheme) == 0) {
325 			txml_print_topology(thp, fp, tp->tt_scheme,
326 			    tp->tt_root);
327 			return (0);
328 		}
329 	}
330 
331 	*err = EINVAL;
332 	return (-1);
333 }
334