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 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 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 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 99 end_element(FILE *fp, const char *ename) 100 { 101 (void) fprintf(fp, "</%s>\n", ename); 102 } 103 104 static void 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 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 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 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 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 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 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