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 * Copyright (c) 2019, Joyent, Inc. All rights reserved. 28 */ 29 30 #include <stdio.h> 31 #include <strings.h> 32 #include <time.h> 33 #include <sys/types.h> 34 #include <sys/fm/protocol.h> 35 #include <sys/utsname.h> 36 37 #include <topo_parse.h> 38 #include <topo_prop.h> 39 #include <topo_tree.h> 40 41 /* 42 * In the XML representation of the topo snapshot, 32-bit integer values are 43 * represented as base-10 values. 44 * 45 * 10 bytes for base-10 value + 1 for sign + nul 46 */ 47 #define INT32BUFSZ 12 48 /* 2 bytes for "0x" + 16 bytes for the hex value + 1 for sign + nul */ 49 #define INT64BUFSZ 20 50 #define XML_VERSION "1.0" 51 52 static int txml_print_range(topo_hdl_t *, FILE *, tnode_t *, int); 53 54 void 55 print_header(FILE *fp) 56 { 57 char buf[32]; 58 time_t tod = time(NULL); 59 struct utsname uts; 60 61 (void) fprintf(fp, "<?xml version=\"%s\"?>\n", XML_VERSION); 62 (void) fprintf(fp, "<!DOCTYPE topology SYSTEM \"%s\">\n", 63 TOPO_DTD_PATH); 64 65 (void) uname(&uts); 66 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); 67 (void) fprintf(fp, "<!--\n"); 68 (void) fprintf(fp, " This topology map file was generated on " 69 "%-15s for %s\n", buf, uts.nodename); 70 (void) fprintf(fp, "<-->\n\n"); 71 } 72 73 void 74 begin_element(FILE *fp, const char *ename, ...) 75 { 76 char *name, *value; 77 va_list ap; 78 79 (void) fprintf(fp, "<%s ", ename); 80 va_start(ap, ename); 81 name = va_arg(ap, char *); 82 while (name != NULL) { 83 value = va_arg(ap, char *); 84 (void) fprintf(fp, "%s='%s' ", name, value); 85 name = va_arg(ap, char *); 86 } 87 (void) fprintf(fp, ">\n"); 88 } 89 90 void 91 begin_end_element(FILE *fp, const char *ename, ...) 92 { 93 char *name, *value; 94 va_list ap; 95 96 (void) fprintf(fp, "<%s ", ename); 97 va_start(ap, ename); 98 name = va_arg(ap, char *); 99 while (name != NULL) { 100 value = va_arg(ap, char *); 101 (void) fprintf(fp, "%s='%s' ", name, value); 102 name = va_arg(ap, char *); 103 } 104 (void) fprintf(fp, "/>\n"); 105 } 106 107 void 108 end_element(FILE *fp, const char *ename) 109 { 110 (void) fprintf(fp, "</%s>\n", ename); 111 } 112 113 static void 114 txml_print_prop(topo_hdl_t *thp, FILE *fp, tnode_t *node, const char *pgname, 115 topo_propval_t *pv) 116 { 117 int err; 118 char *fmri = NULL; 119 char vbuf[INT64BUFSZ], tbuf[32], *pval = NULL, *aval = NULL; 120 121 switch (pv->tp_type) { 122 case TOPO_TYPE_INT32: { 123 int32_t val; 124 if (topo_prop_get_int32(node, pgname, pv->tp_name, &val, 125 &err) == 0) { 126 (void) snprintf(vbuf, INT64BUFSZ, "%d", val); 127 (void) snprintf(tbuf, sizeof (tbuf), "%s", 128 Int32); 129 pval = vbuf; 130 } else 131 return; 132 break; 133 } 134 case TOPO_TYPE_UINT32: { 135 uint32_t val; 136 if (topo_prop_get_uint32(node, pgname, pv->tp_name, 137 &val, &err) == 0) { 138 (void) snprintf(vbuf, INT64BUFSZ, "0x%x", val); 139 (void) snprintf(tbuf, sizeof (tbuf), "%s", 140 UInt32); 141 pval = vbuf; 142 } else 143 return; 144 break; 145 } 146 case TOPO_TYPE_INT64: { 147 int64_t val; 148 if (topo_prop_get_int64(node, pgname, pv->tp_name, &val, 149 &err) == 0) { 150 (void) snprintf(vbuf, INT64BUFSZ, "0x%llx", 151 (longlong_t)val); 152 (void) snprintf(tbuf, sizeof (tbuf), "%s", 153 Int64); 154 pval = vbuf; 155 } else 156 return; 157 break; 158 } 159 case TOPO_TYPE_UINT64: { 160 uint64_t val; 161 if (topo_prop_get_uint64(node, pgname, pv->tp_name, 162 &val, &err) == 0) { 163 (void) snprintf(vbuf, INT64BUFSZ, "0x%llx", 164 (u_longlong_t)val); 165 (void) snprintf(tbuf, sizeof (tbuf), "%s", 166 UInt64); 167 pval = vbuf; 168 } else 169 return; 170 break; 171 } 172 case TOPO_TYPE_STRING: { 173 if (topo_prop_get_string(node, pgname, pv->tp_name, 174 &pval, &err) != 0) 175 return; 176 (void) snprintf(tbuf, sizeof (tbuf), "%s", "string"); 177 break; 178 } 179 case TOPO_TYPE_FMRI: { 180 nvlist_t *val; 181 182 if (topo_prop_get_fmri(node, pgname, pv->tp_name, &val, 183 &err) == 0) { 184 if (topo_fmri_nvl2str(thp, val, &fmri, &err) 185 == 0) { 186 nvlist_free(val); 187 pval = fmri; 188 } else { 189 nvlist_free(val); 190 return; 191 } 192 } else 193 return; 194 (void) snprintf(tbuf, sizeof (tbuf), "%s", FMRI); 195 break; 196 } 197 case TOPO_TYPE_UINT32_ARRAY: { 198 uint32_t *val; 199 uint_t nelem, i; 200 if (topo_prop_get_uint32_array(node, pgname, 201 pv->tp_name, &val, &nelem, &err) != 0) 202 return; 203 204 if (nelem > 0) { 205 if ((aval = calloc((nelem * 9 - 1), 206 sizeof (uchar_t))) == NULL) { 207 208 topo_hdl_free(thp, val, 209 nelem * sizeof (uint32_t)); 210 return; 211 } 212 213 (void) sprintf(aval, "0x%x", val[0]); 214 for (i = 1; i < nelem; i++) { 215 (void) sprintf(vbuf, " 0x%x", val[i]); 216 (void) strcat(aval, vbuf); 217 } 218 topo_hdl_free(thp, val, 219 nelem * sizeof (uint32_t)); 220 (void) snprintf(tbuf, sizeof (tbuf), "%s", 221 UInt32_Arr); 222 pval = aval; 223 } 224 break; 225 } 226 default: 227 return; 228 } 229 230 begin_end_element(fp, Propval, Name, pv->tp_name, Type, tbuf, 231 Value, pval, NULL); 232 233 if (pval != NULL && pv->tp_type == TOPO_TYPE_STRING) 234 topo_hdl_strfree(thp, pval); 235 236 if (fmri != NULL) 237 topo_hdl_strfree(thp, fmri); 238 239 if (aval != NULL) 240 free(aval); 241 } 242 243 static void 244 txml_print_pgroup(topo_hdl_t *thp, FILE *fp, tnode_t *node, topo_pgroup_t *pg) 245 { 246 topo_ipgroup_info_t *pip = pg->tpg_info; 247 topo_proplist_t *plp; 248 const char *namestab, *datastab; 249 char version[INT32BUFSZ]; 250 251 namestab = topo_stability2name(pip->tpi_namestab); 252 datastab = topo_stability2name(pip->tpi_datastab); 253 (void) snprintf(version, INT32BUFSZ, "%d", pip->tpi_version); 254 begin_element(fp, Propgrp, Name, pip->tpi_name, Namestab, 255 namestab, Datastab, datastab, Version, version, NULL); 256 for (plp = topo_list_next(&pg->tpg_pvals); plp != NULL; 257 plp = topo_list_next(plp)) { 258 txml_print_prop(thp, fp, node, pip->tpi_name, plp->tp_pval); 259 } 260 end_element(fp, Propgrp); 261 } 262 263 static void 264 txml_print_dependents(topo_hdl_t *thp, FILE *fp, tnode_t *node) 265 { 266 if (topo_list_next(&node->tn_children) == NULL) 267 return; 268 269 if (txml_print_range(thp, fp, node, 1) == 1) 270 end_element(fp, Dependents); 271 } 272 273 static void 274 txml_print_node(topo_hdl_t *thp, FILE *fp, tnode_t *node) 275 { 276 char inst[INT32BUFSZ]; 277 topo_pgroup_t *pg; 278 279 (void) snprintf(inst, INT32BUFSZ, "%d", node->tn_instance); 280 begin_element(fp, Node, Instance, inst, Static, True, NULL); 281 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 282 pg = topo_list_next(pg)) { 283 txml_print_pgroup(thp, fp, node, pg); 284 } 285 txml_print_dependents(thp, fp, node); 286 end_element(fp, Node); 287 288 } 289 290 static int 291 txml_print_range(topo_hdl_t *thp, FILE *fp, tnode_t *node, int dependent) 292 { 293 int i, create = 0, ret = 0; 294 topo_nodehash_t *nhp; 295 char min[INT32BUFSZ], max[INT32BUFSZ]; 296 297 for (nhp = topo_list_next(&node->tn_children); nhp != NULL; 298 nhp = topo_list_next(nhp)) { 299 (void) snprintf(min, INT32BUFSZ, "%d", nhp->th_range.tr_min); 300 (void) snprintf(max, INT32BUFSZ, "%d", nhp->th_range.tr_max); 301 302 /* 303 * Some enumerators create empty ranges: make sure there 304 * are real nodes before creating this range 305 */ 306 for (i = 0; i < nhp->th_arrlen; ++i) { 307 if (nhp->th_nodearr[i] != NULL) 308 ++create; 309 } 310 if (!create) 311 continue; 312 313 if (dependent) { 314 begin_element(fp, Dependents, Grouping, Children, NULL); 315 dependent = 0; 316 ret = 1; 317 } 318 begin_element(fp, Range, Name, nhp->th_name, Min, min, Max, 319 max, NULL); 320 for (i = 0; i < nhp->th_arrlen; ++i) { 321 if (nhp->th_nodearr[i] != NULL) 322 txml_print_node(thp, fp, nhp->th_nodearr[i]); 323 } 324 end_element(fp, Range); 325 } 326 327 return (ret); 328 } 329 330 static void 331 txml_print_topology(topo_hdl_t *thp, FILE *fp, char *scheme, tnode_t *node) 332 { 333 char *name; 334 335 if (thp->th_product != NULL) 336 name = thp->th_product; 337 else 338 name = thp->th_platform; 339 340 begin_element(fp, Topology, Name, name, Scheme, scheme, 341 NULL); 342 (void) txml_print_range(thp, fp, node, 0); 343 end_element(fp, Topology); 344 345 } 346 347 int 348 topo_xml_print(topo_hdl_t *thp, FILE *fp, const char *scheme, int *err) 349 { 350 ttree_t *tp; 351 352 print_header(fp); 353 for (tp = topo_list_next(&thp->th_trees); tp != NULL; 354 tp = topo_list_next(tp)) { 355 if (strcmp(scheme, tp->tt_scheme) == 0) { 356 txml_print_topology(thp, fp, tp->tt_scheme, 357 tp->tt_root); 358 return (0); 359 } 360 } 361 362 *err = EINVAL; 363 return (-1); 364 } 365