dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fm / modules / common / eversholt / platform.c
blob70f66ddc7f3a8960934082a40fc020eb44713219
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * platform.c -- interfaces to the platform's configuration information
26 * this platform.c allows eft to run on Solaris systems.
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"
62 extern fmd_hdl_t *Hdl; /* handle from eft.c */
65 * Lastcfg points to the last configuration snapshot we made.
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;
75 static topo_hdl_t *Eft_topo_hdl;
77 void *
78 topo_use_alloc(size_t bytes)
80 void *p = alloc_malloc(bytes, NULL, 0);
82 bzero(p, bytes);
83 return (p);
86 void
87 topo_use_free(void *p)
89 alloc_free(p, NULL, 0);
92 /*ARGSUSED*/
93 static void *
94 alloc_nv_alloc(nv_alloc_t *nva, size_t size)
96 return (alloc_malloc(size, NULL, 0));
99 /*ARGSUSED*/
100 static void
101 alloc_nv_free(nv_alloc_t *nva, void *p, size_t sz)
103 alloc_free(p, NULL, 0);
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() */
114 nv_alloc_t Eft_nv_hdl;
116 static char *Root;
117 static char *Mach;
118 static char *Plat;
119 static char tmpbuf[MAXPATHLEN];
120 static char numbuf[MAXPATHLEN];
123 * platform_globals -- set global variables based on sysinfo() calls
125 static void
126 platform_globals()
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");
133 static void
134 platform_free_globals()
136 fmd_prop_free_string(Hdl, Root);
137 fmd_prop_free_string(Hdl, Mach);
138 fmd_prop_free_string(Hdl, Plat);
142 * platform_init -- perform any platform-specific initialization
144 void
145 platform_init(void)
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();
151 out(O_ALTFP, "platform_init() sucessful");
154 void
155 platform_fini(void)
157 if (Lastcfg != NULL) {
158 config_free(Lastcfg);
159 Lastcfg = NULL;
161 fmd_hdl_topo_rele(Hdl, Eft_topo_hdl);
162 platform_free_globals();
163 (void) nv_alloc_fini(&Eft_nv_hdl);
165 out(O_ALTFP, "platform_fini() sucessful");
169 * hc_fmri_nodeize -- convert hc-scheme FMRI to eft compatible format
171 * this is an internal platform.c helper routine
173 static struct node *
174 hc_fmri_nodeize(nvlist_t *hcfmri)
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;
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.
192 * Get the hc-list of elements in the FMRI
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);
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;
209 sname = stable(ename);
210 tmpn = tree_name_iterator(
211 tree_name(sname, IT_VERTICAL, NULL, 0),
212 tree_num(eid, NULL, 0));
214 if (pathtree == NULL)
215 pathtree = tmpn;
216 else
217 (void) tree_name_append(pathtree, tmpn);
220 return (pathtree);
224 * platform_getpath -- extract eft-compatible path from ereport
226 struct node *
227 platform_getpath(nvlist_t *nvl)
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;
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);
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);
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) {
258 * devid takes precedence over tp which takes precedence over
259 * path
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);
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);
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);
291 out(O_ALTFP|O_VERB, "Received ereport in scheme %s", scheme);
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) {
300 * If hc-scheme use the fmri that was passed in.
302 in_getpath = 0;
303 return (hc_fmri_nodeize(dfmri));
305 out(O_ALTFP, "XFILE: cannot snapshot configuration");
306 in_getpath = 0;
307 return (NULL);
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.
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);
327 nvlist_free(resource);
328 break;
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);
335 break;
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;
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;
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;
356 /* free the snapshot */
357 structconfig_free(Lastcfg->cooked);
358 config_free(Lastcfg);
359 in_getpath = 0;
360 return (ret);
363 /* Allocate space for raw config strings in chunks of this size */
364 #define STRSBUFLEN 512
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.
370 static void
371 cfgadjust(struct cfgdata *rawdata, int addlen)
373 int curnext, newlen;
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;
385 static char *
386 hc_path(tnode_t *node)
388 int i, err;
389 char *name, *instance, *estr;
390 nvlist_t *fmri, **hcl;
391 ulong_t ul;
392 uint_t nhc;
394 if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
395 &fmri, &err) < 0)
396 return (NULL);
398 if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &nhc)
399 != 0) {
400 nvlist_free(fmri);
401 return (NULL);
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);
413 ul = strtoul(instance, &estr, 10);
414 /* conversion to number failed? */
415 if (estr == instance) {
416 nvlist_free(fmri);
417 return (NULL);
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);
427 nvlist_free(fmri);
429 return (tmpbuf);
432 static void
433 add_prop_val(topo_hdl_t *thp, struct cfgdata *rawdata, char *propn,
434 nvpair_t *pv_nvp)
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 b;
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;
450 * malformed prop nvpair
452 if (propn == NULL)
453 return;
455 switch (nvpair_type(pv_nvp)) {
456 case DATA_TYPE_STRING_ARRAY:
458 * Convert string array into single space-separated string
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] = ' ';
470 break;
472 case DATA_TYPE_STRING:
473 (void) nvpair_value_string(pv_nvp, &propv);
474 break;
476 case DATA_TYPE_NVLIST:
478 * At least try to collect the protocol
479 * properties
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;
489 break;
491 case DATA_TYPE_UINT64:
493 * Convert uint64 to hex strings
495 (void) nvpair_value_uint64(pv_nvp, &ui64);
496 (void) snprintf(buf, sizeof (buf), "0x%llx", ui64);
497 propv = buf;
498 break;
500 case DATA_TYPE_BOOLEAN_VALUE:
502 * Convert boolean_t to hex strings
504 (void) nvpair_value_boolean_value(pv_nvp, &b);
505 (void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)b);
506 propv = buf;
507 break;
509 case DATA_TYPE_INT32:
511 * Convert int32 to hex strings
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;
519 case DATA_TYPE_INT64:
521 * Convert int64 to hex strings
523 (void) nvpair_value_int64(pv_nvp, &i64);
524 (void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)i64);
525 propv = buf;
526 break;
528 case DATA_TYPE_UINT32:
530 * Convert uint32 to hex strings
532 (void) nvpair_value_uint32(pv_nvp, &ui32);
533 (void) snprintf(buf, sizeof (buf), "0x%llx", (uint64_t)ui32);
534 propv = buf;
535 break;
537 default:
538 out(O_ALTFP, "cfgcollect: failed to get property value for "
539 "%s", propn);
540 return;
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);
552 if (nvpair_type(pv_nvp) == DATA_TYPE_STRING_ARRAY)
553 FREE(propv);
555 rawdata->nextfree += addlen;
557 if (fmristr != NULL)
558 topo_hdl_strfree(thp, fmristr);
562 * cfgcollect -- Assemble raw configuration data in string form suitable
563 * for checkpointing.
565 static int
566 cfgcollect(topo_hdl_t *thp, tnode_t *node, void *arg)
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;
574 if (topo_node_flags(node) == TOPO_NODE_FACILITY)
575 return (TOPO_WALK_NEXT);
577 path = hc_path(node);
578 if (path == NULL)
579 return (TOPO_WALK_ERR);
581 addlen = strlen(path) + 1;
583 cfgadjust(rawdata, addlen);
584 (void) strcpy(rawdata->nextfree, path);
585 rawdata->nextfree += addlen;
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).
596 * For now prune_raw_config is 0 for Solaris, though it is expected to
597 * be set to 1 for fmsp.
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.
605 if (!in_getpath && prune_raw_config &&
606 lut_lookup(Usednames, (void *)lastcomp, NULL) == NULL)
607 return (TOPO_WALK_NEXT);
610 * Collect properties
612 * eversholt should support alternate property types
613 * Better yet, topo properties could be represented as
614 * a packed nvlist
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;
623 (void) nvpair_value_nvlist(nvp, &pg_nv);
625 for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL;
626 pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) {
628 if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) != 0 ||
629 nvpair_type(pg_nvp) != DATA_TYPE_NVLIST)
630 continue;
632 (void) nvpair_value_nvlist(pg_nvp, &pv_nv);
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)) {
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);
646 * Get property value
648 if (strcmp(TOPO_PROP_VAL_VAL,
649 nvpair_name(pv_nvp)) == 0)
650 add_prop_val(thp, rawdata, propn,
651 pv_nvp);
657 nvlist_free(p_nv);
659 return (TOPO_WALK_NEXT);
662 void
663 platform_restore_config(fmd_hdl_t *hdl, fmd_case_t *fmcase)
665 if (hdl == Lasthdl && fmcase == Lastfmcase) {
666 size_t cfglen;
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;
679 void
680 platform_save_config(fmd_hdl_t *hdl, fmd_case_t *fmcase)
682 size_t cfglen;
685 * Put the raw config into an fmd_buf. Then we can free it to
686 * save space.
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);
698 FREE(Lastcfg->begin);
699 Lastcfg->begin = NULL;
700 Lastcfg->end = NULL;
701 Lastcfg->nextfree = NULL;
705 * platform_config_snapshot -- gather a snapshot of the current configuration
707 struct cfgdata *
708 platform_config_snapshot(void)
710 int err;
711 topo_walk_t *twp;
712 static uint64_t lastgen;
713 uint64_t curgen;
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.
720 if (prune_raw_config == 0 && (curgen = fmd_fmri_get_drgen()) <=
721 lastgen && Lastcfg != NULL) {
722 Lastcfg->raw_refcnt++;
724 * if config has been backed away to an fmd_buf, restore it
726 if (Lastcfg->begin == NULL)
727 platform_restore_config(Lasthdl, Lastfmcase);
728 return (Lastcfg);
731 lastgen = curgen;
732 /* we're getting a new config, so clean up the last one */
733 if (Lastcfg != NULL) {
734 config_free(Lastcfg);
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;
747 fmd_hdl_topo_rele(Hdl, Eft_topo_hdl);
748 Eft_topo_hdl = fmd_hdl_topo_hold(Hdl, TOPO_VERSION);
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));
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");
762 topo_walk_fini(twp);
763 out(O_ALTFP|O_STAMP, "raw config complete");
766 return (Lastcfg);
769 static const char *
770 cfgstrprop_lookup(struct config *croot, char *path, char *pname)
772 struct config *cresource;
773 const char *fmristr;
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.
780 if ((cresource = config_lookup(croot, path, 0)) == NULL) {
781 out(O_ALTFP, "Cannot find config info for %s.", path);
782 return (NULL);
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);
789 return (fmristr);
793 * Get resource FMRI from libtopo
795 /*ARGSUSED*/
796 void
797 platform_units_translate(int isdefect, struct config *croot,
798 nvlist_t **dfltasru, nvlist_t **dfltfru, nvlist_t **dfltrsrc, char *path)
800 const char *fmristr;
801 char *serial;
802 nvlist_t *rsrc;
803 int err;
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;
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;
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.
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);
829 *dfltrsrc = rsrc;
833 * platform_get_files -- return names of all files we should load
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.
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.
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).
848 static char **
849 platform_get_files(const char *dirname[], const char *fnstr, int nodups)
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;
862 ASSERT(fnstr != NULL);
863 fnlen = strlen(fnstr);
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;
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)) {
879 if (nodups != 0) {
880 const char *snm = stable(dp->d_name);
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;
893 foundnames = lut_add(foundnames,
894 (void *)snm,
895 (void *)snm,
896 NULL);
899 if (nfiles > slots - 2) {
900 /* allocate ten more slots */
901 slots += 10;
902 files = (char **)REALLOC(files,
903 slots * sizeof (char *));
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);
915 (void) closedir(dirp);
918 if (foundnames != NULL)
919 lut_free(foundnames, NULL, NULL);
921 if (nfiles == 0)
922 return (&nullav);
924 files[nfiles] = NULL;
925 return (files);
929 * search for files in a standard set of directories
931 static char **
932 platform_get_files_stddirs(char *fname, int nodups)
934 const char *dirlist[4];
935 char **flist;
936 char *eftgendir, *eftmachdir, *eftplatdir;
938 eftgendir = MALLOC(MAXPATHLEN);
939 eftmachdir = MALLOC(MAXPATHLEN);
940 eftplatdir = MALLOC(MAXPATHLEN);
942 /* Generic files that apply to any machine */
943 (void) snprintf(eftgendir, MAXPATHLEN, "%s/usr/lib/fm/eft", Root);
945 (void) snprintf(eftmachdir,
946 MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Mach);
948 (void) snprintf(eftplatdir,
949 MAXPATHLEN, "%s/usr/platform/%s/lib/fm/eft", Root, Plat);
951 dirlist[0] = eftplatdir;
952 dirlist[1] = eftmachdir;
953 dirlist[2] = eftgendir;
954 dirlist[3] = NULL;
956 flist = platform_get_files(dirlist, fname, nodups);
958 FREE(eftplatdir);
959 FREE(eftmachdir);
960 FREE(eftgendir);
962 return (flist);
966 * platform_run_poller -- execute a poller
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.
975 /*ARGSUSED*/
976 void
977 platform_run_poller(const char *poller)
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.
986 * see execve(2) for more descriptions for path, argv and envp.
988 static int
989 forkandexecve(const char *path, char *const argv[], char *const envp[],
990 char *outbuf, size_t outbuflen, char *errbuf, size_t errbuflen)
992 pid_t pid;
993 int outpipe[2], errpipe[2];
994 int rt = 0;
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.
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);
1014 if ((pid = fork()) < 0) {
1015 rt = (int)strlcat(errbuf, ": fork() failed", errbuflen);
1016 } else if (pid) {
1017 int wstat, count;
1019 /* parent */
1020 (void) close(errpipe[1]);
1021 (void) close(outpipe[1]);
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);
1029 /* check for stderr contents */
1030 if (ioctl(errpipe[0], FIONREAD, &count) >= 0 && count) {
1031 if (read(errpipe[0], errbuf, errbuflen) <= 0) {
1033 * read failed even though ioctl indicated
1034 * that nonzero bytes were available for
1035 * reading
1037 if (strlcat(errbuf, ": read(errpipe) failed",
1038 errbuflen) >= errbuflen)
1039 return (1);
1042 * handle case where errbuf is not properly
1043 * terminated
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);
1059 /* check for stdout contents */
1060 if (ioctl(outpipe[0], FIONREAD, &count) >= 0 && count) {
1061 if (read(outpipe[0], outbuf, outbuflen) <= 0) {
1063 * read failed even though ioctl indicated
1064 * that nonzero bytes were available for
1065 * reading
1067 if (strlcat(errbuf, ": read(outpipe) failed",
1068 errbuflen) >= errbuflen)
1069 return (1);
1072 * handle case where outbuf is not properly
1073 * terminated
1075 if (count > outbuflen - 1)
1076 count = outbuflen - 1;
1077 if (outbuf[count - 1] != '\0' &&
1078 outbuf[count - 1] != '\n')
1079 outbuf[count] = '\0';
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]);
1091 if (execve(path, argv, envp))
1092 perror(path);
1093 _exit(1);
1096 return (rt);
1099 #define MAXDIGITIDX 23
1101 static int
1102 arglist2argv(struct node *np, struct lut **globals, struct config *croot,
1103 struct arrow *arrowp, char ***argv, int *argc, int *argvlen)
1105 struct node *namep;
1106 char numbuf[MAXDIGITIDX + 1];
1107 char *numstr, *nullbyte;
1108 char *addthisarg = NULL;
1110 if (np == NULL)
1111 return (0);
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);
1122 * only leftmost element of a list can provide the command
1123 * name (after which *argc becomes 1)
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;
1157 if (!eval_expr(np, NULL, NULL, globals, croot, arrowp,
1158 0, &value))
1159 return (1);
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);
1182 break;
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;
1206 if (*argc == 0 && addthisarg != NULL) {
1208 * first argument added is the command name.
1210 char **files;
1212 files = platform_get_files_stddirs(addthisarg, 0);
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);
1222 addthisarg = STRDUP(files[0]);
1223 FREE(files[0]);
1224 FREE(files);
1227 if (addthisarg != NULL) {
1228 if (*argc >= *argvlen - 2) {
1230 * make sure argv is long enough so it has a
1231 * terminating element set to NULL
1233 *argvlen += 10;
1234 *argv = (char **)REALLOC(*argv,
1235 sizeof (char *) * *argvlen);
1237 (*argv)[*argc] = addthisarg;
1238 (*argc)++;
1239 (*argv)[*argc] = NULL;
1242 return (0);
1245 static int
1246 generate_envp(struct arrow *arrowp, char ***envp, int *envc, int *envplen)
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;
1255 *envc = 4;
1258 * make sure envp is long enough so it has a terminating element
1259 * set to NULL
1261 *envplen = *envc + 1;
1262 *envp = (char **)MALLOC(sizeof (char *) * *envplen);
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);
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);
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);
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]);
1290 (*envp)[*envc] = NULL;
1292 return (0);
1296 * platform_call -- call an external function
1298 * evaluate a user-defined function and place result in valuep. return 0
1299 * if function evaluation was successful; 1 if otherwise.
1302 platform_call(struct node *np, struct lut **globals, struct config *croot,
1303 struct arrow *arrowp, struct evalue *valuep)
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.
1310 char outbuf[256], errbuf[512];
1311 struct stat buf;
1312 char **argv, **envp;
1313 int argc, argvlen, envc, envplen;
1314 int i, ret;
1317 * np is the argument list. the user-defined function is the first
1318 * element of the list.
1320 ASSERT(np->t == T_LIST);
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);
1330 * make sure program has executable bit set
1332 if (stat(argv[0], &buf) == 0) {
1333 int exec_bit_set = 0;
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;
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);
1349 envp = NULL;
1350 envc = 0;
1351 envplen = 0;
1352 if (generate_envp(arrowp, &envp, &envc, &envplen))
1353 return (1);
1355 outbuf[0] = '\0';
1356 errbuf[0] = '\0';
1358 ret = forkandexecve((const char *) argv[0], (char *const *) argv,
1359 (char *const *) envp, outbuf, sizeof (outbuf),
1360 errbuf, sizeof (errbuf));
1362 for (i = 0; i < envc; i++)
1363 FREE(envp[i]);
1364 if (envp)
1365 FREE(envp);
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;
1373 /* chomp the result */
1374 for (ptr = outbuf; *ptr; ptr++)
1375 if (*ptr == '\n' || *ptr == '\r') {
1376 *ptr = '\0';
1377 break;
1379 valuep->t = STRING;
1380 valuep->v = (uintptr_t)stable(outbuf);
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);
1390 for (i = 0; i < argc; i++)
1391 FREE(argv[i]);
1392 FREE(argv);
1394 return (ret);
1398 * platform_confcall -- call a configuration database function
1400 * returns result in *valuep, return 0 on success
1402 /*ARGSUSED*/
1404 platform_confcall(struct node *np, struct lut **globals, struct config *croot,
1405 struct arrow *arrowp, struct evalue *valuep)
1407 outfl(O_ALTFP|O_VERB, np->file, np->line, "unknown confcall");
1408 return (0);
1412 * platform_get_eft_files -- return names of all eft files we should load
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).
1417 char **
1418 platform_get_eft_files(void)
1420 return (platform_get_files_stddirs(".eft", 1));
1423 void
1424 platform_free_eft_files(char **flist)
1426 char **f;
1428 if (flist == NULL || *flist == NULL)
1429 return; /* no files were found so we're done */
1431 f = flist;
1432 while (*f != NULL) {
1433 FREE(*f);
1434 f++;
1436 FREE(flist);
1439 static nvlist_t *payloadnvp = NULL;
1441 void
1442 platform_set_payloadnvp(nvlist_t *nvlp)
1445 * cannot replace a non-NULL payloadnvp with a non-NULL nvlp
1447 ASSERT(payloadnvp != NULL ? nvlp == NULL : 1);
1448 payloadnvp = nvlp;
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.
1456 static int
1457 get_array_info(const char *inputstr, const char **name, unsigned int *index)
1459 char *indexptr, *indexend, *dupname, *endname;
1461 if (strchr(inputstr, '[') == NULL)
1462 return (1);
1464 dupname = STRDUP(inputstr);
1465 indexptr = strchr(dupname, '[');
1466 indexend = strchr(dupname, ']');
1469 * return if array notation is not complete or if index is negative
1471 if (indexend == NULL || indexptr >= indexend ||
1472 strchr(indexptr, '-') != NULL) {
1473 FREE(dupname);
1474 return (1);
1478 * search past any spaces between the name string and '['
1480 endname = indexptr;
1481 while (isspace(*(endname - 1)) && dupname < endname)
1482 endname--;
1483 *endname = '\0';
1484 ASSERT(dupname < endname);
1487 * search until indexptr points to the first digit and indexend
1488 * points to the last digit
1490 while (!isdigit(*indexptr) && indexptr < indexend)
1491 indexptr++;
1492 while (!isdigit(*indexend) && indexptr <= indexend)
1493 indexend--;
1495 *(indexend + 1) = '\0';
1496 *index = (unsigned int)atoi(indexptr);
1498 *name = stable(dupname);
1499 FREE(dupname);
1501 return (0);
1505 * platform_payloadprop -- fetch a payload value
1507 * XXX this function should be replaced and eval_func() should be
1508 * XXX changed to use the more general platform_payloadprop_values().
1511 platform_payloadprop(struct node *np, struct evalue *valuep)
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;
1523 ASSERT(np->t == T_QUOTE);
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);
1531 basenvp = payloadnvp;
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.)
1539 if (strchr(propstr, '.') != NULL) {
1540 nvlist_t **arraynvp;
1541 uint_t nelem;
1542 char *w;
1543 int ier;
1545 nameslist = STRDUP(propstr);
1546 lastnameptr = strtok(nameslist, ".");
1549 * decompose nameslist into its component names while
1550 * extracting the embedded nvlist
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];
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);
1576 lastnameptr = w;
1578 } else {
1579 lastnameptr = propstr;
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);
1587 if (nameslist != NULL)
1588 FREE(nameslist);
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);
1596 if (nameptr == stable(nvpname))
1597 break;
1600 if (nvpair == NULL) {
1601 out(O_ALTFP, "platform_payloadprop: no entry for %s", propstr);
1602 return (1);
1603 } else if (valuep == NULL) {
1605 * caller is interested in the existence of a property with
1606 * this name, regardless of type or value
1608 return (0);
1611 valuep->t = UNDEFINED;
1614 * get to this point if we found an entry. figure out its data
1615 * type and copy its value.
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);
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1810 default :
1811 out(O_ALTFP|O_VERB2,
1812 "platform_payloadprop: unsupported data type for %s",
1813 propstr);
1814 return (1);
1817 return (0);
1819 invalid:
1820 out(O_ALTFP|O_VERB2,
1821 "platform_payloadprop: invalid array reference for %s", propstr);
1822 return (1);
1825 /*ARGSUSED*/
1827 platform_path_exists(nvlist_t *fmri)
1829 return (fmd_nvl_fmri_present(Hdl, fmri));
1832 struct evalue *
1833 platform_payloadprop_values(const char *propstr, int *nvals)
1835 struct evalue *retvals;
1836 nvlist_t *basenvp;
1837 nvpair_t *nvpair;
1838 char *nvpname;
1840 *nvals = 0;
1842 if (payloadnvp == NULL)
1843 return (NULL);
1845 basenvp = payloadnvp;
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);
1853 if (strcmp(propstr, nvpname) == 0)
1854 break;
1857 if (nvpair == NULL)
1858 return (NULL); /* property not found */
1860 switch (nvpair_type(nvpair)) {
1861 case DATA_TYPE_NVLIST: {
1862 nvlist_t *embnvp = NULL;
1863 char *scheme = NULL;
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);
1877 return (NULL);
1879 case DATA_TYPE_NVLIST_ARRAY: {
1880 char *scheme = NULL;
1881 nvlist_t **nvap;
1882 uint_t nel;
1883 int i;
1884 int hccount;
1887 * since we're only willing to handle hc fmri's, we
1888 * must count them first before allocating retvals.
1890 if (nvpair_value_nvlist_array(nvpair, &nvap, &nel) != 0)
1891 return (NULL);
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++;
1902 if (hccount == 0)
1903 return (NULL);
1905 *nvals = hccount;
1906 retvals = MALLOC(sizeof (struct evalue) * hccount);
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++;
1919 return (retvals);
1921 case DATA_TYPE_BOOLEAN:
1922 case DATA_TYPE_BOOLEAN_VALUE: {
1923 boolean_t val;
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);
1932 case DATA_TYPE_BYTE: {
1933 uchar_t val;
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);
1942 case DATA_TYPE_STRING: {
1943 char *val;
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);
1953 case DATA_TYPE_INT8: {
1954 int8_t val;
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);
1963 case DATA_TYPE_UINT8: {
1964 uint8_t val;
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);
1974 case DATA_TYPE_INT16: {
1975 int16_t val;
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);
1984 case DATA_TYPE_UINT16: {
1985 uint16_t val;
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);
1995 case DATA_TYPE_INT32: {
1996 int32_t val;
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);
2005 case DATA_TYPE_UINT32: {
2006 uint32_t val;
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);
2016 case DATA_TYPE_INT64: {
2017 int64_t val;
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);
2026 case DATA_TYPE_UINT64: {
2027 uint64_t val;
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);
2037 case DATA_TYPE_BOOLEAN_ARRAY: {
2038 boolean_t *val;
2039 uint_t nel;
2040 int i;
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];
2049 return (retvals);
2051 case DATA_TYPE_BYTE_ARRAY: {
2052 uchar_t *val;
2053 uint_t nel;
2054 int i;
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];
2063 return (retvals);
2065 case DATA_TYPE_STRING_ARRAY: {
2066 char **val;
2067 uint_t nel;
2068 int i;
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]);
2077 return (retvals);
2080 case DATA_TYPE_INT8_ARRAY: {
2081 int8_t *val;
2082 uint_t nel;
2083 int i;
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];
2092 return (retvals);
2094 case DATA_TYPE_UINT8_ARRAY: {
2095 uint8_t *val;
2096 uint_t nel;
2097 int i;
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];
2106 return (retvals);
2108 case DATA_TYPE_INT16_ARRAY: {
2109 int16_t *val;
2110 uint_t nel;
2111 int i;
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];
2120 return (retvals);
2122 case DATA_TYPE_UINT16_ARRAY: {
2123 uint16_t *val;
2124 uint_t nel;
2125 int i;
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];
2134 return (retvals);
2136 case DATA_TYPE_INT32_ARRAY: {
2137 int32_t *val;
2138 uint_t nel;
2139 int i;
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];
2148 return (retvals);
2150 case DATA_TYPE_UINT32_ARRAY: {
2151 uint32_t *val;
2152 uint_t nel;
2153 int i;
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];
2162 return (retvals);
2164 case DATA_TYPE_INT64_ARRAY: {
2165 int64_t *val;
2166 uint_t nel;
2167 int i;
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];
2176 return (retvals);
2178 case DATA_TYPE_UINT64_ARRAY: {
2179 uint64_t *val;
2180 uint_t nel;
2181 int i;
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];
2190 return (retvals);
2195 return (NULL);
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.
2203 const struct ipath *
2204 platform_fault2ipath(nvlist_t *flt)
2206 nvlist_t *rsrc;
2207 struct node *np;
2208 char *scheme;
2209 const struct ipath *ip;
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);
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);
2226 if ((np = hc_fmri_nodeize(rsrc)) == NULL)
2227 return (NULL); /* nodeize will already have whinged */
2229 ip = ipath(np);
2230 tree_free(np);
2231 return (ip);