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