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