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