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
print_header(FILE * fp)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
begin_element(FILE * fp,const char * ename,...)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
begin_end_element(FILE * fp,const char * ename,...)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
end_element(FILE * fp,const char * ename)99 end_element(FILE *fp, const char *ename)
100 {
101 (void) fprintf(fp, "</%s>\n", ename);
102 }
103
104 static void
txml_print_prop(topo_hdl_t * thp,FILE * fp,tnode_t * node,const char * pgname,topo_propval_t * pv)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
txml_print_pgroup(topo_hdl_t * thp,FILE * fp,tnode_t * node,topo_pgroup_t * pg)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
txml_print_dependents(topo_hdl_t * thp,FILE * fp,tnode_t * node)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
txml_print_node(topo_hdl_t * thp,FILE * fp,tnode_t * node)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
txml_print_range(topo_hdl_t * thp,FILE * fp,tnode_t * node,int dependent)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
txml_print_topology(topo_hdl_t * thp,FILE * fp,char * scheme,tnode_t * node)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
topo_xml_print(topo_hdl_t * thp,FILE * fp,const char * scheme,int * err)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