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