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,char * pname)770 cfgstrprop_lookup(struct config *croot, char *path, 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 resource FMRI from libtopo
794 */
795 /*ARGSUSED*/
796 void
platform_units_translate(int isdefect,struct config * croot,nvlist_t ** dfltasru,nvlist_t ** dfltfru,nvlist_t ** dfltrsrc,char * path)797 platform_units_translate(int isdefect, struct config *croot,
798 nvlist_t **dfltasru, nvlist_t **dfltfru, nvlist_t **dfltrsrc, char *path)
799 {
800 const char *fmristr;
801 char *serial;
802 nvlist_t *rsrc;
803 int err;
804
805 fmristr = cfgstrprop_lookup(croot, path, TOPO_PROP_RESOURCE);
806 if (fmristr == NULL) {
807 out(O_ALTFP, "Cannot rewrite resource for %s.", path);
808 return;
809 }
810 if (topo_fmri_str2nvl(Eft_topo_hdl, fmristr, &rsrc, &err) < 0) {
811 out(O_ALTFP, "Can not convert config info: %s",
812 topo_strerror(err));
813 out(O_ALTFP, "Cannot rewrite resource for %s.", path);
814 return;
815 }
816
817 /*
818 * If we don't have a serial number in the resource then check if it
819 * is available as a separate property and if so then add it.
820 */
821 if (nvlist_lookup_string(rsrc, FM_FMRI_HC_SERIAL_ID, &serial) != 0) {
822 serial = (char *)cfgstrprop_lookup(croot, path,
823 FM_FMRI_HC_SERIAL_ID);
824 if (serial != NULL)
825 (void) nvlist_add_string(rsrc, FM_FMRI_HC_SERIAL_ID,
826 serial);
827 }
828
829 *dfltrsrc = rsrc;
830 }
831
832 /*
833 * platform_get_files -- return names of all files we should load
834 *
835 * search directories in dirname[] for all files with names ending with the
836 * substring fnstr. dirname[] should be a NULL-terminated array. fnstr
837 * may be set to "*" to indicate all files in a directory.
838 *
839 * if nodups is non-zero, then the first file of a given name found is
840 * the only file added to the list of names. for example if nodups is
841 * set and we're looking for .efts, and find a pci.eft in the dirname[0],
842 * then no pci.eft found in any of the other dirname[] entries will be
843 * included in the final list of names.
844 *
845 * this routine doesn't return NULL, even if no files are found (in that
846 * case, a char ** is returned with the first element NULL).
847 */
848 static char **
platform_get_files(const char * dirname[],const char * fnstr,int nodups)849 platform_get_files(const char *dirname[], const char *fnstr, int nodups)
850 {
851 DIR *dirp;
852 struct dirent *dp;
853 struct lut *foundnames = NULL;
854 char **files = NULL; /* char * array of filenames found */
855 int nfiles = 0; /* files found so far */
856 int slots = 0; /* char * slots allocated in files */
857 size_t fnlen, d_namelen;
858 size_t totlen;
859 int i;
860 static char *nullav;
861
862 ASSERT(fnstr != NULL);
863 fnlen = strlen(fnstr);
864
865 for (i = 0; dirname[i] != NULL; i++) {
866 out(O_VERB, "Looking for %s files in %s", fnstr, dirname[i]);
867 if ((dirp = opendir(dirname[i])) == NULL) {
868 out(O_DEBUG|O_SYS,
869 "platform_get_files: opendir failed for %s",
870 dirname[i]);
871 continue;
872 }
873 while ((dp = readdir(dirp)) != NULL) {
874 if ((fnlen == 1 && *fnstr == '*') ||
875 ((d_namelen = strlen(dp->d_name)) >= fnlen &&
876 strncmp(dp->d_name + d_namelen - fnlen,
877 fnstr, fnlen) == 0)) {
878
879 if (nodups != 0) {
880 const char *snm = stable(dp->d_name);
881
882 if (lut_lookup(foundnames,
883 (void *)snm,
884 NULL) != NULL) {
885 out(O_VERB,
886 "platform_get_files: "
887 "skipping repeated name "
888 "%s/%s",
889 dirname[i],
890 snm);
891 continue;
892 }
893 foundnames = lut_add(foundnames,
894 (void *)snm,
895 (void *)snm,
896 NULL);
897 }
898
899 if (nfiles > slots - 2) {
900 /* allocate ten more slots */
901 slots += 10;
902 files = (char **)REALLOC(files,
903 slots * sizeof (char *));
904 }
905 /* prepend directory name and / */
906 totlen = strlen(dirname[i]) + 1;
907 totlen += strlen(dp->d_name) + 1;
908 files[nfiles] = MALLOC(totlen);
909 out(O_VERB, "File %d: \"%s/%s\"", nfiles,
910 dirname[i], dp->d_name);
911 (void) snprintf(files[nfiles++], totlen,
912 "%s/%s", dirname[i], dp->d_name);
913 }
914 }
915 (void) closedir(dirp);
916 }
917
918 if (foundnames != NULL)
919 lut_free(foundnames, NULL, NULL);
920
921 if (nfiles == 0)
922 return (&nullav);
923
924 files[nfiles] = NULL;
925 return (files);
926 }
927
928 /*
929 * search for files in a standard set of directories
930 */
931 static char **
platform_get_files_stddirs(char * fname,int nodups)932 platform_get_files_stddirs(char *fname, int nodups)
933 {
934 const char *dirlist[4];
935 char **flist;
936 char *eftgendir, *eftmachdir, *eftplatdir;
937
938 eftgendir = MALLOC(MAXPATHLEN);
939 eftmachdir = MALLOC(MAXPATHLEN);
940 eftplatdir = MALLOC(MAXPATHLEN);
941
942 /* Generic files that apply to any machine */
943 (void) snprintf(eftgendir, MAXPATHLEN, "%s/usr/lib/fm/eft", Root);
944
945 (void) snprintf(eftmachdir,
946 MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Mach);
947
948 (void) snprintf(eftplatdir,
949 MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Plat);
950
951 dirlist[0] = eftplatdir;
952 dirlist[1] = eftmachdir;
953 dirlist[2] = eftgendir;
954 dirlist[3] = NULL;
955
956 flist = platform_get_files(dirlist, fname, nodups);
957
958 FREE(eftplatdir);
959 FREE(eftmachdir);
960 FREE(eftgendir);
961
962 return (flist);
963 }
964
965 /*
966 * platform_run_poller -- execute a poller
967 *
968 * when eft needs to know if a polled ereport exists this routine
969 * is called so the poller code may be run in a platform-specific way.
970 * there's no return value from this routine -- either the polled ereport
971 * is generated (and delivered *before* this routine returns) or not.
972 * any errors, like "poller unknown" are considered platform-specific
973 * should be handled here rather than passing an error back up.
974 */
975 /*ARGSUSED*/
976 void
platform_run_poller(const char * poller)977 platform_run_poller(const char *poller)
978 {
979 }
980
981 /*
982 * fork and execve path with argument array argv and environment array
983 * envp. data from stdout and stderr are placed in outbuf and errbuf,
984 * respectively.
985 *
986 * see execve(2) for more descriptions for path, argv and envp.
987 */
988 static int
forkandexecve(const char * path,char * const argv[],char * const envp[],char * outbuf,size_t outbuflen,char * errbuf,size_t errbuflen)989 forkandexecve(const char *path, char *const argv[], char *const envp[],
990 char *outbuf, size_t outbuflen, char *errbuf, size_t errbuflen)
991 {
992 pid_t pid;
993 int outpipe[2], errpipe[2];
994 int rt = 0;
995
996 /*
997 * run the cmd and see if it failed. this function is *not* a
998 * generic command runner -- we depend on some knowledge we
999 * have about the commands we run. first of all, we expect
1000 * errors to spew something to stdout, and that something is
1001 * typically short enough to fit into a pipe so we can wait()
1002 * for the command to complete and then fetch the error text
1003 * from the pipe.
1004 */
1005 if (pipe(outpipe) < 0)
1006 if (strlcat(errbuf, ": pipe(outpipe) failed",
1007 errbuflen) >= errbuflen)
1008 return (1);
1009 if (pipe(errpipe) < 0)
1010 if (strlcat(errbuf, ": pipe(errpipe) failed",
1011 errbuflen) >= errbuflen)
1012 return (1);
1013
1014 if ((pid = fork()) < 0) {
1015 rt = (int)strlcat(errbuf, ": fork() failed", errbuflen);
1016 } else if (pid) {
1017 int wstat, count;
1018
1019 /* parent */
1020 (void) close(errpipe[1]);
1021 (void) close(outpipe[1]);
1022
1023 /* PHASE2 need to guard against hang in child? */
1024 if (waitpid(pid, &wstat, 0) < 0)
1025 if (strlcat(errbuf, ": waitpid() failed",
1026 errbuflen) >= errbuflen)
1027 return (1);
1028
1029 /* check for stderr contents */
1030 if (ioctl(errpipe[0], FIONREAD, &count) >= 0 && count) {
1031 if (read(errpipe[0], errbuf, errbuflen) <= 0) {
1032 /*
1033 * read failed even though ioctl indicated
1034 * that nonzero bytes were available for
1035 * reading
1036 */
1037 if (strlcat(errbuf, ": read(errpipe) failed",
1038 errbuflen) >= errbuflen)
1039 return (1);
1040 }
1041 /*
1042 * handle case where errbuf is not properly
1043 * terminated
1044 */
1045 if (count > errbuflen - 1)
1046 count = errbuflen - 1;
1047 if (errbuf[count - 1] != '\0' &&
1048 errbuf[count - 1] != '\n')
1049 errbuf[count] = '\0';
1050 } else if (WIFSIGNALED(wstat))
1051 if (strlcat(errbuf, ": signaled",
1052 errbuflen) >= errbuflen)
1053 return (1);
1054 else if (WIFEXITED(wstat) && WEXITSTATUS(wstat))
1055 if (strlcat(errbuf, ": abnormal exit",
1056 errbuflen) >= errbuflen)
1057 return (1);
1058
1059 /* check for stdout contents */
1060 if (ioctl(outpipe[0], FIONREAD, &count) >= 0 && count) {
1061 if (read(outpipe[0], outbuf, outbuflen) <= 0) {
1062 /*
1063 * read failed even though ioctl indicated
1064 * that nonzero bytes were available for
1065 * reading
1066 */
1067 if (strlcat(errbuf, ": read(outpipe) failed",
1068 errbuflen) >= errbuflen)
1069 return (1);
1070 }
1071 /*
1072 * handle case where outbuf is not properly
1073 * terminated
1074 */
1075 if (count > outbuflen - 1)
1076 count = outbuflen - 1;
1077 if (outbuf[count - 1] != '\0' &&
1078 outbuf[count - 1] != '\n')
1079 outbuf[count] = '\0';
1080 }
1081
1082 (void) close(errpipe[0]);
1083 (void) close(outpipe[0]);
1084 } else {
1085 /* child */
1086 (void) dup2(errpipe[1], fileno(stderr));
1087 (void) close(errpipe[0]);
1088 (void) dup2(outpipe[1], fileno(stdout));
1089 (void) close(outpipe[0]);
1090
1091 if (execve(path, argv, envp))
1092 perror(path);
1093 _exit(1);
1094 }
1095
1096 return (rt);
1097 }
1098
1099 #define MAXDIGITIDX 23
1100
1101 static int
arglist2argv(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,char *** argv,int * argc,int * argvlen)1102 arglist2argv(struct node *np, struct lut **globals, struct config *croot,
1103 struct arrow *arrowp, char ***argv, int *argc, int *argvlen)
1104 {
1105 struct node *namep;
1106 char numbuf[MAXDIGITIDX + 1];
1107 char *numstr, *nullbyte;
1108 char *addthisarg = NULL;
1109
1110 if (np == NULL)
1111 return (0);
1112
1113 switch (np->t) {
1114 case T_QUOTE:
1115 addthisarg = STRDUP(np->u.func.s);
1116 break;
1117 case T_LIST:
1118 if (arglist2argv(np->u.expr.left, globals, croot, arrowp,
1119 argv, argc, argvlen))
1120 return (1);
1121 /*
1122 * only leftmost element of a list can provide the command
1123 * name (after which *argc becomes 1)
1124 */
1125 ASSERT(*argc > 0);
1126 if (arglist2argv(np->u.expr.right, globals, croot, arrowp,
1127 argv, argc, argvlen))
1128 return (1);
1129 break;
1130 case T_FUNC:
1131 case T_GLOBID:
1132 case T_ASSIGN:
1133 case T_CONDIF:
1134 case T_CONDELSE:
1135 case T_EQ:
1136 case T_NE:
1137 case T_LT:
1138 case T_LE:
1139 case T_GT:
1140 case T_GE:
1141 case T_BITAND:
1142 case T_BITOR:
1143 case T_BITXOR:
1144 case T_BITNOT:
1145 case T_LSHIFT:
1146 case T_RSHIFT:
1147 case T_AND:
1148 case T_OR:
1149 case T_NOT:
1150 case T_ADD:
1151 case T_SUB:
1152 case T_MUL:
1153 case T_DIV:
1154 case T_MOD: {
1155 struct evalue value;
1156
1157 if (!eval_expr(np, NULL, NULL, globals, croot, arrowp,
1158 0, &value))
1159 return (1);
1160
1161 switch (value.t) {
1162 case UINT64:
1163 numbuf[MAXDIGITIDX] = '\0';
1164 nullbyte = &numbuf[MAXDIGITIDX];
1165 numstr = ulltostr(value.v, nullbyte);
1166 addthisarg = STRDUP(numstr);
1167 break;
1168 case STRING:
1169 addthisarg = STRDUP((const char *)(uintptr_t)value.v);
1170 break;
1171 case NODEPTR :
1172 namep = (struct node *)(uintptr_t)value.v;
1173 addthisarg = ipath2str(NULL, ipath(namep));
1174 break;
1175 default:
1176 out(O_ERR,
1177 "call: arglist2argv: unexpected result from"
1178 " operation %s",
1179 ptree_nodetype2str(np->t));
1180 return (1);
1181 }
1182 break;
1183 }
1184 case T_NUM:
1185 case T_TIMEVAL:
1186 numbuf[MAXDIGITIDX] = '\0';
1187 nullbyte = &numbuf[MAXDIGITIDX];
1188 numstr = ulltostr(np->u.ull, nullbyte);
1189 addthisarg = STRDUP(numstr);
1190 break;
1191 case T_NAME:
1192 addthisarg = ipath2str(NULL, ipath(np));
1193 break;
1194 case T_EVENT:
1195 addthisarg = ipath2str(np->u.event.ename->u.name.s,
1196 ipath(np->u.event.epname));
1197 break;
1198 default:
1199 out(O_ERR, "call: arglist2argv: node type %s is unsupported",
1200 ptree_nodetype2str(np->t));
1201 return (1);
1202 /*NOTREACHED*/
1203 break;
1204 }
1205
1206 if (*argc == 0 && addthisarg != NULL) {
1207 /*
1208 * first argument added is the command name.
1209 */
1210 char **files;
1211
1212 files = platform_get_files_stddirs(addthisarg, 0);
1213
1214 /* do not proceed if number of files found != 1 */
1215 if (files[0] == NULL)
1216 out(O_DIE, "call: function %s not found", addthisarg);
1217 if (files[1] != NULL)
1218 out(O_DIE, "call: multiple functions %s found",
1219 addthisarg);
1220 FREE(addthisarg);
1221
1222 addthisarg = STRDUP(files[0]);
1223 FREE(files[0]);
1224 FREE(files);
1225 }
1226
1227 if (addthisarg != NULL) {
1228 if (*argc >= *argvlen - 2) {
1229 /*
1230 * make sure argv is long enough so it has a
1231 * terminating element set to NULL
1232 */
1233 *argvlen += 10;
1234 *argv = (char **)REALLOC(*argv,
1235 sizeof (char *) * *argvlen);
1236 }
1237 (*argv)[*argc] = addthisarg;
1238 (*argc)++;
1239 (*argv)[*argc] = NULL;
1240 }
1241
1242 return (0);
1243 }
1244
1245 static int
generate_envp(struct arrow * arrowp,char *** envp,int * envc,int * envplen)1246 generate_envp(struct arrow *arrowp, char ***envp, int *envc, int *envplen)
1247 {
1248 char *envnames[] = { "EFT_FROM_EVENT", "EFT_TO_EVENT",
1249 "EFT_FILE", "EFT_LINE", NULL };
1250 char *envvalues[4];
1251 char *none = "(none)";
1252 size_t elen;
1253 int i;
1254
1255 *envc = 4;
1256
1257 /*
1258 * make sure envp is long enough so it has a terminating element
1259 * set to NULL
1260 */
1261 *envplen = *envc + 1;
1262 *envp = (char **)MALLOC(sizeof (char *) * *envplen);
1263
1264 envvalues[0] = ipath2str(
1265 arrowp->tail->myevent->enode->u.event.ename->u.name.s,
1266 arrowp->tail->myevent->ipp);
1267 envvalues[1] = ipath2str(
1268 arrowp->head->myevent->enode->u.event.ename->u.name.s,
1269 arrowp->head->myevent->ipp);
1270
1271 if (arrowp->head->myevent->enode->file == NULL) {
1272 envvalues[2] = STRDUP(none);
1273 envvalues[3] = STRDUP(none);
1274 } else {
1275 envvalues[2] = STRDUP(arrowp->head->myevent->enode->file);
1276
1277 /* large enough for max int */
1278 envvalues[3] = MALLOC(sizeof (char) * 25);
1279 (void) snprintf(envvalues[3], sizeof (envvalues[3]), "%d",
1280 arrowp->head->myevent->enode->line);
1281 }
1282
1283 for (i = 0; envnames[i] != NULL && i < *envc; i++) {
1284 elen = strlen(envnames[i]) + strlen(envvalues[i]) + 2;
1285 (*envp)[i] = MALLOC(elen);
1286 (void) snprintf((*envp)[i], elen, "%s=%s",
1287 envnames[i], envvalues[i]);
1288 FREE(envvalues[i]);
1289 }
1290 (*envp)[*envc] = NULL;
1291
1292 return (0);
1293 }
1294
1295 /*
1296 * platform_call -- call an external function
1297 *
1298 * evaluate a user-defined function and place result in valuep. return 0
1299 * if function evaluation was successful; 1 if otherwise.
1300 */
1301 int
platform_call(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,struct evalue * valuep)1302 platform_call(struct node *np, struct lut **globals, struct config *croot,
1303 struct arrow *arrowp, struct evalue *valuep)
1304 {
1305 /*
1306 * use rather short buffers. only the first string on outbuf[] is
1307 * taken as output from the called function. any message in
1308 * errbuf[] is echoed out as an error message.
1309 */
1310 char outbuf[256], errbuf[512];
1311 struct stat buf;
1312 char **argv, **envp;
1313 int argc, argvlen, envc, envplen;
1314 int i, ret;
1315
1316 /*
1317 * np is the argument list. the user-defined function is the first
1318 * element of the list.
1319 */
1320 ASSERT(np->t == T_LIST);
1321
1322 argv = NULL;
1323 argc = 0;
1324 argvlen = 0;
1325 if (arglist2argv(np, globals, croot, arrowp, &argv, &argc, &argvlen) ||
1326 argc == 0)
1327 return (1);
1328
1329 /*
1330 * make sure program has executable bit set
1331 */
1332 if (stat(argv[0], &buf) == 0) {
1333 int exec_bit_set = 0;
1334
1335 if (buf.st_uid == geteuid() && buf.st_mode & S_IXUSR)
1336 exec_bit_set = 1;
1337 else if (buf.st_gid == getegid() && buf.st_mode & S_IXGRP)
1338 exec_bit_set = 1;
1339 else if (buf.st_mode & S_IXOTH)
1340 exec_bit_set = 1;
1341
1342 if (exec_bit_set == 0)
1343 out(O_DIE, "call: executable bit not set on %s",
1344 argv[0]);
1345 } else {
1346 out(O_DIE, "call: failure in stat(), errno = %d\n", errno);
1347 }
1348
1349 envp = NULL;
1350 envc = 0;
1351 envplen = 0;
1352 if (generate_envp(arrowp, &envp, &envc, &envplen))
1353 return (1);
1354
1355 outbuf[0] = '\0';
1356 errbuf[0] = '\0';
1357
1358 ret = forkandexecve((const char *) argv[0], (char *const *) argv,
1359 (char *const *) envp, outbuf, sizeof (outbuf),
1360 errbuf, sizeof (errbuf));
1361
1362 for (i = 0; i < envc; i++)
1363 FREE(envp[i]);
1364 if (envp)
1365 FREE(envp);
1366
1367 if (ret) {
1368 outfl(O_OK, np->file, np->line,
1369 "call: failure in fork + exec of %s", argv[0]);
1370 } else {
1371 char *ptr;
1372
1373 /* chomp the result */
1374 for (ptr = outbuf; *ptr; ptr++)
1375 if (*ptr == '\n' || *ptr == '\r') {
1376 *ptr = '\0';
1377 break;
1378 }
1379 valuep->t = STRING;
1380 valuep->v = (uintptr_t)stable(outbuf);
1381 }
1382
1383 if (errbuf[0] != '\0') {
1384 ret = 1;
1385 outfl(O_OK, np->file, np->line,
1386 "call: unexpected stderr output from %s: %s",
1387 argv[0], errbuf);
1388 }
1389
1390 for (i = 0; i < argc; i++)
1391 FREE(argv[i]);
1392 FREE(argv);
1393
1394 return (ret);
1395 }
1396
1397 /*
1398 * platform_confcall -- call a configuration database function
1399 *
1400 * returns result in *valuep, return 0 on success
1401 */
1402 /*ARGSUSED*/
1403 int
platform_confcall(struct node * np,struct lut ** globals,struct config * croot,struct arrow * arrowp,struct evalue * valuep)1404 platform_confcall(struct node *np, struct lut **globals, struct config *croot,
1405 struct arrow *arrowp, struct evalue *valuep)
1406 {
1407 outfl(O_ALTFP|O_VERB, np->file, np->line, "unknown confcall");
1408 return (0);
1409 }
1410
1411 /*
1412 * platform_get_eft_files -- return names of all eft files we should load
1413 *
1414 * this routine doesn't return NULL, even if no files are found (in that
1415 * case, a char ** is returned with the first element NULL).
1416 */
1417 char **
platform_get_eft_files(void)1418 platform_get_eft_files(void)
1419 {
1420 return (platform_get_files_stddirs(".eft", 1));
1421 }
1422
1423 void
platform_free_eft_files(char ** flist)1424 platform_free_eft_files(char **flist)
1425 {
1426 char **f;
1427
1428 if (flist == NULL || *flist == NULL)
1429 return; /* no files were found so we're done */
1430
1431 f = flist;
1432 while (*f != NULL) {
1433 FREE(*f);
1434 f++;
1435 }
1436 FREE(flist);
1437 }
1438
1439 static nvlist_t *payloadnvp = NULL;
1440
1441 void
platform_set_payloadnvp(nvlist_t * nvlp)1442 platform_set_payloadnvp(nvlist_t *nvlp)
1443 {
1444 /*
1445 * cannot replace a non-NULL payloadnvp with a non-NULL nvlp
1446 */
1447 ASSERT(payloadnvp != NULL ? nvlp == NULL : 1);
1448 payloadnvp = nvlp;
1449 }
1450
1451 /*
1452 * given array notation in inputstr such as "foo[1]" or "foo [ 1 ]" (spaces
1453 * allowed), figure out the array name and index. return 0 if successful,
1454 * nonzero if otherwise.
1455 */
1456 static int
get_array_info(const char * inputstr,const char ** name,unsigned int * index)1457 get_array_info(const char *inputstr, const char **name, unsigned int *index)
1458 {
1459 char *indexptr, *indexend, *dupname, *endname;
1460
1461 if (strchr(inputstr, '[') == NULL)
1462 return (1);
1463
1464 dupname = STRDUP(inputstr);
1465 indexptr = strchr(dupname, '[');
1466 indexend = strchr(dupname, ']');
1467
1468 /*
1469 * return if array notation is not complete or if index is negative
1470 */
1471 if (indexend == NULL || indexptr >= indexend ||
1472 strchr(indexptr, '-') != NULL) {
1473 FREE(dupname);
1474 return (1);
1475 }
1476
1477 /*
1478 * search past any spaces between the name string and '['
1479 */
1480 endname = indexptr;
1481 while (isspace(*(endname - 1)) && dupname < endname)
1482 endname--;
1483 *endname = '\0';
1484 ASSERT(dupname < endname);
1485
1486 /*
1487 * search until indexptr points to the first digit and indexend
1488 * points to the last digit
1489 */
1490 while (!isdigit(*indexptr) && indexptr < indexend)
1491 indexptr++;
1492 while (!isdigit(*indexend) && indexptr <= indexend)
1493 indexend--;
1494
1495 *(indexend + 1) = '\0';
1496 *index = (unsigned int)atoi(indexptr);
1497
1498 *name = stable(dupname);
1499 FREE(dupname);
1500
1501 return (0);
1502 }
1503
1504 /*
1505 * platform_payloadprop -- fetch a payload value
1506 *
1507 * XXX this function should be replaced and eval_func() should be
1508 * XXX changed to use the more general platform_payloadprop_values().
1509 */
1510 int
platform_payloadprop(struct node * np,struct evalue * valuep)1511 platform_payloadprop(struct node *np, struct evalue *valuep)
1512 {
1513 nvlist_t *basenvp;
1514 nvlist_t *embnvp = NULL;
1515 nvpair_t *nvpair;
1516 const char *nameptr, *propstr, *lastnameptr;
1517 int not_array = 0;
1518 unsigned int index = 0;
1519 uint_t nelem;
1520 char *nvpname, *nameslist = NULL;
1521 char *scheme = NULL;
1522
1523 ASSERT(np->t == T_QUOTE);
1524
1525 propstr = np->u.quote.s;
1526 if (payloadnvp == NULL) {
1527 out(O_ALTFP | O_VERB2, "platform_payloadprop: no nvp for %s",
1528 propstr);
1529 return (1);
1530 }
1531 basenvp = payloadnvp;
1532
1533 /*
1534 * first handle any embedded nvlists. if propstr is "foo.bar[2]"
1535 * then lastnameptr should end up being "bar[2]" with basenvp set
1536 * to the nvlist for "foo". (the search for "bar" within "foo"
1537 * will be done later.)
1538 */
1539 if (strchr(propstr, '.') != NULL) {
1540 nvlist_t **arraynvp;
1541 uint_t nelem;
1542 char *w;
1543 int ier;
1544
1545 nameslist = STRDUP(propstr);
1546 lastnameptr = strtok(nameslist, ".");
1547
1548 /*
1549 * decompose nameslist into its component names while
1550 * extracting the embedded nvlist
1551 */
1552 while ((w = strtok(NULL, ".")) != NULL) {
1553 if (get_array_info(lastnameptr, &nameptr, &index)) {
1554 ier = nvlist_lookup_nvlist(basenvp,
1555 lastnameptr, &basenvp);
1556 } else {
1557 /* handle array of nvlists */
1558 ier = nvlist_lookup_nvlist_array(basenvp,
1559 nameptr, &arraynvp, &nelem);
1560 if (ier == 0) {
1561 if ((uint_t)index > nelem - 1)
1562 ier = 1;
1563 else
1564 basenvp = arraynvp[index];
1565 }
1566 }
1567
1568 if (ier) {
1569 out(O_ALTFP, "platform_payloadprop: "
1570 " invalid list for %s (in %s)",
1571 lastnameptr, propstr);
1572 FREE(nameslist);
1573 return (1);
1574 }
1575
1576 lastnameptr = w;
1577 }
1578 } else {
1579 lastnameptr = propstr;
1580 }
1581
1582 /* if property is an array reference, extract array name and index */
1583 not_array = get_array_info(lastnameptr, &nameptr, &index);
1584 if (not_array)
1585 nameptr = stable(lastnameptr);
1586
1587 if (nameslist != NULL)
1588 FREE(nameslist);
1589
1590 /* search for nvpair entry */
1591 nvpair = NULL;
1592 while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
1593 nvpname = nvpair_name(nvpair);
1594 ASSERT(nvpname != NULL);
1595
1596 if (nameptr == stable(nvpname))
1597 break;
1598 }
1599
1600 if (nvpair == NULL) {
1601 out(O_ALTFP, "platform_payloadprop: no entry for %s", propstr);
1602 return (1);
1603 } else if (valuep == NULL) {
1604 /*
1605 * caller is interested in the existence of a property with
1606 * this name, regardless of type or value
1607 */
1608 return (0);
1609 }
1610
1611 valuep->t = UNDEFINED;
1612
1613 /*
1614 * get to this point if we found an entry. figure out its data
1615 * type and copy its value.
1616 */
1617 (void) nvpair_value_nvlist(nvpair, &embnvp);
1618 if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME, &scheme) == 0) {
1619 if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1620 valuep->t = NODEPTR;
1621 valuep->v = (uintptr_t)hc_fmri_nodeize(embnvp);
1622 return (0);
1623 }
1624 }
1625 switch (nvpair_type(nvpair)) {
1626 case DATA_TYPE_BOOLEAN:
1627 case DATA_TYPE_BOOLEAN_VALUE: {
1628 boolean_t val;
1629 (void) nvpair_value_boolean_value(nvpair, &val);
1630 valuep->t = UINT64;
1631 valuep->v = (unsigned long long)val;
1632 break;
1633 }
1634 case DATA_TYPE_BYTE: {
1635 uchar_t val;
1636 (void) nvpair_value_byte(nvpair, &val);
1637 valuep->t = UINT64;
1638 valuep->v = (unsigned long long)val;
1639 break;
1640 }
1641 case DATA_TYPE_STRING: {
1642 char *val;
1643 valuep->t = STRING;
1644 (void) nvpair_value_string(nvpair, &val);
1645 valuep->v = (uintptr_t)stable(val);
1646 break;
1647 }
1648
1649 case DATA_TYPE_INT8: {
1650 int8_t val;
1651 (void) nvpair_value_int8(nvpair, &val);
1652 valuep->t = UINT64;
1653 valuep->v = (unsigned long long)val;
1654 break;
1655 }
1656 case DATA_TYPE_UINT8: {
1657 uint8_t val;
1658 (void) nvpair_value_uint8(nvpair, &val);
1659 valuep->t = UINT64;
1660 valuep->v = (unsigned long long)val;
1661 break;
1662 }
1663
1664 case DATA_TYPE_INT16: {
1665 int16_t val;
1666 (void) nvpair_value_int16(nvpair, &val);
1667 valuep->t = UINT64;
1668 valuep->v = (unsigned long long)val;
1669 break;
1670 }
1671 case DATA_TYPE_UINT16: {
1672 uint16_t val;
1673 (void) nvpair_value_uint16(nvpair, &val);
1674 valuep->t = UINT64;
1675 valuep->v = (unsigned long long)val;
1676 break;
1677 }
1678
1679 case DATA_TYPE_INT32: {
1680 int32_t val;
1681 (void) nvpair_value_int32(nvpair, &val);
1682 valuep->t = UINT64;
1683 valuep->v = (unsigned long long)val;
1684 break;
1685 }
1686 case DATA_TYPE_UINT32: {
1687 uint32_t val;
1688 (void) nvpair_value_uint32(nvpair, &val);
1689 valuep->t = UINT64;
1690 valuep->v = (unsigned long long)val;
1691 break;
1692 }
1693
1694 case DATA_TYPE_INT64: {
1695 int64_t val;
1696 (void) nvpair_value_int64(nvpair, &val);
1697 valuep->t = UINT64;
1698 valuep->v = (unsigned long long)val;
1699 break;
1700 }
1701 case DATA_TYPE_UINT64: {
1702 uint64_t val;
1703 (void) nvpair_value_uint64(nvpair, &val);
1704 valuep->t = UINT64;
1705 valuep->v = (unsigned long long)val;
1706 break;
1707 }
1708
1709 case DATA_TYPE_BOOLEAN_ARRAY: {
1710 boolean_t *val;
1711 (void) nvpair_value_boolean_array(nvpair, &val, &nelem);
1712 if (not_array == 1 || index >= nelem)
1713 goto invalid;
1714 valuep->t = UINT64;
1715 valuep->v = (unsigned long long)val[index];
1716 break;
1717 }
1718 case DATA_TYPE_BYTE_ARRAY: {
1719 uchar_t *val;
1720 (void) nvpair_value_byte_array(nvpair, &val, &nelem);
1721 if (not_array == 1 || index >= nelem)
1722 goto invalid;
1723 valuep->t = UINT64;
1724 valuep->v = (unsigned long long)val[index];
1725 break;
1726 }
1727 case DATA_TYPE_STRING_ARRAY: {
1728 char **val;
1729 (void) nvpair_value_string_array(nvpair, &val, &nelem);
1730 if (not_array == 1 || index >= nelem)
1731 goto invalid;
1732 valuep->t = STRING;
1733 valuep->v = (uintptr_t)stable(val[index]);
1734 break;
1735 }
1736
1737 case DATA_TYPE_INT8_ARRAY: {
1738 int8_t *val;
1739 (void) nvpair_value_int8_array(nvpair, &val, &nelem);
1740 if (not_array == 1 || index >= nelem)
1741 goto invalid;
1742 valuep->t = UINT64;
1743 valuep->v = (unsigned long long)val[index];
1744 break;
1745 }
1746 case DATA_TYPE_UINT8_ARRAY: {
1747 uint8_t *val;
1748 (void) nvpair_value_uint8_array(nvpair, &val, &nelem);
1749 if (not_array == 1 || index >= nelem)
1750 goto invalid;
1751 valuep->t = UINT64;
1752 valuep->v = (unsigned long long)val[index];
1753 break;
1754 }
1755 case DATA_TYPE_INT16_ARRAY: {
1756 int16_t *val;
1757 (void) nvpair_value_int16_array(nvpair, &val, &nelem);
1758 if (not_array == 1 || index >= nelem)
1759 goto invalid;
1760 valuep->t = UINT64;
1761 valuep->v = (unsigned long long)val[index];
1762 break;
1763 }
1764 case DATA_TYPE_UINT16_ARRAY: {
1765 uint16_t *val;
1766 (void) nvpair_value_uint16_array(nvpair, &val, &nelem);
1767 if (not_array == 1 || index >= nelem)
1768 goto invalid;
1769 valuep->t = UINT64;
1770 valuep->v = (unsigned long long)val[index];
1771 break;
1772 }
1773 case DATA_TYPE_INT32_ARRAY: {
1774 int32_t *val;
1775 (void) nvpair_value_int32_array(nvpair, &val, &nelem);
1776 if (not_array == 1 || index >= nelem)
1777 goto invalid;
1778 valuep->t = UINT64;
1779 valuep->v = (unsigned long long)val[index];
1780 break;
1781 }
1782 case DATA_TYPE_UINT32_ARRAY: {
1783 uint32_t *val;
1784 (void) nvpair_value_uint32_array(nvpair, &val, &nelem);
1785 if (not_array == 1 || index >= nelem)
1786 goto invalid;
1787 valuep->t = UINT64;
1788 valuep->v = (unsigned long long)val[index];
1789 break;
1790 }
1791 case DATA_TYPE_INT64_ARRAY: {
1792 int64_t *val;
1793 (void) nvpair_value_int64_array(nvpair, &val, &nelem);
1794 if (not_array == 1 || index >= nelem)
1795 goto invalid;
1796 valuep->t = UINT64;
1797 valuep->v = (unsigned long long)val[index];
1798 break;
1799 }
1800 case DATA_TYPE_UINT64_ARRAY: {
1801 uint64_t *val;
1802 (void) nvpair_value_uint64_array(nvpair, &val, &nelem);
1803 if (not_array == 1 || index >= nelem)
1804 goto invalid;
1805 valuep->t = UINT64;
1806 valuep->v = (unsigned long long)val[index];
1807 break;
1808 }
1809
1810 default :
1811 out(O_ALTFP|O_VERB2,
1812 "platform_payloadprop: unsupported data type for %s",
1813 propstr);
1814 return (1);
1815 }
1816
1817 return (0);
1818
1819 invalid:
1820 out(O_ALTFP|O_VERB2,
1821 "platform_payloadprop: invalid array reference for %s", propstr);
1822 return (1);
1823 }
1824
1825 /*ARGSUSED*/
1826 int
platform_path_exists(nvlist_t * fmri)1827 platform_path_exists(nvlist_t *fmri)
1828 {
1829 return (fmd_nvl_fmri_present(Hdl, fmri));
1830 }
1831
1832 struct evalue *
platform_payloadprop_values(const char * propstr,int * nvals)1833 platform_payloadprop_values(const char *propstr, int *nvals)
1834 {
1835 struct evalue *retvals;
1836 nvlist_t *basenvp;
1837 nvpair_t *nvpair;
1838 char *nvpname;
1839
1840 *nvals = 0;
1841
1842 if (payloadnvp == NULL)
1843 return (NULL);
1844
1845 basenvp = payloadnvp;
1846
1847 /* search for nvpair entry */
1848 nvpair = NULL;
1849 while ((nvpair = nvlist_next_nvpair(basenvp, nvpair)) != NULL) {
1850 nvpname = nvpair_name(nvpair);
1851 ASSERT(nvpname != NULL);
1852
1853 if (strcmp(propstr, nvpname) == 0)
1854 break;
1855 }
1856
1857 if (nvpair == NULL)
1858 return (NULL); /* property not found */
1859
1860 switch (nvpair_type(nvpair)) {
1861 case DATA_TYPE_NVLIST: {
1862 nvlist_t *embnvp = NULL;
1863 char *scheme = NULL;
1864
1865 (void) nvpair_value_nvlist(nvpair, &embnvp);
1866 if (nvlist_lookup_string(embnvp, FM_FMRI_SCHEME,
1867 &scheme) == 0) {
1868 if (strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1869 *nvals = 1;
1870 retvals = MALLOC(sizeof (struct evalue));
1871 retvals->t = NODEPTR;
1872 retvals->v =
1873 (uintptr_t)hc_fmri_nodeize(embnvp);
1874 return (retvals);
1875 }
1876 }
1877 return (NULL);
1878 }
1879 case DATA_TYPE_NVLIST_ARRAY: {
1880 char *scheme = NULL;
1881 nvlist_t **nvap;
1882 uint_t nel;
1883 int i;
1884 int hccount;
1885
1886 /*
1887 * since we're only willing to handle hc fmri's, we
1888 * must count them first before allocating retvals.
1889 */
1890 if (nvpair_value_nvlist_array(nvpair, &nvap, &nel) != 0)
1891 return (NULL);
1892
1893 hccount = 0;
1894 for (i = 0; i < nel; i++) {
1895 if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
1896 &scheme) == 0 &&
1897 strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1898 hccount++;
1899 }
1900 }
1901
1902 if (hccount == 0)
1903 return (NULL);
1904
1905 *nvals = hccount;
1906 retvals = MALLOC(sizeof (struct evalue) * hccount);
1907
1908 hccount = 0;
1909 for (i = 0; i < nel; i++) {
1910 if (nvlist_lookup_string(nvap[i], FM_FMRI_SCHEME,
1911 &scheme) == 0 &&
1912 strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1913 retvals[hccount].t = NODEPTR;
1914 retvals[hccount].v = (uintptr_t)
1915 hc_fmri_nodeize(nvap[i]);
1916 hccount++;
1917 }
1918 }
1919 return (retvals);
1920 }
1921 case DATA_TYPE_BOOLEAN:
1922 case DATA_TYPE_BOOLEAN_VALUE: {
1923 boolean_t val;
1924
1925 *nvals = 1;
1926 retvals = MALLOC(sizeof (struct evalue));
1927 (void) nvpair_value_boolean_value(nvpair, &val);
1928 retvals->t = UINT64;
1929 retvals->v = (unsigned long long)val;
1930 return (retvals);
1931 }
1932 case DATA_TYPE_BYTE: {
1933 uchar_t val;
1934
1935 *nvals = 1;
1936 retvals = MALLOC(sizeof (struct evalue));
1937 (void) nvpair_value_byte(nvpair, &val);
1938 retvals->t = UINT64;
1939 retvals->v = (unsigned long long)val;
1940 return (retvals);
1941 }
1942 case DATA_TYPE_STRING: {
1943 char *val;
1944
1945 *nvals = 1;
1946 retvals = MALLOC(sizeof (struct evalue));
1947 retvals->t = STRING;
1948 (void) nvpair_value_string(nvpair, &val);
1949 retvals->v = (uintptr_t)stable(val);
1950 return (retvals);
1951 }
1952
1953 case DATA_TYPE_INT8: {
1954 int8_t val;
1955
1956 *nvals = 1;
1957 retvals = MALLOC(sizeof (struct evalue));
1958 (void) nvpair_value_int8(nvpair, &val);
1959 retvals->t = UINT64;
1960 retvals->v = (unsigned long long)val;
1961 return (retvals);
1962 }
1963 case DATA_TYPE_UINT8: {
1964 uint8_t val;
1965
1966 *nvals = 1;
1967 retvals = MALLOC(sizeof (struct evalue));
1968 (void) nvpair_value_uint8(nvpair, &val);
1969 retvals->t = UINT64;
1970 retvals->v = (unsigned long long)val;
1971 return (retvals);
1972 }
1973
1974 case DATA_TYPE_INT16: {
1975 int16_t val;
1976
1977 *nvals = 1;
1978 retvals = MALLOC(sizeof (struct evalue));
1979 (void) nvpair_value_int16(nvpair, &val);
1980 retvals->t = UINT64;
1981 retvals->v = (unsigned long long)val;
1982 return (retvals);
1983 }
1984 case DATA_TYPE_UINT16: {
1985 uint16_t val;
1986
1987 *nvals = 1;
1988 retvals = MALLOC(sizeof (struct evalue));
1989 (void) nvpair_value_uint16(nvpair, &val);
1990 retvals->t = UINT64;
1991 retvals->v = (unsigned long long)val;
1992 return (retvals);
1993 }
1994
1995 case DATA_TYPE_INT32: {
1996 int32_t val;
1997
1998 *nvals = 1;
1999 retvals = MALLOC(sizeof (struct evalue));
2000 (void) nvpair_value_int32(nvpair, &val);
2001 retvals->t = UINT64;
2002 retvals->v = (unsigned long long)val;
2003 return (retvals);
2004 }
2005 case DATA_TYPE_UINT32: {
2006 uint32_t val;
2007
2008 *nvals = 1;
2009 retvals = MALLOC(sizeof (struct evalue));
2010 (void) nvpair_value_uint32(nvpair, &val);
2011 retvals->t = UINT64;
2012 retvals->v = (unsigned long long)val;
2013 return (retvals);
2014 }
2015
2016 case DATA_TYPE_INT64: {
2017 int64_t val;
2018
2019 *nvals = 1;
2020 retvals = MALLOC(sizeof (struct evalue));
2021 (void) nvpair_value_int64(nvpair, &val);
2022 retvals->t = UINT64;
2023 retvals->v = (unsigned long long)val;
2024 return (retvals);
2025 }
2026 case DATA_TYPE_UINT64: {
2027 uint64_t val;
2028
2029 *nvals = 1;
2030 retvals = MALLOC(sizeof (struct evalue));
2031 (void) nvpair_value_uint64(nvpair, &val);
2032 retvals->t = UINT64;
2033 retvals->v = (unsigned long long)val;
2034 return (retvals);
2035 }
2036
2037 case DATA_TYPE_BOOLEAN_ARRAY: {
2038 boolean_t *val;
2039 uint_t nel;
2040 int i;
2041
2042 (void) nvpair_value_boolean_array(nvpair, &val, &nel);
2043 *nvals = nel;
2044 retvals = MALLOC(sizeof (struct evalue) * nel);
2045 for (i = 0; i < nel; i++) {
2046 retvals[i].t = UINT64;
2047 retvals[i].v = (unsigned long long)val[i];
2048 }
2049 return (retvals);
2050 }
2051 case DATA_TYPE_BYTE_ARRAY: {
2052 uchar_t *val;
2053 uint_t nel;
2054 int i;
2055
2056 (void) nvpair_value_byte_array(nvpair, &val, &nel);
2057 *nvals = nel;
2058 retvals = MALLOC(sizeof (struct evalue) * nel);
2059 for (i = 0; i < nel; i++) {
2060 retvals[i].t = UINT64;
2061 retvals[i].v = (unsigned long long)val[i];
2062 }
2063 return (retvals);
2064 }
2065 case DATA_TYPE_STRING_ARRAY: {
2066 char **val;
2067 uint_t nel;
2068 int i;
2069
2070 (void) nvpair_value_string_array(nvpair, &val, &nel);
2071 *nvals = nel;
2072 retvals = MALLOC(sizeof (struct evalue) * nel);
2073 for (i = 0; i < nel; i++) {
2074 retvals[i].t = STRING;
2075 retvals[i].v = (uintptr_t)stable(val[i]);
2076 }
2077 return (retvals);
2078 }
2079
2080 case DATA_TYPE_INT8_ARRAY: {
2081 int8_t *val;
2082 uint_t nel;
2083 int i;
2084
2085 (void) nvpair_value_int8_array(nvpair, &val, &nel);
2086 *nvals = nel;
2087 retvals = MALLOC(sizeof (struct evalue) * nel);
2088 for (i = 0; i < nel; i++) {
2089 retvals[i].t = UINT64;
2090 retvals[i].v = (unsigned long long)val[i];
2091 }
2092 return (retvals);
2093 }
2094 case DATA_TYPE_UINT8_ARRAY: {
2095 uint8_t *val;
2096 uint_t nel;
2097 int i;
2098
2099 (void) nvpair_value_uint8_array(nvpair, &val, &nel);
2100 *nvals = nel;
2101 retvals = MALLOC(sizeof (struct evalue) * nel);
2102 for (i = 0; i < nel; i++) {
2103 retvals[i].t = UINT64;
2104 retvals[i].v = (unsigned long long)val[i];
2105 }
2106 return (retvals);
2107 }
2108 case DATA_TYPE_INT16_ARRAY: {
2109 int16_t *val;
2110 uint_t nel;
2111 int i;
2112
2113 (void) nvpair_value_int16_array(nvpair, &val, &nel);
2114 *nvals = nel;
2115 retvals = MALLOC(sizeof (struct evalue) * nel);
2116 for (i = 0; i < nel; i++) {
2117 retvals[i].t = UINT64;
2118 retvals[i].v = (unsigned long long)val[i];
2119 }
2120 return (retvals);
2121 }
2122 case DATA_TYPE_UINT16_ARRAY: {
2123 uint16_t *val;
2124 uint_t nel;
2125 int i;
2126
2127 (void) nvpair_value_uint16_array(nvpair, &val, &nel);
2128 *nvals = nel;
2129 retvals = MALLOC(sizeof (struct evalue) * nel);
2130 for (i = 0; i < nel; i++) {
2131 retvals[i].t = UINT64;
2132 retvals[i].v = (unsigned long long)val[i];
2133 }
2134 return (retvals);
2135 }
2136 case DATA_TYPE_INT32_ARRAY: {
2137 int32_t *val;
2138 uint_t nel;
2139 int i;
2140
2141 (void) nvpair_value_int32_array(nvpair, &val, &nel);
2142 *nvals = nel;
2143 retvals = MALLOC(sizeof (struct evalue) * nel);
2144 for (i = 0; i < nel; i++) {
2145 retvals[i].t = UINT64;
2146 retvals[i].v = (unsigned long long)val[i];
2147 }
2148 return (retvals);
2149 }
2150 case DATA_TYPE_UINT32_ARRAY: {
2151 uint32_t *val;
2152 uint_t nel;
2153 int i;
2154
2155 (void) nvpair_value_uint32_array(nvpair, &val, &nel);
2156 *nvals = nel;
2157 retvals = MALLOC(sizeof (struct evalue) * nel);
2158 for (i = 0; i < nel; i++) {
2159 retvals[i].t = UINT64;
2160 retvals[i].v = (unsigned long long)val[i];
2161 }
2162 return (retvals);
2163 }
2164 case DATA_TYPE_INT64_ARRAY: {
2165 int64_t *val;
2166 uint_t nel;
2167 int i;
2168
2169 (void) nvpair_value_int64_array(nvpair, &val, &nel);
2170 *nvals = nel;
2171 retvals = MALLOC(sizeof (struct evalue) * nel);
2172 for (i = 0; i < nel; i++) {
2173 retvals[i].t = UINT64;
2174 retvals[i].v = (unsigned long long)val[i];
2175 }
2176 return (retvals);
2177 }
2178 case DATA_TYPE_UINT64_ARRAY: {
2179 uint64_t *val;
2180 uint_t nel;
2181 int i;
2182
2183 (void) nvpair_value_uint64_array(nvpair, &val, &nel);
2184 *nvals = nel;
2185 retvals = MALLOC(sizeof (struct evalue) * nel);
2186 for (i = 0; i < nel; i++) {
2187 retvals[i].t = UINT64;
2188 retvals[i].v = (unsigned long long)val[i];
2189 }
2190 return (retvals);
2191 }
2192
2193 }
2194
2195 return (NULL);
2196 }
2197
2198 /*
2199 * When a list.repaired event is seen the following is called for
2200 * each fault in the associated fault list to convert the given FMRI
2201 * to an instanced path. Only hc scheme is supported.
2202 */
2203 const struct ipath *
platform_fault2ipath(nvlist_t * flt)2204 platform_fault2ipath(nvlist_t *flt)
2205 {
2206 nvlist_t *rsrc;
2207 struct node *np;
2208 char *scheme;
2209 const struct ipath *ip;
2210
2211 if (nvlist_lookup_nvlist(flt, FM_FAULT_RESOURCE, &rsrc) != 0) {
2212 out(O_ALTFP, "platform_fault2ipath: no resource member");
2213 return (NULL);
2214 } else if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) {
2215 out(O_ALTFP, "platform_fault2ipath: no scheme type for rsrc");
2216 return (NULL);
2217 }
2218
2219 if (strncmp(scheme, FM_FMRI_SCHEME_HC,
2220 sizeof (FM_FMRI_SCHEME_HC) - 1) != 0) {
2221 out(O_ALTFP, "platform_fault2ipath: returning NULL for non-hc "
2222 "scheme %s", scheme);
2223 return (NULL);
2224 }
2225
2226 if ((np = hc_fmri_nodeize(rsrc)) == NULL)
2227 return (NULL); /* nodeize will already have whinged */
2228
2229 ip = ipath(np);
2230 tree_free(np);
2231 return (ip);
2232 }
2233