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