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