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