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