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