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