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