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