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