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