xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_2xml.c (revision 150d2c5288c645a1c1a7d2bee61199a3729406c7)
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 2006 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 #define	INT64BUFSZ	sizeof (UINT64_MAX) + 1
42 #define	XML_VERSION	"1.0"
43 
44 static int txml_print_range(topo_hdl_t *, FILE *, tnode_t *, int);
45 
46 void
47 print_header(FILE *fp)
48 {
49 	char buf[32];
50 	time_t tod = time(NULL);
51 	struct utsname uts;
52 
53 	(void) fprintf(fp, "<?xml version=\"%s\"?>\n", XML_VERSION);
54 	(void) fprintf(fp, "<!DOCTYPE topology SYSTEM \"%s\">\n",
55 	    TOPO_DTD_PATH);
56 
57 	(void) uname(&uts);
58 	(void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
59 	(void) fprintf(fp, "<!--\n");
60 	(void) fprintf(fp, " This topology map file was generated on "
61 	    "%-15s for %s\n", buf, uts.nodename);
62 	(void) fprintf(fp, "<-->\n\n");
63 }
64 
65 void
66 begin_element(FILE *fp, const char *ename, ...)
67 {
68 	char *name, *value;
69 	va_list ap;
70 
71 	(void) fprintf(fp, "<%s ", ename);
72 	va_start(ap, ename);
73 	name = va_arg(ap, char *);
74 	while (name != NULL) {
75 		value = va_arg(ap, char *);
76 		(void) fprintf(fp, "%s='%s' ", name, value);
77 		name = va_arg(ap, char *);
78 	}
79 	(void) fprintf(fp, ">\n");
80 }
81 
82 void
83 begin_end_element(FILE *fp, const char *ename, ...)
84 {
85 	char *name, *value;
86 	va_list ap;
87 
88 	(void) fprintf(fp, "<%s ", ename);
89 	va_start(ap, ename);
90 	name = va_arg(ap, char *);
91 	while (name != NULL) {
92 		value = va_arg(ap, char *);
93 		(void) fprintf(fp, "%s='%s' ", name, value);
94 		name = va_arg(ap, char *);
95 	}
96 	(void) fprintf(fp, "/>\n");
97 }
98 
99 void
100 end_element(FILE *fp, const char *ename)
101 {
102 	(void) fprintf(fp, "</%s>\n", ename);
103 }
104 
105 static void
106 txml_print_prop(topo_hdl_t *thp, FILE *fp, topo_propval_t *pv)
107 {
108 	int err;
109 	char *fmri = NULL;
110 	char vbuf[INT64BUFSZ], tbuf[10], *pval;
111 	nvpair_t *nvp;
112 
113 	if ((nvp = nvlist_next_nvpair(pv->tp_val, NULL)) == NULL)
114 		return;
115 
116 	switch (pv->tp_type) {
117 		case TOPO_TYPE_INT32: {
118 			int32_t val;
119 			(void) nvpair_value_int32(nvp, &val);
120 			(void) snprintf(vbuf, INT64BUFSZ, "%d", val);
121 			(void) snprintf(tbuf, 10, "%s", Int32);
122 			pval = vbuf;
123 			break;
124 		}
125 		case TOPO_TYPE_UINT32: {
126 			uint32_t val;
127 			(void) nvpair_value_uint32(nvp, &val);
128 			(void) snprintf(vbuf, INT64BUFSZ, "0x%x", val);
129 			(void) snprintf(tbuf, 10, "%s", UInt32);
130 			pval = vbuf;
131 			break;
132 		}
133 		case TOPO_TYPE_INT64: {
134 			int64_t val;
135 			(void) nvpair_value_int64(nvp, &val);
136 			(void) snprintf(vbuf, INT64BUFSZ, "%lld",
137 			    (longlong_t)val);
138 			(void) snprintf(tbuf, 10, "%s", Int64);
139 			pval = vbuf;
140 			break;
141 		}
142 		case TOPO_TYPE_UINT64: {
143 			uint64_t val;
144 			(void) nvpair_value_uint64(nvp, &val);
145 			(void) snprintf(vbuf, INT64BUFSZ, "0x%llx",
146 			    (u_longlong_t)val);
147 			(void) snprintf(tbuf, 10, "%s", UInt64);
148 			pval = vbuf;
149 			break;
150 		}
151 		case TOPO_TYPE_STRING: {
152 			(void) nvpair_value_string(nvp, &pval);
153 			(void) snprintf(tbuf, 10, "%s", String);
154 			break;
155 		}
156 		case TOPO_TYPE_FMRI: {
157 			nvlist_t *val;
158 
159 			(void) nvpair_value_nvlist(nvp, &val);
160 			if (topo_fmri_nvl2str(thp, val, &fmri, &err) == 0)
161 				pval = fmri;
162 			else
163 				return;
164 
165 			(void) snprintf(tbuf, 10, "%s", FMRI);
166 			break;
167 		}
168 	}
169 
170 	begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf,
171 	    Value, pval, NULL);
172 
173 	if (fmri != NULL)
174 		topo_hdl_strfree(thp, fmri);
175 
176 }
177 
178 static void
179 txml_print_pgroup(topo_hdl_t *thp, FILE *fp, topo_pgroup_t *pg)
180 {
181 	topo_ipgroup_info_t *pip = pg->tpg_info;
182 	topo_proplist_t *plp;
183 	const char *namestab, *datastab;
184 	char version[INT32BUFSZ];
185 
186 	namestab = topo_stability2name(pip->tpi_namestab);
187 	datastab = topo_stability2name(pip->tpi_datastab);
188 	(void) snprintf(version, INT32BUFSZ, "%d", pip->tpi_version);
189 	begin_element(fp, Propgrp, Name, pip->tpi_name, Namestab,
190 	    namestab, Datastab, datastab, Version, version, NULL);
191 	topo_hdl_strfree(thp, (char *)namestab);
192 	topo_hdl_strfree(thp, (char *)datastab);
193 	for (plp = topo_list_next(&pg->tpg_pvals); plp != NULL;
194 	    plp = topo_list_next(plp)) {
195 		txml_print_prop(thp, fp, plp->tp_pval);
196 	}
197 	end_element(fp, Propgrp);
198 }
199 
200 static void
201 txml_print_dependents(topo_hdl_t *thp, FILE *fp, tnode_t *node)
202 {
203 	if (topo_list_next(&node->tn_children) == NULL)
204 		return;
205 
206 	if (txml_print_range(thp, fp, node, 1) == 1)
207 		end_element(fp, Dependents);
208 }
209 
210 static void
211 txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node)
212 {
213 	char inst[INT32BUFSZ];
214 	topo_pgroup_t *pg;
215 
216 	(void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance);
217 	begin_element(fp, Node, Instance, inst, Static, True, NULL);
218 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
219 	    pg = topo_list_next(pg)) {
220 		txml_print_pgroup(thp, fp, pg);
221 	}
222 	txml_print_dependents(thp, fp, node);
223 	end_element(fp, Node);
224 
225 }
226 
227 static int
228 txml_print_range(topo_hdl_t *thp, FILE *fp, tnode_t *node, int dependent)
229 {
230 	int i, create = 0, ret = 0;
231 	topo_nodehash_t *nhp;
232 	char min[INT32BUFSZ], max[INT32BUFSZ];
233 
234 	for (nhp = topo_list_next(&node->tn_children); nhp != NULL;
235 	    nhp = topo_list_next(nhp)) {
236 		(void) snprintf(min, INT32BUFSZ, "%d", nhp->th_range.tr_min);
237 		(void) snprintf(max, INT32BUFSZ, "%d", nhp->th_range.tr_max);
238 
239 		/*
240 		 * Some enumerators create empty ranges: make sure there
241 		 * are real nodes before creating this range
242 		 */
243 		for (i = 0; i < nhp->th_arrlen; ++i) {
244 			if (nhp->th_nodearr[i] != NULL)
245 				++create;
246 		}
247 		if (!create)
248 			continue;
249 
250 		if (dependent) {
251 			begin_element(fp, Dependents, Grouping, Children, NULL);
252 			dependent = 0;
253 			ret = 1;
254 		}
255 		begin_element(fp, Range, Name, nhp->th_name, Min, min, Max,
256 		    max, NULL);
257 		for (i = 0; i < nhp->th_arrlen; ++i) {
258 			if (nhp->th_nodearr[i] != NULL)
259 				txml_print_node(thp, fp, nhp->th_nodearr[i]);
260 		}
261 		end_element(fp, Range);
262 	}
263 
264 	return (ret);
265 }
266 
267 static void
268 txml_print_topology(topo_hdl_t *thp, FILE *fp, char *scheme, tnode_t *node)
269 {
270 	begin_element(fp, Topology, Name, thp->th_product, Scheme, scheme,
271 	    NULL);
272 	(void) txml_print_range(thp, fp, node, 0);
273 	end_element(fp, Topology);
274 
275 }
276 
277 int
278 topo_xml_print(topo_hdl_t *thp,  FILE *fp, const char *scheme, int *err)
279 {
280 	ttree_t *tp;
281 
282 	print_header(fp);
283 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
284 	    tp = topo_list_next(tp)) {
285 		if (strcmp(scheme, tp->tt_scheme) == 0) {
286 			txml_print_topology(thp, fp, tp->tt_scheme,
287 			    tp->tt_root);
288 			return (0);
289 		}
290 	}
291 
292 	*err = EINVAL;
293 	return (-1);
294 }
295