Home | History | Annotate | Download | only in eversholt
      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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * platform.c -- interfaces to the platform's configuration information
     26  *
     27  * this platform.c allows eft to run on Solaris systems.
     28  */
     29 
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <strings.h>
     34 #include <ctype.h>
     35 #include <dirent.h>
     36 #include <libnvpair.h>
     37 #include <dlfcn.h>
     38 #include <unistd.h>
     39 #include <errno.h>
     40 #include <stropts.h>
     41 #include <sys/types.h>
     42 #include <sys/stat.h>
     43 #include <sys/wait.h>
     44 #include <sys/filio.h>
     45 #include <sys/param.h>
     46 #include <sys/fm/protocol.h>
     47 #include <fm/fmd_api.h>
     48 #include <fm/fmd_fmri.h>
     49 #include <fm/libtopo.h>
     50 #include <fm/topo_hc.h>
     51 #include "alloc.h"
     52 #include "out.h"
     53 #include "tree.h"
     54 #include "itree.h"
     55 #include "ipath.h"
     56 #include "ptree.h"
     57 #include "fme.h"
     58 #include "stable.h"
     59 #include "eval.h"
     60 #include "config.h"
     61 #include "platform.h"
     62 
     63 extern fmd_hdl_t *Hdl;		/* handle from eft.c */
     64 
     65 /*
     66  * Lastcfg points to the last configuration snapshot we made.
     67  */
     68 static struct cfgdata *Lastcfg;
     69 static fmd_hdl_t *Lasthdl;
     70 static fmd_case_t *Lastfmcase;
     71 static const char *lastcomp;
     72 static int in_getpath;
     73 extern struct lut *Usednames;
     74 int prune_raw_config = 0;
     75 
     76 static topo_hdl_t *Eft_topo_hdl;
     77 
     78 void *
     79 topo_use_alloc(size_t bytes)
     80 {
     81 	void *p = alloc_malloc(bytes, NULL, 0);
     82 
     83 	bzero(p, bytes);
     84 	return (p);
     85 }
     86 
     87 void
     88 topo_use_free(void *p)
     89 {
     90 	alloc_free(p, NULL, 0);
     91 }
     92 
     93 /*ARGSUSED*/
     94 static void *
     95 alloc_nv_alloc(nv_alloc_t *nva, size_t size)
     96 {
     97 	return (alloc_malloc(size, NULL, 0));
     98 }
     99 
    100 /*ARGSUSED*/
    101 static void
    102 alloc_nv_free(nv_alloc_t *nva, void *p, size_t sz)
    103 {
    104 	alloc_free(p, NULL, 0);
    105 }
    106 
    107 const nv_alloc_ops_t Eft_nv_alloc_ops = {
    108 	NULL,		/* nv_ao_init() */
    109 	NULL,		/* nv_ao_fini() */
    110 	alloc_nv_alloc,	/* nv_ao_alloc() */
    111 	alloc_nv_free,	/* nv_ao_free() */
    112 	NULL		/* nv_ao_reset() */
    113 };
    114 
    115 nv_alloc_t Eft_nv_hdl;
    116 
    117 static char *Root;
    118 static char *Mach;
    119 static char *Plat;
    120 static char tmpbuf[MAXPATHLEN];
    121 static char numbuf[MAXPATHLEN];
    122 
    123 /*
    124  * platform_globals -- set global variables based on sysinfo() calls
    125  */
    126 static void
    127 platform_globals()
    128 {
    129 	Root = fmd_prop_get_string(Hdl, "fmd.rootdir");
    130 	Mach = fmd_prop_get_string(Hdl, "fmd.machine");
    131 	Plat = fmd_prop_get_string(Hdl, "fmd.platform");
    132 }
    133 
    134 static void
    135 platform_free_globals()
    136 {
    137 	fmd_prop_free_string(Hdl, Root);
    138 	fmd_prop_free_string(Hdl, Mach);
    139 	fmd_prop_free_string(Hdl, Plat);
    140 }
    141 
    142 /*
    143  * platform_init -- perform any platform-specific initialization
    144  */
    145 void
    146 platform_init(void)
    147 {
    148 	(void) nv_alloc_init(&Eft_nv_hdl, &Eft_nv_alloc_ops);
    149 	Eft_topo_hdl = fmd_hdl_topo_hold(Hdl, TOPO_VERSION);
    150 	platform_globals();
    151 
    152 	out(O_ALTFP, "platform_init() sucessful");
    153 }
    154 
    155 void
    156 platform_fini(void)
    157 {
    158 	if (Lastcfg != NULL) {
    159 		config_free(Lastcfg);
    160 		Lastcfg = NULL;
    161 	}
    162 	fmd_hdl_topo_rele(Hdl, Eft_topo_hdl);
    163 	platform_free_globals();
    164 	(void) nv_alloc_fini(&Eft_nv_hdl);
    165 
    166 	out(O_ALTFP, "platform_fini() sucessful");
    167 }
    168 
    169 /*
    170  * hc_fmri_nodeize -- convert hc-scheme FMRI to eft compatible format
    171  *
    172  * this is an internal platform.c helper routine
    173  */
    174 static struct node *
    175 hc_fmri_nodeize(nvlist_t *hcfmri)
    176 {
    177 	struct node *pathtree = NULL;
    178 	struct node *tmpn;
    179 	nvlist_t **hc_prs;
    180 	uint_t hc_nprs;
    181 	const char *sname;
    182 	char *ename;
    183 	char *eid;
    184 	int e, r;
    185 
    186 	/*
    187 	 * What to do with/about hc-root?  Would we have any clue what
    188 	 * to do with it if it weren't /?  For now, we don't bother
    189 	 * even looking it up.
    190 	 */
    191 
    192 	/*
    193 	 * Get the hc-list of elements in the FMRI
    194 	 */
    195 	if (nvlist_lookup_nvlist_array(hcfmri, FM_FMRI_HC_LIST,
    196 	    &hc_prs, &hc_nprs) != 0) {
    197 		out(O_ALTFP, "XFILE: hc FMRI missing %s", FM_FMRI_HC_LIST);
    198 		return (NULL);
    199 	}
    200 
    201 	for (e = 0; e < hc_nprs; e++) {
    202 		ename = NULL;
    203 		eid = NULL;
    204 		r = nvlist_lookup_string(hc_prs[e], FM_FMRI_HC_NAME, &ename);
    205 		r |= nvlist_lookup_string(hc_prs[e], FM_FMRI_HC_ID, &eid);
    206 		if (r != 0) {
    207 			/* probably should bail */
    208 			continue;
    209 		}
    210 		sname = stable(ename);
    211 		tmpn = tree_name_iterator(
    212 		    tree_name(sname, IT_VERTICAL, NULL, 0),
    213 		    tree_num(eid, NULL, 0));
    214 
    215 		if (pathtree == NULL)
    216 			pathtree = tmpn;
    217 		else
    218 			(void) tree_name_append(pathtree, tmpn);
    219 	}
    220 
    221 	return (pathtree);
    222 }
    223 
    224 /*
    225  * platform_getpath -- extract eft-compatible path from ereport
    226  */
    227 struct node *
    228 platform_getpath(nvlist_t *nvl)
    229 {
    230 	struct node	*ret;
    231 	nvlist_t	*dfmri;
    232 	char		*scheme;
    233 	char		*path;
    234 	char		*devid;
    235 	uint32_t	cpuid;
    236 	enum {DT_HC, DT_DEVID, DT_DEV, DT_CPU, DT_UNKNOWN} type = DT_UNKNOWN;
    237 
    238 	/* Find the detector */
    239 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &dfmri) != 0) {
    240 		out(O_ALTFP, "XFILE: ereport has no detector FMRI");
    241 		return (NULL);
    242 	}
    243 
    244 	/* get the scheme from the detector */
    245 	if (nvlist_lookup_string(dfmri, FM_FMRI_SCHEME, &scheme) != 0) {
    246 		out(O_ALTFP, "XFILE: detector FMRI missing scheme");
    247 		return (NULL);
    248 	}
    249 
    250 	/* based on scheme, determine type */
    251 	if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
    252 		/* already in hc scheme */
    253 		return (hc_fmri_nodeize(dfmri));
    254 	} else if (strcmp(scheme, FM_FMRI_SCHEME_DEV) == 0) {
    255 		/* devid takes precedence over path */
    256 		if (nvlist_lookup_string(dfmri,
    257 		    FM_FMRI_DEV_ID, &devid) == 0)
    258 			type = DT_DEVID;
    259 		else if (nvlist_lookup_string(dfmri,
    260 		    FM_FMRI_DEV_PATH, &path) == 0)
    261 			type = DT_DEV;
    262 		else {
    263 			out(O_ALTFP, "XFILE: detector FMRI missing %s or %s",
    264 			    FM_FMRI_DEV_ID, FM_FMRI_DEV_PATH);
    265 			return (NULL);
    266 		}
    267 	} else if (strcmp(scheme, FM_FMRI_SCHEME_CPU) == 0) {
    268 		if (nvlist_lookup_uint32(dfmri, FM_FMRI_CPU_ID, &cpuid) == 0)
    269 			type = DT_CPU;
    270 		else {
    271 			out(O_ALTFP, "XFILE: detector FMRI missing %s",
    272 			    FM_FMRI_CPU_ID);
    273 			return (NULL);
    274 		}
    275 	} else {
    276 		out(O_ALTFP, "XFILE: detector FMRI not recognized "
    277 		    "(scheme is %s, expect %s or %s or %s)",
    278 		    scheme, FM_FMRI_SCHEME_HC, FM_FMRI_SCHEME_DEV,
    279 		    FM_FMRI_SCHEME_CPU);
    280 		return (NULL);
    281 	}
    282 
    283 	out(O_ALTFP|O_VERB, "Received ereport in scheme %s", scheme);
    284 
    285 	/* take a config snapshot */
    286 	lut_free(Usednames, NULL, NULL);
    287 	Usednames = NULL;
    288 	in_getpath = 1;
    289 	if (config_snapshot() == NULL) {
    290 		out(O_ALTFP, "XFILE: cannot snapshot configuration");
    291 		in_getpath = 0;
    292 		return (NULL);
    293 	}
    294 
    295 	/* Look up the path, cpuid, or devid in the last config snapshot. */
    296 	switch (type) {
    297 	case DT_DEV:
    298 		if ((ret = config_bydev_lookup(Lastcfg, path)) == NULL)
    299 			out(O_ALTFP, "platform_getpath: no configuration node "
    300 			    "has device path matching \"%s\".", path);
    301 
    302 		break;
    303 
    304 	case DT_DEVID:
    305 		if ((ret = config_bydevid_lookup(Lastcfg, devid)) == NULL)
    306 			out(O_ALTFP, "platform_getpath: no configuration node "
    307 			    "has devid matching \"%s\".", devid);
    308 		break;
    309 
    310 	case DT_CPU:
    311 		if ((ret = config_bycpuid_lookup(Lastcfg, cpuid)) == NULL)
    312 			out(O_ALTFP, "platform_getpath: no configuration node "
    313 			    "has cpu-id matching %u.", cpuid);
    314 		break;
    315 	}
    316 
    317 	/* free the snapshot */
    318 	structconfig_free(Lastcfg->cooked);
    319 	config_free(Lastcfg);
    320 	in_getpath = 0;
    321 	return (ret);
    322 }
    323 
    324 /* Allocate space for raw config strings in chunks of this size */
    325 #define	STRSBUFLEN	512
    326 
    327 /*
    328  * cfgadjust -- Make sure the amount we want to add to the raw config string
    329  *		buffer will fit, and if not, increase the size of the buffer.
    330  */
    331 static void
    332 cfgadjust(struct cfgdata *rawdata, int addlen)
    333 {
    334 	int curnext, newlen;
    335 
    336 	if (rawdata->nextfree + addlen >= rawdata->end) {
    337 		newlen = (((rawdata->nextfree - rawdata->begin + 1 + addlen)
    338 		    / STRSBUFLEN) + 1) * STRSBUFLEN;
    339 		curnext = rawdata->nextfree - rawdata->begin;
    340 		rawdata->begin = REALLOC(rawdata->begin, newlen);
    341 		rawdata->nextfree = rawdata->begin + curnext;
    342 		rawdata->end = rawdata->begin + newlen;
    343 	}
    344 }
    345 
    346 static char *
    347 hc_path(tnode_t *node)
    348 {
    349 	int i, err;
    350 	char *name, *instance, *estr;
    351 	nvlist_t *fmri, **hcl;
    352 	ulong_t ul;
    353 	uint_t nhc;
    354 
    355 	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
    356 	    &fmri, &err) < 0)
    357 		return (NULL);
    358 
    359 	if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &nhc)
    360 	    != 0) {
    361 		nvlist_free(fmri);
    362 		return (NULL);
    363 	}
    364 
    365 	tmpbuf[0] = '\0';
    366 	for (i = 0; i < nhc; ++i) {
    367 		err = nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name);
    368 		err |= nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &instance);
    369 		if (err) {
    370 			nvlist_free(fmri);
    371 			return (NULL);
    372 		}
    373 
    374 		ul = strtoul(instance, &estr, 10);
    375 		/* conversion to number failed? */
    376 		if (estr == instance) {
    377 			nvlist_free(fmri);
    378 			return (NULL);
    379 		}
    380 
    381 		(void) strlcat(tmpbuf, "/", MAXPATHLEN);
    382 		(void) strlcat(tmpbuf, name, MAXPATHLEN);
    383 		(void) snprintf(numbuf, MAXPATHLEN, "%lu", ul);
    384 		(void) strlcat(tmpbuf, numbuf, MAXPATHLEN);
    385 		lastcomp = stable(name);
    386 	}
    387 
    388 	nvlist_free(fmri);
    389 
    390 	return (tmpbuf);
    391 }
    392 
    393 static void
    394 add_prop_val(topo_hdl_t *thp, struct cfgdata *rawdata, char *propn,
    395     nvpair_t *pv_nvp)
    396 {
    397 	int addlen, err;
    398 	char *propv, *fmristr = NULL;
    399 	nvlist_t *fmri;
    400 	uint32_t ui32;
    401 	int64_t i64;
    402 	int32_t i32;
    403 	boolean_t bool;
    404 	uint64_t ui64;
    405 	char buf[32];	/* big enough for any 64-bit int */
    406 
    407 	/*
    408 	 * malformed prop nvpair
    409 	 */
    410 	if (propn == NULL)
    411 		return;
    412 
    413 	/*
    414 	 * We can only handle properties of string type
    415 	 */
    416 	switch (nvpair_type(pv_nvp)) {
    417 	case DATA_TYPE_STRING:
    418 		(void) nvpair_value_string(pv_nvp, &propv);
    419 		break;
    420 
    421 	case DATA_TYPE_NVLIST:
    422 		/*
    423 		 * At least try to collect the protocol
    424 		 * properties
    425 		 */
    426 		(void) nvpair_value_nvlist(pv_nvp, &fmri);
    427 		if (topo_fmri_nvl2str(thp, fmri, &fmristr, &err) < 0) {
    428 			out(O_ALTFP, "cfgcollect: failed to convert fmri to "
    429 			    "string");
    430 			return;
    431 		} else {
    432 			propv = fmristr;
    433 		}
    434 		break;
    435 
    436 	case DATA_TYPE_UINT64:
    437 		/*
    438 		 * Convert uint64 to hex strings
    439 		 */
    440 		(void) nvpair_value_uint64(pv_nvp, &ui64);
    441 		(void) snprintf(buf, sizeof (buf), "0x%llx", ui64);
    442 		propv = buf;
    443 		break;
    444 
    445 	case DATA_TYPE_BOOLEAN_VALUE:
    446 		/*
    447 		 * Convert boolean_t to hex strings
    448 		 */
    449 		(void) nvpair_value_boolean_value(pv_nvp, &bool);
    450 		(void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)bool);
    451 		propv = buf;
    452 		break;
    453 
    454 	case DATA_TYPE_INT32:
    455 		/*
    456 		 * Convert int32 to hex strings
    457 		 */
    458 		(void) nvpair_value_int32(pv_nvp, &i32);
    459 		(void) snprintf(buf, sizeof (buf), "0x%llx",
    460 		    (uint64_t)(int64_t)i32);
    461 		propv = buf;
    462 		break;
    463 
    464 	case DATA_TYPE_INT64:
    465 		/*
    466 		 * Convert int64 to hex strings
    467 		 */
    468 		(void) nvpair_value_int64(pv_nvp, &i64);
    469 		(void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)i64);
    470 		propv = buf;
    471 		break;
    472 
    473 	case DATA_TYPE_UINT32:
    474 		/*
    475 		 * Convert uint32 to hex strings
    476 		 */
    477 		(void) nvpair_value_uint32(pv_nvp, &ui32);
    478 		(void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)ui32);
    479 		propv = buf;
    480 		break;
    481 
    482 	default:
    483 		out(O_ALTFP, "cfgcollect: failed to get property value for "
    484 		    "%s", propn);
    485 		return;
    486 	}
    487 
    488 	/* = & NULL */
    489 	addlen = strlen(propn) + strlen(propv) + 2;
    490 	cfgadjust(rawdata, addlen);
    491 	(void) snprintf(rawdata->nextfree,
    492 	    rawdata->end - rawdata->nextfree, "%s=%s",
    493 	    propn, propv);
    494 	if (strcmp(propn, TOPO_PROP_RESOURCE) == 0)
    495 		out(O_ALTFP|O_VERB3, "cfgcollect: %s", propv);
    496 
    497 	rawdata->nextfree += addlen;
    498 
    499 	if (fmristr != NULL)
    500 		topo_hdl_strfree(thp, fmristr);
    501 }
    502 
    503 /*
    504  * cfgcollect -- Assemble raw configuration data in string form suitable
    505  *		 for checkpointing.
    506  */
    507 static int
    508 cfgcollect(topo_hdl_t *thp, tnode_t *node, void *arg)
    509 {
    510 	struct cfgdata *rawdata = (struct cfgdata *)arg;
    511 	int err, addlen;
    512 	char *propn, *path = NULL;
    513 	nvlist_t *p_nv, *pg_nv, *pv_nv;
    514 	nvpair_t *nvp, *pg_nvp, *pv_nvp;
    515 
    516 	if (topo_node_flags(node) == TOPO_NODE_FACILITY)
    517 		return (TOPO_WALK_NEXT);
    518 
    519 	path = hc_path(node);
    520 	if (path == NULL)
    521 		return (TOPO_WALK_ERR);
    522 
    523 	addlen = strlen(path) + 1;
    524 
    525 	cfgadjust(rawdata, addlen);
    526 	(void) strcpy(rawdata->nextfree, path);
    527 	rawdata->nextfree += addlen;
    528 
    529 	/*
    530 	 * If the prune_raw_config flag is set then we will only include in the
    531 	 * raw config those nodes that are used by the rules remaining after
    532 	 * prune_propagations() has been run - ie only those that could possibly
    533 	 * be relevant to the incoming ereport given the current rules. This
    534 	 * means that any other parts of the config will not get saved to the
    535 	 * checkpoint file (even if they may theoretically be used if the
    536 	 * rules are subsequently modified).
    537 	 *
    538 	 * For now prune_raw_config is 0 for Solaris, though it is expected to
    539 	 * be set to 1 for fmsp.
    540 	 *
    541 	 * Note we only prune the raw config like this if we have been called
    542 	 * from newfme(), not if we have been called when handling dev or cpu
    543 	 * scheme ereports from platform_getpath(), as this is called before
    544 	 * prune_propagations() - again this is not an issue on fmsp as the
    545 	 * ereports are all in hc scheme.
    546 	 */
    547 	if (!in_getpath && prune_raw_config &&
    548 	    lut_lookup(Usednames, (void *)lastcomp, NULL) == NULL)
    549 		return (TOPO_WALK_NEXT);
    550 
    551 	/*
    552 	 * Collect properties
    553 	 *
    554 	 * eversholt should support alternate property types
    555 	 * Better yet, topo properties could be represented as
    556 	 * a packed nvlist
    557 	 */
    558 	p_nv = topo_prop_getprops(node, &err);
    559 	for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL;
    560 	    nvp = nvlist_next_nvpair(p_nv, nvp)) {
    561 		if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 ||
    562 		    nvpair_type(nvp) != DATA_TYPE_NVLIST)
    563 			continue;
    564 
    565 		(void) nvpair_value_nvlist(nvp, &pg_nv);
    566 
    567 		for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL;
    568 		    pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) {
    569 
    570 			if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) != 0 ||
    571 			    nvpair_type(pg_nvp) != DATA_TYPE_NVLIST)
    572 				continue;
    573 
    574 			(void) nvpair_value_nvlist(pg_nvp, &pv_nv);
    575 
    576 			propn = NULL;
    577 			for (pv_nvp = nvlist_next_nvpair(pv_nv, NULL);
    578 			    pv_nvp != NULL;
    579 			    pv_nvp = nvlist_next_nvpair(pv_nv, pv_nvp)) {
    580 
    581 				/* Get property name */
    582 				if (strcmp(TOPO_PROP_VAL_NAME,
    583 				    nvpair_name(pv_nvp)) == 0)
    584 					(void) nvpair_value_string(pv_nvp,
    585 					    &propn);
    586 
    587 				/*
    588 				 * Get property value
    589 				 */
    590 				if (strcmp(TOPO_PROP_VAL_VAL,
    591 				    nvpair_name(pv_nvp)) == 0)
    592 					add_prop_val(thp, rawdata, propn,
    593 					    pv_nvp);
    594 			}
    595 
    596 		}
    597 	}
    598 
    599 	nvlist_free(p_nv);
    600 
    601 	return (TOPO_WALK_NEXT);
    602 }
    603 
    604 void
    605 platform_restore_config(fmd_hdl_t *hdl, fmd_case_t *fmcase)
    606 {
    607 	if (hdl == Lasthdl && fmcase == Lastfmcase) {
    608 		size_t cfglen;
    609 
    610 		fmd_buf_read(Lasthdl, Lastfmcase, WOBUF_CFGLEN, (void *)&cfglen,
    611 		    sizeof (size_t));
    612 		Lastcfg->begin = MALLOC(cfglen);
    613 		Lastcfg->end = Lastcfg->nextfree = Lastcfg->begin + cfglen;
    614 		fmd_buf_read(Lasthdl, Lastfmcase, WOBUF_CFG, Lastcfg->begin,
    615 		    cfglen);
    616 		Lasthdl = NULL;
    617 		Lastfmcase = NULL;
    618 	}
    619 }
    620 
    621 void
    622 platform_save_config(fmd_hdl_t *hdl, fmd_case_t *fmcase)
    623 {
    624 	size_t cfglen;
    625 
    626 	/*
    627 	 * Put the raw config into an fmd_buf. Then we can free it to
    628 	 * save space.
    629 	 */
    630 	Lastfmcase = fmcase;
    631 	Lasthdl = hdl;
    632 	cfglen = Lastcfg->nextfree - Lastcfg->begin;
    633 	fmd_buf_create(hdl, fmcase, WOBUF_CFGLEN, sizeof (cfglen));
    634 	fmd_buf_write(hdl, fmcase, WOBUF_CFGLEN, (void *)&cfglen,
    635 	    sizeof (cfglen));
    636 	if (cfglen != 0) {
    637 		fmd_buf_create(hdl, fmcase, WOBUF_CFG, cfglen);
    638 		fmd_buf_write(hdl, fmcase, WOBUF_CFG, Lastcfg->begin, cfglen);
    639 	}
    640 	FREE(Lastcfg->begin);
    641 	Lastcfg->begin = NULL;
    642 	Lastcfg->end = NULL;
    643 	Lastcfg->nextfree = NULL;
    644 }
    645 
    646 /*
    647  * platform_config_snapshot -- gather a snapshot of the current configuration
    648  */
    649 struct cfgdata *
    650 platform_config_snapshot(void)
    651 {
    652 	int err;
    653 	topo_walk_t *twp;
    654 	static uint64_t lastgen;
    655 	uint64_t curgen;
    656 
    657 	/*
    658 	 * If the DR generation number has changed,
    659 	 * we need to grab a new snapshot, otherwise we
    660 	 * can simply point them at the last config.
    661 	 */
    662 	if (prune_raw_config == 0 && (curgen = fmd_fmri_get_drgen()) <=
    663 	    lastgen && Lastcfg != NULL) {
    664 		Lastcfg->raw_refcnt++;
    665 		/*
    666 		 * if config has been backed away to an fmd_buf, restore it
    667 		 */
    668 		if (Lastcfg->begin == NULL)
    669 			platform_restore_config(Lasthdl, Lastfmcase);
    670 		return (Lastcfg);
    671 	}
    672 
    673 	lastgen = curgen;
    674 	/* we're getting a new config, so clean up the last one */
    675 	if (Lastcfg != NULL) {
    676 		if (--Lastcfg->raw_refcnt == 0) {
    677 			if (Lastcfg->begin != NULL)
    678 				FREE(Lastcfg->begin);
    679 			FREE(Lastcfg);
    680 		}
    681 	}
    682 
    683 	Lastcfg = MALLOC(sizeof (struct cfgdata));
    684 	Lastcfg->raw_refcnt = 2;	/* caller + Lastcfg */
    685 	Lastcfg->begin = Lastcfg->nextfree = Lastcfg->end = NULL;
    686 	Lastcfg->cooked = NULL;
    687 	Lastcfg->devcache = NULL;
    688 	Lastcfg->devidcache = NULL;
    689 	Lastcfg->cpucache = NULL;
    690 
    691 
    692 	fmd_hdl_topo_rele(Hdl, Eft_topo_hdl);
    693 	Eft_topo_hdl = fmd_hdl_topo_hold(Hdl, TOPO_VERSION);
    694 
    695 	if ((twp = topo_walk_init(Eft_topo_hdl, FM_FMRI_SCHEME_HC, cfgcollect,
    696 	    Lastcfg, &err)) == NULL) {
    697 		out(O_DIE, "platform_config_snapshot: NULL topology tree: %s",
    698 		    topo_strerror(err));
    699 	}
    700 
    701 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
    702 		topo_walk_fini(twp);
    703 		out(O_DIE, "platform_config_snapshot: error walking topology "
    704 		    "tree");
    705 	}
    706 
    707 	topo_walk_fini(twp);
    708 	out(O_ALTFP|O_STAMP, "raw config complete");
    709 
    710 
    711 	return (Lastcfg);
    712 }
    713 
    714 static const char *
    715 cfgstrprop_lookup(struct config *croot, char *path, char *pname)
    716 {
    717 	struct config *cresource;
    718 	const char *fmristr;
    719 
    720 	/*
    721 	 * The first order of business is to find the resource in the
    722 	 * config database so we can examine properties associated with
    723 	 * that node.
    724 	 */
    725 	if ((cresource = config_lookup(croot, path, 0)) == NULL) {
    726 		out(O_ALTFP, "Cannot find config info for %s.", path);
    727 		return (NULL);
    728 	}
    729 	if ((fmristr = config_getprop(cresource, pname)) == NULL) {
    730 		out(O_ALTFP, "Cannot find %s property for %s resource "
    731 		    "re-write", pname, path);
    732 		return (NULL);
    733 	}
    734 	return (fmristr);
    735 }
    736 
    737 /*
    738  * Get resource FMRI from libtopo
    739  */
    740 /*ARGSUSED*/
    741 void
    742 platform_units_translate(int isdefect, struct config *croot,
    743     nvlist_t **dfltasru, nvlist_t **dfltfru, nvlist_t **dfltrsrc, char *path)
    744 {
    745 	const char *fmristr;
    746 	char *serial;
    747 	nvlist_t *rsrc;
    748 	int err;
    749 
    750 	fmristr = cfgstrprop_lookup(croot, path, TOPO_PROP_RESOURCE);
    751 	if (fmristr == NULL) {
    752 		out(O_ALTFP, "Cannot rewrite resource for %s.", path);
    753 		return;
    754 	}
    755 	if (topo_fmri_str2nvl(Eft_topo_hdl, fmristr, &rsrc, &err) < 0) {
    756 		out(O_ALTFP, "Can not convert config info: %s",
    757 		    topo_strerror(err));
    758 		out(O_ALTFP, "Cannot rewrite resource for %s.", path);
    759 		return;
    760 	}
    761 
    762 	/*
    763 	 * If we don't have a serial number in the resource then check if it
    764 	 * is available as a separate property and if so then add it.
    765 	 */
    766 	if (nvlist_lookup_string(rsrc, FM_FMRI_HC_SERIAL_ID, &serial) != 0) {
    767 		serial = (char *)cfgstrprop_lookup(croot, path,
    768 		    FM_FMRI_HC_SERIAL_ID);
    769 		if (serial != NULL)
    770 			(void) nvlist_add_string(rsrc, FM_FMRI_HC_SERIAL_ID,
    771 			    serial);
    772 	}
    773 
    774 	*dfltrsrc = rsrc;
    775 }
    776 
    777 /*
    778  * platform_get_files -- return names of all files we should load
    779  *
    780  * search directories in dirname[] for all files with names ending with the
    781  * substring fnstr.  dirname[] should be a NULL-terminated array.  fnstr
    782  * may be set to "*" to indicate all files in a directory.
    783  *
    784  * if nodups is non-zero, then the first file of a given name found is
    785  * the only file added to the list of names.  for example if nodups is
    786  * set and we're looking for .efts, and find a pci.eft in the dirname[0],
    787  * then no pci.eft found in any of the other dirname[] entries will be
    788  * included in the final list of names.
    789  *
    790  * this routine doesn't return NULL, even if no files are found (in that
    791  * case, a char ** is returned with the first element NULL).
    792  */
    793 static char **
    794 platform_get_files(const char *dirname[], const char *fnstr, int nodups)
    795 {
    796 	DIR *dirp;
    797 	struct dirent *dp;
    798 	struct lut *foundnames = NULL;
    799 	char **files = NULL;	/* char * array of filenames found */
    800 	int nfiles = 0;		/* files found so far */
    801 	int slots = 0;		/* char * slots allocated in files */
    802 	size_t fnlen, d_namelen;
    803 	size_t totlen;
    804 	int i;
    805 	static char *nullav;
    806 
    807 	ASSERT(fnstr != NULL);
    808 	fnlen = strlen(fnstr);
    809 
    810 	for (i = 0; dirname[i] != NULL; i++) {
    811 		out(O_DEBUG, "Looking for %s files in %s", fnstr, dirname[i]);
    812 		if ((dirp = opendir(dirname[i])) == NULL) {
    813 			out(O_DEBUG|O_SYS,
    814 			    "platform_get_files: opendir failed for %s",
    815 			    dirname[i]);
    816 			continue;
    817 		}
    818 		while ((dp = readdir(dirp)) != NULL) {
    819 			if ((fnlen == 1 && *fnstr == '*') ||
    820 			    ((d_namelen = strlen(dp->d_name)) >= fnlen &&
    821 			    strncmp(dp->d_name + d_namelen - fnlen,
    822 			    fnstr, fnlen) == 0)) {
    823 
    824 				if (nodups != 0) {
    825 					const char *snm = stable(dp->d_name);
    826 
    827 					if (lut_lookup(foundnames,
    828 					    (void *)snm,
    829 					    NULL) != NULL) {
    830 						out(O_DEBUG,
    831 						    "platform_get_files: "
    832 						    "skipping repeated name "
    833 						    "%s/%s",
    834 						    dirname[i],
    835 						    snm);
    836 						continue;
    837 					}
    838 					foundnames = lut_add(foundnames,
    839 					    (void *)snm,
    840 					    (void *)snm,
    841 					    NULL);
    842 				}
    843 
    844 				if (nfiles > slots - 2) {
    845 					/* allocate ten more slots */
    846 					slots += 10;
    847 					files = (char **)REALLOC(files,
    848 					    slots * sizeof (char *));
    849 				}
    850 				/* prepend directory name and / */
    851 				totlen = strlen(dirname[i]) + 1;
    852 				totlen += strlen(dp->d_name) + 1;
    853 				files[nfiles] = MALLOC(totlen);
    854 				out(O_DEBUG, "File %d: \"%s/%s\"", nfiles,
    855 				    dirname[i], dp->d_name);
    856 				(void) snprintf(files[nfiles++], totlen,
    857 				    "%s/%s", dirname[i], dp->d_name);
    858 			}
    859 		}
    860 		(void) closedir(dirp);
    861 	}
    862 
    863 	if (foundnames != NULL)
    864 		lut_free(foundnames, NULL, NULL);
    865 
    866 	if (nfiles == 0)
    867 		return (&nullav);
    868 
    869 	files[nfiles] = NULL;
    870 	return (files);
    871 }
    872 
    873 /*
    874  * search for files in a standard set of directories
    875  */
    876 static char **
    877 platform_get_files_stddirs(char *fname, int nodups)
    878 {
    879 	const char *dirlist[4];
    880 	char **flist;
    881 	char *eftgendir, *eftmachdir, *eftplatdir;
    882 
    883 	eftgendir = MALLOC(MAXPATHLEN);
    884 	eftmachdir = MALLOC(MAXPATHLEN);
    885 	eftplatdir = MALLOC(MAXPATHLEN);
    886 
    887 	/* Generic files that apply to any machine */
    888 	(void) snprintf(eftgendir, MAXPATHLEN, "%s/usr/lib/fm/eft", Root);
    889 
    890 	(void) snprintf(eftmachdir,
    891 	    MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Mach);
    892 
    893 	(void) snprintf(eftplatdir,
    894 	    MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Plat);
    895 
    896 	dirlist[0] = eftplatdir;
    897 	dirlist[1] = eftmachdir;
    898 	dirlist[2] = eftgendir;
    899 	dirlist[3] = NULL;
    900 
    901 	flist = platform_get_files(dirlist, fname, nodups);
    902 
    903 	FREE(eftplatdir);
    904 	FREE(eftmachdir);
    905 	FREE(eftgendir);
    906 
    907 	return (flist);
    908 }
    909 
    910 /*
    911  * platform_run_poller -- execute a poller
    912  *
    913  * when eft needs to know if a polled ereport exists this routine
    914  * is called so the poller code may be run in a platform-specific way.
    915  * there's no return value from this routine -- either the polled ereport
    916  * is generated (and delivered *before* this routine returns) or not.
    917  * any errors, like "poller unknown" are considered platform-specific
    918  * should be handled here rather than passing an error back up.
    919  */
    920 /*ARGSUSED*/
    921 void
    922 platform_run_poller(const char *poller)
    923 {
    924 }
    925 
    926 /*
    927  * fork and execve path with argument array argv and environment array
    928  * envp.  data from stdout and stderr are placed in outbuf and errbuf,
    929  * respectively.
    930  *
    931  * see execve(2) for more descriptions for path, argv and envp.
    932  */
    933 static int
    934 forkandexecve(const char *path, char *const argv[], char *const envp[],
    935 	char *outbuf, size_t outbuflen, char *errbuf, size_t errbuflen)
    936 {
    937 	pid_t pid;
    938 	int outpipe[2], errpipe[2];
    939 	int rt = 0;
    940 
    941 	/*
    942 	 * run the cmd and see if it failed.  this function is *not* a
    943 	 * generic command runner -- we depend on some knowledge we
    944 	 * have about the commands we run.  first of all, we expect
    945 	 * errors to spew something to stdout, and that something is
    946 	 * typically short enough to fit into a pipe so we can wait()
    947 	 * for the command to complete and then fetch the error text
    948 	 * from the pipe.
    949 	 */
    950 	if (pipe(outpipe) < 0)
    951 		if (strlcat(errbuf, ": pipe(outpipe) failed",
    952 		    errbuflen) >= errbuflen)
    953 			return (1);
    954 	if (pipe(errpipe) < 0)
    955 		if (strlcat(errbuf, ": pipe(errpipe) failed",
    956 		    errbuflen) >= errbuflen)
    957 			return (1);
    958 
    959 	if ((pid = fork()) < 0) {
    960 		rt = (int)strlcat(errbuf, ": fork() failed", errbuflen);
    961 	} else if (pid) {
    962 		int wstat, count;
    963 
    964 		/* parent */
    965 		(void) close(errpipe[1]);
    966 		(void) close(outpipe[1]);
    967 
    968 		/* PHASE2 need to guard against hang in child? */
    969 		if (waitpid(pid, &wstat, 0) < 0)
    970 			if (strlcat(errbuf, ": waitpid() failed",
    971 			    errbuflen) >= errbuflen)
    972 				return (1);
    973 
    974 		/* check for stderr contents */
    975 		if (ioctl(errpipe[0], FIONREAD, &count) >= 0 && count) {
    976 			if (read(errpipe[0], errbuf, errbuflen) <= 0) {
    977 				/*
    978 				 * read failed even though ioctl indicated
    979 				 * that nonzero bytes were available for
    980 				 * reading
    981 				 */
    982 				if (strlcat(errbuf, ": read(errpipe) failed",
    983 				    errbuflen) >= errbuflen)
    984 					return (1);
    985 			}
    986 			/*
    987 			 * handle case where errbuf is not properly
    988 			 * terminated
    989 			 */
    990 			if (count > errbuflen - 1)
    991 				count = errbuflen - 1;
    992 			if (errbuf[count - 1] != '\0' &&
    993 			    errbuf[count - 1] != '\n')
    994 				errbuf[count] = '\0';
    995 		} else if (WIFSIGNALED(wstat))
    996 			if (strlcat(errbuf, ": signaled",
    997 			    errbuflen) >= errbuflen)
    998 				return (1);
    999 		else if (WIFEXITED(wstat) && WEXITSTATUS(wstat))
   1000 			if (strlcat(errbuf, ": abnormal exit",
   1001 			    errbuflen) >= errbuflen)
   1002 				return (1);
   1003 
   1004 		/* check for stdout contents */
   1005 		if (ioctl(outpipe[0], FIONREAD, &count) >= 0 && count) {
   1006 			if (read(outpipe[0], outbuf, outbuflen) <= 0) {
   1007 				/*
   1008 				 * read failed even though ioctl indicated
   1009 				 * that nonzero bytes were available for
   1010 				 * reading
   1011 				 */
   1012 				if (strlcat(errbuf, ": read(outpipe) failed",
   1013 				    errbuflen) >= errbuflen)
   1014 					return (1);
   1015 			}
   1016 			/*
   1017 			 * handle case where outbuf is not properly
   1018 			 * terminated
   1019 			 */
   1020 			if (count > outbuflen - 1)
   1021 				count = outbuflen - 1;
   1022 			if (outbuf[count - 1] != '\0' &&
   1023 			    outbuf[count - 1] != '\n')
   1024 				outbuf[count] = '\0';
   1025 		}
   1026 
   1027 		(void) close(errpipe[0]);
   1028 		(void) close(outpipe[0]);
   1029 	} else {
   1030 		/* child */
   1031 		(void) dup2(errpipe[1], fileno(stderr));
   1032 		(void) close(errpipe[0]);
   1033 		(void) dup2(outpipe[1], fileno(stdout));
   1034 		(void) close(outpipe[0]);
   1035 
   1036 		if (execve(path, argv, envp))
   1037 			perror(path);
   1038 		_exit(1);
   1039 	}
   1040 
   1041 	return (rt);
   1042 }
   1043 
   1044 #define	MAXDIGITIDX	23
   1045 
   1046 static int
   1047 arglist2argv(struct node *np, struct lut **globals, struct config *croot,
   1048 	struct arrow *arrowp, char ***argv, int *argc, int *argvlen)
   1049 {
   1050 	struct node *namep;
   1051 	char numbuf[MAXDIGITIDX + 1];
   1052 	char *numstr, *nullbyte;
   1053 	char *addthisarg = NULL;
   1054 
   1055 	if (np == NULL)
   1056 		return (0);
   1057 
   1058 	switch (np->t) {
   1059 	case T_QUOTE:
   1060 		addthisarg = STRDUP(np->u.func.s);
   1061 		break;
   1062 	case T_LIST:
   1063 		if (arglist2argv(np->u.expr.left, globals, croot, arrowp,
   1064 		    argv, argc, argvlen))
   1065 			return (1);
   1066 		/*
   1067 		 * only leftmost element of a list can provide the command
   1068 		 * name (after which *argc becomes 1)
   1069 		 */
   1070 		ASSERT(*argc > 0);
   1071 		if (arglist2argv(np->u.expr.right, globals, croot, arrowp,
   1072 		    argv, argc, argvlen))
   1073 			return (1);
   1074 		break;
   1075 	case T_FUNC:
   1076 	case T_GLOBID:
   1077 	case T_ASSIGN:
   1078 	case T_CONDIF:
   1079 	case T_CONDELSE:
   1080 	case T_EQ:
   1081 	case T_NE:
   1082 	case T_LT:
   1083 	case T_LE:
   1084 	case T_GT:
   1085 	case T_GE:
   1086 	case T_BITAND:
   1087 	case T_BITOR:
   1088 	case T_BITXOR:
   1089 	case T_BITNOT:
   1090 	case T_LSHIFT:
   1091 	case T_RSHIFT:
   1092 	case T_AND:
   1093 	case T_OR:
   1094 	case T_NOT:
   1095 	case T_ADD:
   1096 	case T_SUB:
   1097 	case T_MUL:
   1098 	case T_DIV:
   1099 	case T_MOD: {
   1100 		struct evalue value;
   1101 
   1102 		if (!eval_expr(np, NULL, NULL, globals, croot, arrowp,
   1103 		    0, &value))
   1104 			return (1);
   1105 
   1106 		switch (value.t) {
   1107 		case UINT64:
   1108 			numbuf[MAXDIGITIDX] = '\0';
   1109 			nullbyte = &numbuf[MAXDIGITIDX];
   1110 			numstr = ulltostr(value.v, nullbyte);
   1111 			addthisarg = STRDUP(numstr);
   1112 			break;
   1113 		case STRING:
   1114 			addthisarg = STRDUP((const char *)(uintptr_t)value.v);
   1115 			break;
   1116 		case NODEPTR :
   1117 			namep = (struct node *)(uintptr_t)value.v;
   1118 			addthisarg = ipath2str(NULL, ipath(namep));
   1119 			break;
   1120 		default:
   1121 			out(O_ERR,
   1122 			    "call: arglist2argv: unexpected result from"
   1123 			    " operation %s",
   1124 			    ptree_nodetype2str(np->t));
   1125 			return (1);
   1126 		}
   1127 		break;
   1128 	}
   1129 	case T_NUM:
   1130 	case T_TIMEVAL:
   1131 		numbuf[MAXDIGITIDX] = '\0';
   1132 		nullbyte = &numbuf[MAXDIGITIDX];
   1133 		numstr = ulltostr(np->u.ull, nullbyte);
   1134 		addthisarg = STRDUP(numstr);
   1135 		break;
   1136 	case T_NAME:
   1137 		addthisarg = ipath2str(NULL, ipath(np));
   1138 		break;
   1139 	case T_EVENT:
   1140 		addthisarg = ipath2str(np->u.event.ename->u.name.s,
   1141 		    ipath(np->u.event.epname));
   1142 		break;
   1143 	default:
   1144 		out(O_ERR, "call: arglist2argv: node type %s is unsupported",
   1145 		    ptree_nodetype2str(np->t));
   1146 		return (1);
   1147 		/*NOTREACHED*/
   1148 		break;
   1149 	}
   1150 
   1151 	if (*argc == 0 && addthisarg != NULL) {
   1152 		/*
   1153 		 * first argument added is the command name.
   1154 		 */
   1155 		char **files;
   1156 
   1157 		files = platform_get_files_stddirs(addthisarg, 0);
   1158 
   1159 		/* do not proceed if number of files found != 1 */
   1160 		if (files[0] == NULL)
   1161 			out(O_DIE, "call: function %s not found", addthisarg);
   1162 		if (files[1] != NULL)
   1163 			out(O_DIE, "call: multiple functions %s found",
   1164 			    addthisarg);
   1165 		FREE(addthisarg);
   1166 
   1167 		addthisarg = STRDUP(files[0]);
   1168 		FREE(files[0]);
   1169 		FREE(files);
   1170 	}
   1171 
   1172 	if (addthisarg != NULL) {
   1173 		if (*argc >= *argvlen - 2) {
   1174 			/*
   1175 			 * make sure argv is long enough so it has a
   1176 			 * terminating element set to NULL
   1177 			 */
   1178 			*argvlen += 10;
   1179 			*argv = (char **)REALLOC(*argv,
   1180 			    sizeof (char *) * *argvlen);
   1181 		}
   1182 		(*argv)[*argc] = addthisarg;
   1183 		(*argc)++;
   1184 		(*argv)[*argc] = NULL;
   1185 	}
   1186 
   1187 	return (0);
   1188 }
   1189 
   1190 static int
   1191 generate_envp(struct arrow *arrowp, char ***envp, int *envc, int *envplen)
   1192 {
   1193 	char *envnames[] = { "EFT_FROM_EVENT", "EFT_TO_EVENT",
   1194 			    "EFT_FILE", "EFT_LINE", NULL };
   1195 	char *envvalues[4];
   1196 	char *none = "(none)";
   1197 	size_t elen;
   1198 	int i;
   1199 
   1200 	*envc = 4;
   1201 
   1202 	/*
   1203 	 * make sure envp is long enough so it has a terminating element
   1204 	 * set to NULL
   1205 	 */
   1206 	*envplen = *envc + 1;
   1207 	*envp = (char **)MALLOC(sizeof (char *) * *envplen);
   1208 
   1209 	envvalues[0] = ipath2str(
   1210 	    arrowp->tail->myevent->enode->u.event.ename->u.name.s,
   1211 	    arrowp->tail->myevent->ipp);
   1212 	envvalues[1] = ipath2str(
   1213 	    arrowp->head->myevent->enode->u.event.ename->u.name.s,
   1214 	    arrowp->head->myevent->ipp);
   1215 
   1216 	if (arrowp->head->myevent->enode->file == NULL) {
   1217 		envvalues[2] = STRDUP(none);
   1218 		envvalues[3] = STRDUP(none);
   1219 	} else {
   1220 		envvalues[2] = STRDUP(arrowp->head->myevent->enode->file);
   1221 
   1222 		/* large enough for max int */
   1223 		envvalues[3] = MALLOC(sizeof (char) * 25);
   1224 		(void) snprintf(envvalues[3], sizeof (envvalues[3]), "%d",
   1225 		    arrowp->head->myevent->enode->line);
   1226 	}
   1227 
   1228 	for (i = 0; envnames[i] != NULL && i < *envc; i++) {
   1229 		elen = strlen(envnames[i]) + strlen(envvalues[i]) + 2;
   1230 		(*envp)[i] = MALLOC(elen);
   1231 		(void) snprintf((*envp)[i], elen, "%s=%s",
   1232 		    envnames[i], envvalues[i]);
   1233 		FREE(envvalues[i]);
   1234 	}
   1235 	(*envp)[*envc] = NULL;
   1236 
   1237 	return (0);
   1238 }
   1239 
   1240 /*
   1241  * platform_call -- call an external function
   1242  *
   1243  * evaluate a user-defined function and place result in valuep.  return 0
   1244  * if function evaluation was successful; 1 if otherwise.
   1245  */
   1246 int
   1247 platform_call(struct node *np, struct lut **globals, struct config *croot,
   1248 	struct arrow *arrowp, struct evalue *valuep)
   1249 {
   1250 	/*
   1251 	 * use rather short buffers.  only the first string on outbuf[] is
   1252 	 * taken as output from the called function.  any message in
   1253 	 * errbuf[] is echoed out as an error message.
   1254 	 */
   1255 	char outbuf[256], errbuf[512];
   1256 	struct stat buf;
   1257 	char **argv, **envp;
   1258 	int argc, argvlen, envc, envplen;
   1259 	int i, ret;
   1260 
   1261 	/*
   1262 	 * np is the argument list.  the user-defined function is the first
   1263 	 * element of the list.
   1264 	 */
   1265 	ASSERT(np->t == T_LIST);
   1266 
   1267 	argv = NULL;
   1268 	argc = 0;
   1269 	argvlen = 0;
   1270 	if (arglist2argv(np, globals, croot, arrowp, &argv, &argc, &argvlen) ||
   1271 	    argc == 0)
   1272 		return (1);
   1273 
   1274 	/*
   1275 	 * make sure program has executable bit set
   1276 	 */
   1277 	if (stat(argv[0], &buf) == 0) {
   1278 		int exec_bit_set = 0;
   1279 
   1280 		if (buf.st_uid == geteuid() && buf.st_mode & S_IXUSR)
   1281 			exec_bit_set = 1;
   1282 		else if (buf.st_gid == getegid() && buf.st_mode & S_IXGRP)
   1283 			exec_bit_set = 1;
   1284 		else if (buf.st_mode & S_IXOTH)
   1285 			exec_bit_set = 1;
   1286 
   1287 		if (exec_bit_set == 0)
   1288 			out(O_DIE, "call: executable bit not set on %s",
   1289 			    argv[0]);
   1290 	} else {
   1291 		out(O_DIE, "call: failure in stat(), errno = %d\n", errno);
   1292 	}
   1293 
   1294 	envp = NULL;
   1295 	envc = 0;
   1296 	envplen = 0;
   1297 	if (generate_envp(arrowp, &envp, &envc, &envplen))
   1298 		return (1);
   1299 
   1300 	outbuf[0] = '\0';
   1301 	errbuf[0] = '\0';
   1302 
   1303 	ret = forkandexecve((const char *) argv[0], (char *const *) argv,
   1304 	    (char *const *) envp, outbuf, sizeof (outbuf),
   1305 	    errbuf, sizeof (errbuf));
   1306 
   1307 	for (i = 0; i < envc; i++)
   1308 		FREE(envp[i]);
   1309 	if (envp)
   1310 		FREE(envp);
   1311 
   1312 	if (ret) {
   1313 		outfl(O_OK, np->file, np->line,
   1314 		    "call: failure in fork + exec of %s", argv[0]);
   1315 	} else {
   1316 		char *ptr;
   1317 
   1318 		/* chomp the result */
   1319 		for (ptr = outbuf; *ptr; ptr++)
   1320 			if (*ptr == '\n' || *ptr == '\r') {
   1321 				*ptr = '\0';
   1322 				break;
   1323 			}
   1324 		valuep->t = STRING;
   1325 		valuep->v = (uintptr_t)stable(outbuf);
   1326 	}
   1327 
   1328 	if (errbuf[0] != '\0') {
   1329 		ret = 1;
   1330 		outfl(O_OK, np->file, np->line,
   1331 		    "call: unexpected stderr output from %s: %s",
   1332 		    argv[0], errbuf);
   1333 	}
   1334 
   1335 	for (i = 0; i < argc; i++)
   1336 		FREE(argv[i]);
   1337 	FREE(argv);
   1338 
   1339 	return (ret);
   1340 }
   1341 
   1342 /*
   1343  * platform_confcall -- call a configuration database function
   1344  *
   1345  * returns result in *valuep, return 0 on success
   1346  */
   1347 /*ARGSUSED*/
   1348 int
   1349 platform_confcall(struct node *np, struct lut **globals, struct config *croot,
   1350 	struct arrow *arrowp, struct evalue *valuep)
   1351 {
   1352 	outfl(O_ALTFP|O_VERB, np->file, np->line, "unknown confcall");
   1353 	return (0);
   1354 }
   1355 
   1356 /*
   1357  * platform_get_eft_files -- return names of all eft files we should load
   1358  *
   1359  * this routine doesn't return NULL, even if no files are found (in that
   1360  * case, a char ** is returned with the first element NULL).
   1361  */
   1362 char **
   1363 platform_get_eft_files(void)
   1364 {
   1365 	return (platform_get_files_stddirs(".eft", 1));
   1366 }
   1367 
   1368 void
   1369 platform_free_eft_files(char **flist)
   1370 {
   1371 	char **f;
   1372 
   1373 	if (flist == NULL || *flist == NULL)
   1374 		return;	/* no files were found so we're done */
   1375 
   1376 	f = flist;
   1377 	while (*f != NULL) {
   1378 		FREE(*f);
   1379 		f++;
   1380 	}
   1381 	FREE(flist);
   1382 }
   1383 
   1384 static nvlist_t *payloadnvp = NULL;
   1385 
   1386 void
   1387 platform_set_payloadnvp(nvlist_t *nvlp)
   1388 {
   1389 	/*
   1390 	 * cannot replace a non-NULL payloadnvp with a non-NULL nvlp
   1391 	 */
   1392 	ASSERT(payloadnvp != NULL ? nvlp == NULL : 1);
   1393 	payloadnvp = nvlp;
   1394 }
   1395 
   1396 /*
   1397  * given array notation in inputstr such as "foo[1]" or "foo [ 1 ]" (spaces
   1398  * allowed), figure out the array name and index.  return 0 if successful,
   1399  * nonzero if otherwise.
   1400  */
   1401 static int
   1402 get_array_info(const char *inputstr, const char **name, unsigned int *index)
   1403 {
   1404 	char *indexptr, *indexend, *dupname, *endname;
   1405 
   1406 	if (strchr(inputstr, '[') == NULL)
   1407 		return (1);
   1408 
   1409 	dupname = STRDUP(inputstr);
   1410 	indexptr = strchr(dupname, '[');
   1411 	indexend = strchr(dupname, ']');
   1412 
   1413 	/*
   1414 	 * return if array notation is not complete or if index is negative
   1415 	 */
   1416 	if (indexend == NULL || indexptr >= indexend ||
   1417 	    strchr(indexptr, '-') != NULL) {
   1418 		FREE(dupname);
   1419 		return (1);
   1420 	}
   1421 
   1422 	/*
   1423 	 * search past any spaces between the name string and '['
   1424 	 */
   1425 	endname = indexptr;
   1426 	while (isspace(*(endname - 1)) && dupname < endname)
   1427 		endname--;
   1428 	*endname = '\0';
   1429 	ASSERT(dupname < endname);
   1430 
   1431 	/*
   1432 	 * search until indexptr points to the first digit and indexend
   1433 	 * points to the last digit
   1434 	 */
   1435 	while (!isdigit(*indexptr) && indexptr < indexend)
   1436 		indexptr++;
   1437 	while (!isdigit(*indexend) && indexptr <= indexend)
   1438 		indexend--;
   1439 
   1440 	*(indexend + 1) = '\0';
   1441 	*index = (unsigned int)atoi(indexptr);
   1442 
   1443 	*name = stable(dupname);
   1444 	FREE(dupname);
   1445 
   1446 	return (0);
   1447 }
   1448 
   1449 /*
   1450  * platform_payloadprop -- fetch a payload value
   1451  *
   1452  * XXX this function should be replaced and eval_func() should be
   1453  * XXX changed to use the more general platform_payloadprop_values().
   1454  */
   1455 int
   1456 platform_payloadprop(struct node *np, struct evalue *valuep)
   1457 {
   1458 	nvlist_t *basenvp;
   1459 	nvlist_t *embnvp = NULL;
   1460 	nvpair_t *nvpair;
   1461 	const char *nameptr, *propstr, *lastnameptr;
   1462 	int not_array = 0;
   1463 	unsigned int index = 0;
   1464 	uint_t nelem;
   1465 	char *nvpname, *nameslist = NULL;
   1466 	char *scheme = NULL;
   1467 
   1468 	ASSERT(np->t == T_QUOTE);
   1469 
   1470 	propstr = np->u.quote.s;
   1471 	if (payloadnvp == NULL) {
   1472 		out(O_ALTFP | O_VERB2, "platform_payloadprop: no nvp for %s",
   1473 		    propstr);
   1474 		return (1);
   1475 	}
   1476 	basenvp = payloadnvp;
   1477 
   1478 	/*
   1479 	 * first handle any embedded nvlists.  if propstr is "foo.bar[2]"
   1480 	 * then lastnameptr should end up being "bar[2]" with basenvp set
   1481 	 * to the nvlist for "foo".  (the search for "bar" within "foo"
   1482 	 * will be done later.)
   1483 	 */
   1484 	if (strchr(propstr, '.') != NULL) {
   1485 		nvlist_t **arraynvp;
   1486 		uint_t nelem;
   1487 		char *w;
   1488 		int ier;
   1489 
   1490 		nameslist = STRDUP(propstr);
   1491 		lastnameptr = strtok(nameslist, ".");
   1492 
   1493 		/*
   1494 		 * decompose nameslist into its component names while
   1495 		 * extracting the embedded nvlist
   1496 		 */
   1497 		while ((w = strtok(NULL, ".")) != NULL) {
   1498 			if (get_array_info(lastnameptr, &nameptr, &index)) {
   1499 				ier = nvlist_lookup_nvlist(basenvp,
   1500 				    lastnameptr, &basenvp);
   1501 			} else {
   1502 				/* handle array of nvlists */
   1503 				ier = nvlist_lookup_nvlist_array(basenvp,
   1504 				    nameptr, &arraynvp, &nelem);
   1505 				if (ier == 0) {
   1506 					if ((uint_t)index > nelem - 1)
   1507 						ier = 1;
   1508 					else
   1509 						basenvp = arraynvp[index];
   1510 				}
   1511 			}
   1512 
   1513 			if (ier) {
   1514 				out(O_ALTFP, "platform_payloadprop: "
   1515 				    " invalid list for %s (in %s)",
   1516 				    lastnameptr, propstr);
   1517 				FREE(nameslist);
   1518 				return (1);
   1519 			}
   1520 
   1521 			lastnameptr = w;
   1522 		}
   1523 	} else {
   1524 		lastnameptr = propstr;
   1525 	}
   1526 
   1527 	/* if property is an array reference, extract array name and index */
   1528 	not_array = get_array_info(lastnameptr, &nameptr, &index);
   1529 	if (not_array)
   1530 		nameptr = stable(lastnameptr);
   1531 
   1532 	if (nameslist != NULL)
   1533 		FREE(nameslist);
   1534 
   1535 	/* search for nvpair entry */
   1536 	nvpair = NULL;
   1537 	while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
   1538 		nvpname = nvpair_name(nvpair);
   1539 		ASSERT(nvpname != NULL);
   1540 
   1541 		if (nameptr == stable(nvpname))
   1542 			break;
   1543 	}
   1544 
   1545 	if (nvpair == NULL) {
   1546 		out(O_ALTFP, "platform_payloadprop: no entry for %s", propstr);
   1547 		return (1);
   1548 	} else if (valuep == NULL) {
   1549 		/*
   1550 		 * caller is interested in the existence of a property with
   1551 		 * this name, regardless of type or value
   1552 		 */
   1553 		return (0);
   1554 	}
   1555 
   1556 	valuep->t = UNDEFINED;
   1557 
   1558 	/*
   1559 	 * get to this point if we found an entry.  figure out its data
   1560 	 * type and copy its value.
   1561 	 */
   1562 	(void) nvpair_value_nvlist(nvpair, &embnvp);
   1563 	if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME, &scheme) == 0) {
   1564 		if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
   1565 			valuep->t = NODEPTR;
   1566 			valuep->v = (uintptr_t)hc_fmri_nodeize(embnvp);
   1567 			return (0);
   1568 		}
   1569 	}
   1570 	switch (nvpair_type(nvpair)) {
   1571 	case DATA_TYPE_BOOLEAN:
   1572 	case DATA_TYPE_BOOLEAN_VALUE: {
   1573 		boolean_t val;
   1574 		(void) nvpair_value_boolean_value(nvpair, &val);
   1575 		valuep->t = UINT64;
   1576 		valuep->v = (unsigned long long)val;
   1577 		break;
   1578 	}
   1579 	case DATA_TYPE_BYTE: {
   1580 		uchar_t val;
   1581 		(void) nvpair_value_byte(nvpair, &val);
   1582 		valuep->t = UINT64;
   1583 		valuep->v = (unsigned long long)val;
   1584 		break;
   1585 	}
   1586 	case DATA_TYPE_STRING: {
   1587 		char *val;
   1588 		valuep->t = STRING;
   1589 		(void) nvpair_value_string(nvpair, &val);
   1590 		valuep->v = (uintptr_t)stable(val);
   1591 		break;
   1592 	}
   1593 
   1594 	case DATA_TYPE_INT8: {
   1595 		int8_t val;
   1596 		(void) nvpair_value_int8(nvpair, &val);
   1597 		valuep->t = UINT64;
   1598 		valuep->v = (unsigned long long)val;
   1599 		break;
   1600 	}
   1601 	case DATA_TYPE_UINT8: {
   1602 		uint8_t val;
   1603 		(void) nvpair_value_uint8(nvpair, &val);
   1604 		valuep->t = UINT64;
   1605 		valuep->v = (unsigned long long)val;
   1606 		break;
   1607 	}
   1608 
   1609 	case DATA_TYPE_INT16: {
   1610 		int16_t val;
   1611 		(void) nvpair_value_int16(nvpair, &val);
   1612 		valuep->t = UINT64;
   1613 		valuep->v = (unsigned long long)val;
   1614 		break;
   1615 	}
   1616 	case DATA_TYPE_UINT16: {
   1617 		uint16_t val;
   1618 		(void) nvpair_value_uint16(nvpair, &val);
   1619 		valuep->t = UINT64;
   1620 		valuep->v = (unsigned long long)val;
   1621 		break;
   1622 	}
   1623 
   1624 	case DATA_TYPE_INT32: {
   1625 		int32_t val;
   1626 		(void) nvpair_value_int32(nvpair, &val);
   1627 		valuep->t = UINT64;
   1628 		valuep->v = (unsigned long long)val;
   1629 		break;
   1630 	}
   1631 	case DATA_TYPE_UINT32: {
   1632 		uint32_t val;
   1633 		(void) nvpair_value_uint32(nvpair, &val);
   1634 		valuep->t = UINT64;
   1635 		valuep->v = (unsigned long long)val;
   1636 		break;
   1637 	}
   1638 
   1639 	case DATA_TYPE_INT64: {
   1640 		int64_t val;
   1641 		(void) nvpair_value_int64(nvpair, &val);
   1642 		valuep->t = UINT64;
   1643 		valuep->v = (unsigned long long)val;
   1644 		break;
   1645 	}
   1646 	case DATA_TYPE_UINT64: {
   1647 		uint64_t val;
   1648 		(void) nvpair_value_uint64(nvpair, &val);
   1649 		valuep->t = UINT64;
   1650 		valuep->v = (unsigned long long)val;
   1651 		break;
   1652 	}
   1653 
   1654 	case DATA_TYPE_BOOLEAN_ARRAY: {
   1655 		boolean_t *val;
   1656 		(void) nvpair_value_boolean_array(nvpair, &val, &nelem);
   1657 		if (not_array == 1 || index >= nelem)
   1658 			goto invalid;
   1659 		valuep->t = UINT64;
   1660 		valuep->v = (unsigned long long)val[index];
   1661 		break;
   1662 	}
   1663 	case DATA_TYPE_BYTE_ARRAY: {
   1664 		uchar_t *val;
   1665 		(void) nvpair_value_byte_array(nvpair, &val, &nelem);
   1666 		if (not_array == 1 || index >= nelem)
   1667 			goto invalid;
   1668 		valuep->t = UINT64;
   1669 		valuep->v = (unsigned long long)val[index];
   1670 		break;
   1671 	}
   1672 	case DATA_TYPE_STRING_ARRAY: {
   1673 		char **val;
   1674 		(void) nvpair_value_string_array(nvpair, &val, &nelem);
   1675 		if (not_array == 1 || index >= nelem)
   1676 			goto invalid;
   1677 		valuep->t = STRING;
   1678 		valuep->v = (uintptr_t)stable(val[index]);
   1679 		break;
   1680 	}
   1681 
   1682 	case DATA_TYPE_INT8_ARRAY: {
   1683 		int8_t *val;
   1684 		(void) nvpair_value_int8_array(nvpair, &val, &nelem);
   1685 		if (not_array == 1 || index >= nelem)
   1686 			goto invalid;
   1687 		valuep->t = UINT64;
   1688 		valuep->v = (unsigned long long)val[index];
   1689 		break;
   1690 	}
   1691 	case DATA_TYPE_UINT8_ARRAY: {
   1692 		uint8_t *val;
   1693 		(void) nvpair_value_uint8_array(nvpair, &val, &nelem);
   1694 		if (not_array == 1 || index >= nelem)
   1695 			goto invalid;
   1696 		valuep->t = UINT64;
   1697 		valuep->v = (unsigned long long)val[index];
   1698 		break;
   1699 	}
   1700 	case DATA_TYPE_INT16_ARRAY: {
   1701 		int16_t *val;
   1702 		(void) nvpair_value_int16_array(nvpair, &val, &nelem);
   1703 		if (not_array == 1 || index >= nelem)
   1704 			goto invalid;
   1705 		valuep->t = UINT64;
   1706 		valuep->v = (unsigned long long)val[index];
   1707 		break;
   1708 	}
   1709 	case DATA_TYPE_UINT16_ARRAY: {
   1710 		uint16_t *val;
   1711 		(void) nvpair_value_uint16_array(nvpair, &val, &nelem);
   1712 		if (not_array == 1 || index >= nelem)
   1713 			goto invalid;
   1714 		valuep->t = UINT64;
   1715 		valuep->v = (unsigned long long)val[index];
   1716 		break;
   1717 	}
   1718 	case DATA_TYPE_INT32_ARRAY: {
   1719 		int32_t *val;
   1720 		(void) nvpair_value_int32_array(nvpair, &val, &nelem);
   1721 		if (not_array == 1 || index >= nelem)
   1722 			goto invalid;
   1723 		valuep->t = UINT64;
   1724 		valuep->v = (unsigned long long)val[index];
   1725 		break;
   1726 	}
   1727 	case DATA_TYPE_UINT32_ARRAY: {
   1728 		uint32_t *val;
   1729 		(void) nvpair_value_uint32_array(nvpair, &val, &nelem);
   1730 		if (not_array == 1 || index >= nelem)
   1731 			goto invalid;
   1732 		valuep->t = UINT64;
   1733 		valuep->v = (unsigned long long)val[index];
   1734 		break;
   1735 	}
   1736 	case DATA_TYPE_INT64_ARRAY: {
   1737 		int64_t *val;
   1738 		(void) nvpair_value_int64_array(nvpair, &val, &nelem);
   1739 		if (not_array == 1 || index >= nelem)
   1740 			goto invalid;
   1741 		valuep->t = UINT64;
   1742 		valuep->v = (unsigned long long)val[index];
   1743 		break;
   1744 	}
   1745 	case DATA_TYPE_UINT64_ARRAY: {
   1746 		uint64_t *val;
   1747 		(void) nvpair_value_uint64_array(nvpair, &val, &nelem);
   1748 		if (not_array == 1 || index >= nelem)
   1749 			goto invalid;
   1750 		valuep->t = UINT64;
   1751 		valuep->v = (unsigned long long)val[index];
   1752 		break;
   1753 	}
   1754 
   1755 	default :
   1756 		out(O_ALTFP|O_VERB2,
   1757 		    "platform_payloadprop: unsupported data type for %s",
   1758 		    propstr);
   1759 		return (1);
   1760 	}
   1761 
   1762 	return (0);
   1763 
   1764 invalid:
   1765 	out(O_ALTFP|O_VERB2,
   1766 	    "platform_payloadprop: invalid array reference for %s", propstr);
   1767 	return (1);
   1768 }
   1769 
   1770 /*ARGSUSED*/
   1771 int
   1772 platform_path_exists(nvlist_t *fmri)
   1773 {
   1774 	return (fmd_nvl_fmri_present(Hdl, fmri));
   1775 }
   1776 
   1777 struct evalue *
   1778 platform_payloadprop_values(const char *propstr, int *nvals)
   1779 {
   1780 	struct evalue *retvals;
   1781 	nvlist_t *basenvp;
   1782 	nvpair_t *nvpair;
   1783 	char *nvpname;
   1784 
   1785 	*nvals = 0;
   1786 
   1787 	if (payloadnvp == NULL)
   1788 		return (NULL);
   1789 
   1790 	basenvp = payloadnvp;
   1791 
   1792 	/* search for nvpair entry */
   1793 	nvpair = NULL;
   1794 	while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
   1795 		nvpname = nvpair_name(nvpair);
   1796 		ASSERT(nvpname != NULL);
   1797 
   1798 		if (strcmp(propstr, nvpname) == 0)
   1799 			break;
   1800 	}
   1801 
   1802 	if (nvpair == NULL)
   1803 		return (NULL);	/* property not found */
   1804 
   1805 	switch (nvpair_type(nvpair)) {
   1806 	case DATA_TYPE_NVLIST: {
   1807 		nvlist_t *embnvp = NULL;
   1808 		char *scheme = NULL;
   1809 
   1810 		(void) nvpair_value_nvlist(nvpair, &embnvp);
   1811 		if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME,
   1812 		    &scheme) == 0) {
   1813 			if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
   1814 				*nvals = 1;
   1815 				retvals = MALLOC(sizeof (struct evalue));
   1816 				retvals->t = NODEPTR;
   1817 				retvals->v =
   1818 				    (uintptr_t)hc_fmri_nodeize(embnvp);
   1819 				return (retvals);
   1820 			}
   1821 		}
   1822 		return (NULL);
   1823 	}
   1824 	case DATA_TYPE_NVLIST_ARRAY: {
   1825 		char *scheme = NULL;
   1826 		nvlist_t **nvap;
   1827 		uint_t nel;
   1828 		int i;
   1829 		int hccount;
   1830 
   1831 		/*
   1832 		 * since we're only willing to handle hc fmri's, we
   1833 		 * must count them first before allocating retvals.
   1834 		 */
   1835 		if (nvpair_value_nvlist_array(nvpair, &nvap, &nel) != 0)
   1836 			return (NULL);
   1837 
   1838 		hccount = 0;
   1839 		for (i = 0; i < nel; i++) {
   1840 			if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
   1841 			    &scheme) == 0 &&
   1842 			    strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
   1843 				hccount++;
   1844 			}
   1845 		}
   1846 
   1847 		if (hccount == 0)
   1848 			return (NULL);
   1849 
   1850 		*nvals = hccount;
   1851 		retvals = MALLOC(sizeof (struct evalue) * hccount);
   1852 
   1853 		hccount = 0;
   1854 		for (i = 0; i < nel; i++) {
   1855 			if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
   1856 			    &scheme) == 0 &&
   1857 			    strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
   1858 				retvals[hccount].t = NODEPTR;
   1859 				retvals[hccount].v = (uintptr_t)
   1860 				    hc_fmri_nodeize(nvap[i]);
   1861 				hccount++;
   1862 			}
   1863 		}
   1864 		return (retvals);
   1865 	}
   1866 	case DATA_TYPE_BOOLEAN:
   1867 	case DATA_TYPE_BOOLEAN_VALUE: {
   1868 		boolean_t val;
   1869 
   1870 		*nvals = 1;
   1871 		retvals = MALLOC(sizeof (struct evalue));
   1872 		(void) nvpair_value_boolean_value(nvpair, &val);
   1873 		retvals->t = UINT64;
   1874 		retvals->v = (unsigned long long)val;
   1875 		return (retvals);
   1876 	}
   1877 	case DATA_TYPE_BYTE: {
   1878 		uchar_t val;
   1879 
   1880 		*nvals = 1;
   1881 		retvals = MALLOC(sizeof (struct evalue));
   1882 		(void) nvpair_value_byte(nvpair, &val);
   1883 		retvals->t = UINT64;
   1884 		retvals->v = (unsigned long long)val;
   1885 		return (retvals);
   1886 	}
   1887 	case DATA_TYPE_STRING: {
   1888 		char *val;
   1889 
   1890 		*nvals = 1;
   1891 		retvals = MALLOC(sizeof (struct evalue));
   1892 		retvals->t = STRING;
   1893 		(void) nvpair_value_string(nvpair, &val);
   1894 		retvals->v = (uintptr_t)stable(val);
   1895 		return (retvals);
   1896 	}
   1897 
   1898 	case DATA_TYPE_INT8: {
   1899 		int8_t val;
   1900 
   1901 		*nvals = 1;
   1902 		retvals = MALLOC(sizeof (struct evalue));
   1903 		(void) nvpair_value_int8(nvpair, &val);
   1904 		retvals->t = UINT64;
   1905 		retvals->v = (unsigned long long)val;
   1906 		return (retvals);
   1907 	}
   1908 	case DATA_TYPE_UINT8: {
   1909 		uint8_t val;
   1910 
   1911 		*nvals = 1;
   1912 		retvals = MALLOC(sizeof (struct evalue));
   1913 		(void) nvpair_value_uint8(nvpair, &val);
   1914 		retvals->t = UINT64;
   1915 		retvals->v = (unsigned long long)val;
   1916 		return (retvals);
   1917 	}
   1918 
   1919 	case DATA_TYPE_INT16: {
   1920 		int16_t val;
   1921 
   1922 		*nvals = 1;
   1923 		retvals = MALLOC(sizeof (struct evalue));
   1924 		(void) nvpair_value_int16(nvpair, &val);
   1925 		retvals->t = UINT64;
   1926 		retvals->v = (unsigned long long)val;
   1927 		return (retvals);
   1928 	}
   1929 	case DATA_TYPE_UINT16: {
   1930 		uint16_t val;
   1931 
   1932 		*nvals = 1;
   1933 		retvals = MALLOC(sizeof (struct evalue));
   1934 		(void) nvpair_value_uint16(nvpair, &val);
   1935 		retvals->t = UINT64;
   1936 		retvals->v = (unsigned long long)val;
   1937 		return (retvals);
   1938 	}
   1939 
   1940 	case DATA_TYPE_INT32: {
   1941 		int32_t val;
   1942 
   1943 		*nvals = 1;
   1944 		retvals = MALLOC(sizeof (struct evalue));
   1945 		(void) nvpair_value_int32(nvpair, &val);
   1946 		retvals->t = UINT64;
   1947 		retvals->v = (unsigned long long)val;
   1948 		return (retvals);
   1949 	}
   1950 	case DATA_TYPE_UINT32: {
   1951 		uint32_t val;
   1952 
   1953 		*nvals = 1;
   1954 		retvals = MALLOC(sizeof (struct evalue));
   1955 		(void) nvpair_value_uint32(nvpair, &val);
   1956 		retvals->t = UINT64;
   1957 		retvals->v = (unsigned long long)val;
   1958 		return (retvals);
   1959 	}
   1960 
   1961 	case DATA_TYPE_INT64: {
   1962 		int64_t val;
   1963 
   1964 		*nvals = 1;
   1965 		retvals = MALLOC(sizeof (struct evalue));
   1966 		(void) nvpair_value_int64(nvpair, &val);
   1967 		retvals->t = UINT64;
   1968 		retvals->v = (unsigned long long)val;
   1969 		return (retvals);
   1970 	}
   1971 	case DATA_TYPE_UINT64: {
   1972 		uint64_t val;
   1973 
   1974 		*nvals = 1;
   1975 		retvals = MALLOC(sizeof (struct evalue));
   1976 		(void) nvpair_value_uint64(nvpair, &val);
   1977 		retvals->t = UINT64;
   1978 		retvals->v = (unsigned long long)val;
   1979 		return (retvals);
   1980 	}
   1981 
   1982 	case DATA_TYPE_BOOLEAN_ARRAY: {
   1983 		boolean_t *val;
   1984 		uint_t nel;
   1985 		int i;
   1986 
   1987 		(void) nvpair_value_boolean_array(nvpair, &val, &nel);
   1988 		*nvals = nel;
   1989 		retvals = MALLOC(sizeof (struct evalue) * nel);
   1990 		for (i = 0; i < nel; i++) {
   1991 			retvals[i].t = UINT64;
   1992 			retvals[i].v = (unsigned long long)val[i];
   1993 		}
   1994 		return (retvals);
   1995 	}
   1996 	case DATA_TYPE_BYTE_ARRAY: {
   1997 		uchar_t *val;
   1998 		uint_t nel;
   1999 		int i;
   2000 
   2001 		(void) nvpair_value_byte_array(nvpair, &val, &nel);
   2002 		*nvals = nel;
   2003 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2004 		for (i = 0; i < nel; i++) {
   2005 			retvals[i].t = UINT64;
   2006 			retvals[i].v = (unsigned long long)val[i];
   2007 		}
   2008 		return (retvals);
   2009 	}
   2010 	case DATA_TYPE_STRING_ARRAY: {
   2011 		char **val;
   2012 		uint_t nel;
   2013 		int i;
   2014 
   2015 		(void) nvpair_value_string_array(nvpair, &val, &nel);
   2016 		*nvals = nel;
   2017 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2018 		for (i = 0; i < nel; i++) {
   2019 			retvals[i].t = STRING;
   2020 			retvals[i].v = (uintptr_t)stable(val[i]);
   2021 		}
   2022 		return (retvals);
   2023 	}
   2024 
   2025 	case DATA_TYPE_INT8_ARRAY: {
   2026 		int8_t *val;
   2027 		uint_t nel;
   2028 		int i;
   2029 
   2030 		(void) nvpair_value_int8_array(nvpair, &val, &nel);
   2031 		*nvals = nel;
   2032 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2033 		for (i = 0; i < nel; i++) {
   2034 			retvals[i].t = UINT64;
   2035 			retvals[i].v = (unsigned long long)val[i];
   2036 		}
   2037 		return (retvals);
   2038 	}
   2039 	case DATA_TYPE_UINT8_ARRAY: {
   2040 		uint8_t *val;
   2041 		uint_t nel;
   2042 		int i;
   2043 
   2044 		(void) nvpair_value_uint8_array(nvpair, &val, &nel);
   2045 		*nvals = nel;
   2046 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2047 		for (i = 0; i < nel; i++) {
   2048 			retvals[i].t = UINT64;
   2049 			retvals[i].v = (unsigned long long)val[i];
   2050 		}
   2051 		return (retvals);
   2052 	}
   2053 	case DATA_TYPE_INT16_ARRAY: {
   2054 		int16_t *val;
   2055 		uint_t nel;
   2056 		int i;
   2057 
   2058 		(void) nvpair_value_int16_array(nvpair, &val, &nel);
   2059 		*nvals = nel;
   2060 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2061 		for (i = 0; i < nel; i++) {
   2062 			retvals[i].t = UINT64;
   2063 			retvals[i].v = (unsigned long long)val[i];
   2064 		}
   2065 		return (retvals);
   2066 	}
   2067 	case DATA_TYPE_UINT16_ARRAY: {
   2068 		uint16_t *val;
   2069 		uint_t nel;
   2070 		int i;
   2071 
   2072 		(void) nvpair_value_uint16_array(nvpair, &val, &nel);
   2073 		*nvals = nel;
   2074 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2075 		for (i = 0; i < nel; i++) {
   2076 			retvals[i].t = UINT64;
   2077 			retvals[i].v = (unsigned long long)val[i];
   2078 		}
   2079 		return (retvals);
   2080 	}
   2081 	case DATA_TYPE_INT32_ARRAY: {
   2082 		int32_t *val;
   2083 		uint_t nel;
   2084 		int i;
   2085 
   2086 		(void) nvpair_value_int32_array(nvpair, &val, &nel);
   2087 		*nvals = nel;
   2088 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2089 		for (i = 0; i < nel; i++) {
   2090 			retvals[i].t = UINT64;
   2091 			retvals[i].v = (unsigned long long)val[i];
   2092 		}
   2093 		return (retvals);
   2094 	}
   2095 	case DATA_TYPE_UINT32_ARRAY: {
   2096 		uint32_t *val;
   2097 		uint_t nel;
   2098 		int i;
   2099 
   2100 		(void) nvpair_value_uint32_array(nvpair, &val, &nel);
   2101 		*nvals = nel;
   2102 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2103 		for (i = 0; i < nel; i++) {
   2104 			retvals[i].t = UINT64;
   2105 			retvals[i].v = (unsigned long long)val[i];
   2106 		}
   2107 		return (retvals);
   2108 	}
   2109 	case DATA_TYPE_INT64_ARRAY: {
   2110 		int64_t *val;
   2111 		uint_t nel;
   2112 		int i;
   2113 
   2114 		(void) nvpair_value_int64_array(nvpair, &val, &nel);
   2115 		*nvals = nel;
   2116 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2117 		for (i = 0; i < nel; i++) {
   2118 			retvals[i].t = UINT64;
   2119 			retvals[i].v = (unsigned long long)val[i];
   2120 		}
   2121 		return (retvals);
   2122 	}
   2123 	case DATA_TYPE_UINT64_ARRAY: {
   2124 		uint64_t *val;
   2125 		uint_t nel;
   2126 		int i;
   2127 
   2128 		(void) nvpair_value_uint64_array(nvpair, &val, &nel);
   2129 		*nvals = nel;
   2130 		retvals = MALLOC(sizeof (struct evalue) * nel);
   2131 		for (i = 0; i < nel; i++) {
   2132 			retvals[i].t = UINT64;
   2133 			retvals[i].v = (unsigned long long)val[i];
   2134 		}
   2135 		return (retvals);
   2136 	}
   2137 
   2138 	}
   2139 
   2140 	return (NULL);
   2141 }
   2142 
   2143 /*
   2144  * When a list.repaired event is seen the following is called for
   2145  * each fault in the associated fault list to convert the given FMRI
   2146  * to an instanced path.  Only hc scheme is supported.
   2147  */
   2148 const struct ipath *
   2149 platform_fault2ipath(nvlist_t *flt)
   2150 {
   2151 	nvlist_t *rsrc;
   2152 	struct node *np;
   2153 	char *scheme;
   2154 	const struct ipath *ip;
   2155 
   2156 	if (nvlist_lookup_nvlist(flt, FM_FAULT_RESOURCE, &rsrc) != 0) {
   2157 		out(O_ALTFP, "platform_fault2ipath: no resource member");
   2158 		return (NULL);
   2159 	} else if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) {
   2160 		out(O_ALTFP, "platform_fault2ipath: no scheme type for rsrc");
   2161 		return (NULL);
   2162 	}
   2163 
   2164 	if (strncmp(scheme, FM_FMRI_SCHEME_HC,
   2165 	    sizeof (FM_FMRI_SCHEME_HC) - 1) != 0) {
   2166 		out(O_ALTFP, "platform_fault2ipath: returning NULL for non-hc "
   2167 		"scheme %s", scheme);
   2168 		return (NULL);
   2169 	}
   2170 
   2171 	if ((np = hc_fmri_nodeize(rsrc)) == NULL)
   2172 		return (NULL);		/* nodeize will already have whinged */
   2173 
   2174 	ip = ipath(np);
   2175 	tree_free(np);
   2176 	return (ip);
   2177 }
   2178