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