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