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