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 *
topo_use_alloc(size_t bytes)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
topo_use_free(void * p)87 topo_use_free(void *p)
88 {
89 alloc_free(p, NULL, 0);
90 }
91
92 /*ARGSUSED*/
93 static void *
alloc_nv_alloc(nv_alloc_t * nva,size_t size)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
alloc_nv_free(nv_alloc_t * nva,void * p,size_t sz)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
platform_globals()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
platform_free_globals()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
platform_init(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
platform_fini(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 *
hc_fmri_nodeize(nvlist_t * hcfmri)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 *
platform_getpath(nvlist_t * nvl)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 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 */
370 static void
cfgadjust(struct cfgdata * rawdata,int addlen)371 cfgadjust(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
385 static char *
hc_path(tnode_t * node)386 hc_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
432 static void
add_prop_val(topo_hdl_t * thp,struct cfgdata * rawdata,char * propn,nvpair_t * pv_nvp)433 add_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 */
565 static int
cfgcollect(topo_hdl_t * thp,tnode_t * node,void * arg)566 cfgcollect(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
662 void
platform_restore_config(fmd_hdl_t * hdl,fmd_case_t * fmcase)663 platform_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
679 void
platform_save_config(fmd_hdl_t * hdl,fmd_case_t * fmcase)680 platform_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 */
707 struct cfgdata *
platform_config_snapshot(void)708 platform_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
769 static const char *
cfgstrprop_lookup(struct config * croot,char * path,const char * pname)770 cfgstrprop_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*/
798 void
platform_unit_translate(int isdefect,struct config * croot,const char * prop,nvlist_t ** fmrip,char * path)799 platform_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 */
850 static char **
platform_get_files(const char * dirname[],const char * fnstr,int nodups)851 platform_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 */
933 static char **
platform_get_files_stddirs(char * fname,int nodups)934 platform_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*/
978 void
platform_run_poller(const char * poller)979 platform_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 */
990 static int
forkandexecve(const char * path,char * const argv[],char * const envp[],char * outbuf,size_t outbuflen,char * errbuf,size_t errbuflen)991 forkandexecve(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
1103 static int
arglist2argv(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,char *** argv,int * argc,int * argvlen)1104 arglist2argv(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
1247 static int
generate_envp(struct arrow * arrowp,char *** envp,int * envc,int * envplen)1248 generate_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 */
1303 int
platform_call(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,struct evalue * valuep)1304 platform_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*/
1405 int
platform_confcall(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,struct evalue * valuep)1406 platform_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 */
1419 char **
platform_get_eft_files(void)1420 platform_get_eft_files(void)
1421 {
1422 return (platform_get_files_stddirs(".eft", 1));
1423 }
1424
1425 void
platform_free_eft_files(char ** flist)1426 platform_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
1441 static nvlist_t *payloadnvp = NULL;
1442
1443 void
platform_set_payloadnvp(nvlist_t * nvlp)1444 platform_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 */
1458 static int
get_array_info(const char * inputstr,const char ** name,unsigned int * index)1459 get_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 */
1512 int
platform_payloadprop(struct node * np,struct evalue * valuep)1513 platform_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
1821 invalid:
1822 out(O_ALTFP|O_VERB2,
1823 "platform_payloadprop: invalid array reference for %s", propstr);
1824 return (1);
1825 }
1826
1827 /*ARGSUSED*/
1828 int
platform_path_exists(nvlist_t * fmri)1829 platform_path_exists(nvlist_t *fmri)
1830 {
1831 return (fmd_nvl_fmri_present(Hdl, fmri));
1832 }
1833
1834 struct evalue *
platform_payloadprop_values(const char * propstr,int * nvals)1835 platform_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 */
2205 const struct ipath *
platform_fault2ipath(nvlist_t * flt)2206 platform_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