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