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