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