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