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