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 #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, *aval; 111 nvpair_t *nvp; 112 113 nvp = nvlist_next_nvpair(pv->tp_val, NULL); 114 while (nvp && (strcmp(TOPO_PROP_VAL_VAL, nvpair_name(nvp)) != 0)) 115 nvp = nvlist_next_nvpair(pv->tp_val, nvp); 116 117 if (nvp == NULL) 118 return; 119 120 switch (pv->tp_type) { 121 case TOPO_TYPE_INT32: { 122 int32_t val; 123 (void) nvpair_value_int32(nvp, &val); 124 (void) snprintf(vbuf, INT64BUFSZ, "%d", val); 125 (void) snprintf(tbuf, 10, "%s", Int32); 126 pval = vbuf; 127 break; 128 } 129 case TOPO_TYPE_UINT32: { 130 uint32_t val; 131 (void) nvpair_value_uint32(nvp, &val); 132 (void) snprintf(vbuf, INT64BUFSZ, "0x%x", val); 133 (void) snprintf(tbuf, 10, "%s", UInt32); 134 pval = vbuf; 135 break; 136 } 137 case TOPO_TYPE_INT64: { 138 int64_t val; 139 (void) nvpair_value_int64(nvp, &val); 140 (void) snprintf(vbuf, INT64BUFSZ, "%lld", 141 (longlong_t)val); 142 (void) snprintf(tbuf, 10, "%s", Int64); 143 pval = vbuf; 144 break; 145 } 146 case TOPO_TYPE_UINT64: { 147 uint64_t val; 148 (void) nvpair_value_uint64(nvp, &val); 149 (void) snprintf(vbuf, INT64BUFSZ, "0x%llx", 150 (u_longlong_t)val); 151 (void) snprintf(tbuf, 10, "%s", UInt64); 152 pval = vbuf; 153 break; 154 } 155 case TOPO_TYPE_STRING: { 156 (void) nvpair_value_string(nvp, &pval); 157 (void) snprintf(tbuf, 10, "%s", String); 158 break; 159 } 160 case TOPO_TYPE_FMRI: { 161 nvlist_t *val; 162 163 (void) nvpair_value_nvlist(nvp, &val); 164 if (topo_fmri_nvl2str(thp, val, &fmri, &err) == 0) 165 pval = fmri; 166 else 167 return; 168 169 (void) snprintf(tbuf, 10, "%s", FMRI); 170 break; 171 } 172 case TOPO_TYPE_UINT32_ARRAY: { 173 uint32_t *val; 174 uint_t nelem, i; 175 176 (void) nvpair_value_uint32_array(nvp, &val, &nelem); 177 178 if (nelem > 0) { 179 aval = calloc((nelem*9-1), sizeof (uchar_t)); 180 181 (void) sprintf(aval, "0x%x", val[0]); 182 for (i = 1; i < nelem; i++) { 183 (void) sprintf(vbuf, " 0x%x", val[i]); 184 (void) strcat(aval, vbuf); 185 } 186 (void) snprintf(tbuf, 10, "%s", UInt32_Arr); 187 pval = aval; 188 } 189 break; 190 } 191 } 192 193 begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf, 194 Value, pval, NULL); 195 196 if (fmri != NULL) 197 topo_hdl_strfree(thp, fmri); 198 199 } 200 201 static void 202 txml_print_pgroup(topo_hdl_t *thp, FILE *fp, topo_pgroup_t *pg) 203 { 204 topo_ipgroup_info_t *pip = pg->tpg_info; 205 topo_proplist_t *plp; 206 const char *namestab, *datastab; 207 char version[INT32BUFSZ]; 208 209 namestab = topo_stability2name(pip->tpi_namestab); 210 datastab = topo_stability2name(pip->tpi_datastab); 211 (void) snprintf(version, INT32BUFSZ, "%d", pip->tpi_version); 212 begin_element(fp, Propgrp, Name, pip->tpi_name, Namestab, 213 namestab, Datastab, datastab, Version, version, NULL); 214 for (plp = topo_list_next(&pg->tpg_pvals); plp != NULL; 215 plp = topo_list_next(plp)) { 216 txml_print_prop(thp, fp, plp->tp_pval); 217 } 218 end_element(fp, Propgrp); 219 } 220 221 static void 222 txml_print_dependents(topo_hdl_t *thp, FILE *fp, tnode_t *node) 223 { 224 if (topo_list_next(&node->tn_children) == NULL) 225 return; 226 227 if (txml_print_range(thp, fp, node, 1) == 1) 228 end_element(fp, Dependents); 229 } 230 231 static void 232 txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node) 233 { 234 char inst[INT32BUFSZ]; 235 topo_pgroup_t *pg; 236 237 (void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance); 238 begin_element(fp, Node, Instance, inst, Static, True, NULL); 239 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 240 pg = topo_list_next(pg)) { 241 txml_print_pgroup(thp, fp, pg); 242 } 243 txml_print_dependents(thp, fp, node); 244 end_element(fp, Node); 245 246 } 247 248 static int 249 txml_print_range(topo_hdl_t *thp, FILE *fp, tnode_t *node, int dependent) 250 { 251 int i, create = 0, ret = 0; 252 topo_nodehash_t *nhp; 253 char min[INT32BUFSZ], max[INT32BUFSZ]; 254 255 for (nhp = topo_list_next(&node->tn_children); nhp != NULL; 256 nhp = topo_list_next(nhp)) { 257 (void) snprintf(min, INT32BUFSZ, "%d", nhp->th_range.tr_min); 258 (void) snprintf(max, INT32BUFSZ, "%d", nhp->th_range.tr_max); 259 260 /* 261 * Some enumerators create empty ranges: make sure there 262 * are real nodes before creating this range 263 */ 264 for (i = 0; i < nhp->th_arrlen; ++i) { 265 if (nhp->th_nodearr[i] != NULL) 266 ++create; 267 } 268 if (!create) 269 continue; 270 271 if (dependent) { 272 begin_element(fp, Dependents, Grouping, Children, NULL); 273 dependent = 0; 274 ret = 1; 275 } 276 begin_element(fp, Range, Name, nhp->th_name, Min, min, Max, 277 max, NULL); 278 for (i = 0; i < nhp->th_arrlen; ++i) { 279 if (nhp->th_nodearr[i] != NULL) 280 txml_print_node(thp, fp, nhp->th_nodearr[i]); 281 } 282 end_element(fp, Range); 283 } 284 285 return (ret); 286 } 287 288 static void 289 txml_print_topology(topo_hdl_t *thp, FILE *fp, char *scheme, tnode_t *node) 290 { 291 char *name; 292 293 if (thp->th_product != NULL) 294 name = thp->th_product; 295 else 296 name = thp->th_platform; 297 298 begin_element(fp, Topology, Name, name, Scheme, scheme, 299 NULL); 300 (void) txml_print_range(thp, fp, node, 0); 301 end_element(fp, Topology); 302 303 } 304 305 int 306 topo_xml_print(topo_hdl_t *thp, FILE *fp, const char *scheme, int *err) 307 { 308 ttree_t *tp; 309 310 print_header(fp); 311 for (tp = topo_list_next(&thp->th_trees); tp != NULL; 312 tp = topo_list_next(tp)) { 313 if (strcmp(scheme, tp->tt_scheme) == 0) { 314 txml_print_topology(thp, fp, tp->tt_scheme, 315 tp->tt_root); 316 return (0); 317 } 318 } 319 320 *err = EINVAL; 321 return (-1); 322 } 323