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