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