xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/platform.c (revision 90231cc22caa602501d3735313671634fdef464d)
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