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