1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/fm/protocol.h> 30 #include <fm/libtopo.h> 31 #include <ctype.h> 32 #include <fnmatch.h> 33 #include <limits.h> 34 #include <strings.h> 35 #include <stdio.h> 36 #include <errno.h> 37 #include <umem.h> 38 #include <sys/param.h> 39 40 #define FMTOPO_EXIT_SUCCESS 0 41 #define FMTOPO_EXIT_ERROR 1 42 #define FMTOPO_EXIT_USAGE 2 43 44 #define STDERR "stderr" 45 #define DOTS "..." 46 #define ALL "all" 47 48 static const char *g_pname; 49 static const char *g_fmri = NULL; 50 51 static const char *opt_R = "/"; 52 static const char *opt_s = FM_FMRI_SCHEME_HC; 53 static const char optstr[] = "aCdeP:pR:s:StvVx"; 54 55 static int opt_e = 0; 56 static int opt_d = 0; 57 static int opt_V = 0; 58 static int opt_p = 0; 59 static int opt_S = 0; 60 static int opt_t = 0; 61 static int opt_x = 0; 62 static int opt_all = 0; 63 64 struct prop_args { 65 const char *group; 66 const char *prop; 67 const char *type; 68 const char *value; 69 }; 70 71 static struct prop_args **pargs = NULL; 72 static int pcnt = 0; 73 74 static int 75 usage(FILE *fp) 76 { 77 (void) fprintf(fp, 78 "Usage: %s [-CedpSVx] [-P group.property[=type:value]] " 79 "[-R root] [-s scheme] [fmri]\n", g_pname); 80 81 (void) fprintf(fp, 82 "\t-C dump core after completing execution\n" 83 "\t-d set debug mode for libtopo modules\n" 84 "\t-e display FMRIs as paths using esc/eft notation\n" 85 "\t-P get/set specified properties\n" 86 "\t-p display of FMRI protocol properties\n" 87 "\t-R set root directory for libtopo plug-ins and other files\n" 88 "\t-s display topology for the specified FMRI scheme\n" 89 "\t-S display FMRI status (present/usable)\n" 90 "\t-V set verbose mode\n" 91 "\t-x display a xml formatted topology\n"); 92 93 return (FMTOPO_EXIT_USAGE); 94 } 95 96 static topo_type_t 97 str2type(const char *tstr) 98 { 99 topo_type_t type; 100 101 if (tstr == NULL) 102 return (TOPO_TYPE_INVALID); 103 104 if (strcmp(tstr, "int32") == 0) 105 type = TOPO_TYPE_INT32; 106 else if (strcmp(tstr, "uint32") == 0) 107 type = TOPO_TYPE_UINT32; 108 else if (strcmp(tstr, "int64") == 0) 109 type = TOPO_TYPE_INT64; 110 else if (strcmp(tstr, "uint64") == 0) 111 type = TOPO_TYPE_UINT64; 112 else if (strcmp(tstr, "string") == 0) 113 type = TOPO_TYPE_STRING; 114 else if (strcmp(tstr, "fmri") == 0) 115 type = TOPO_TYPE_FMRI; 116 else { 117 type = TOPO_TYPE_INVALID; 118 } 119 120 return (type); 121 } 122 123 static void 124 print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri) 125 { 126 int err, ret; 127 128 (void) printf("%s\n", (char *)fmri); 129 130 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { 131 char *aname = NULL, *fname = NULL, *lname = NULL; 132 nvlist_t *asru = NULL; 133 nvlist_t *fru = NULL; 134 135 if (topo_node_asru(node, &asru, NULL, &err) == 0) 136 (void) topo_fmri_nvl2str(thp, asru, &aname, &err); 137 if (topo_node_fru(node, &fru, NULL, &err) == 0) 138 (void) topo_fmri_nvl2str(thp, fru, &fname, &err); 139 (void) topo_node_label(node, &lname, &err); 140 if (aname != NULL) { 141 nvlist_free(asru); 142 (void) printf("\tASRU: %s\n", aname); 143 topo_hdl_strfree(thp, aname); 144 } else { 145 (void) printf("\tASRU: -\n"); 146 } 147 if (fname != NULL) { 148 nvlist_free(fru); 149 (void) printf("\tFRU: %s\n", fname); 150 topo_hdl_strfree(thp, fname); 151 } else { 152 (void) printf("\tFRU: -\n"); 153 } 154 if (lname != NULL) { 155 (void) printf("\tLabel: %s\n", lname); 156 topo_hdl_strfree(thp, lname); 157 } else { 158 (void) printf("\tLabel: -\n"); 159 } 160 } 161 162 if (opt_S) { 163 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) 164 (void) printf("\tPresent: -\n"); 165 else 166 (void) printf("\tPresent: %s\n", 167 ret ? "true" : "false"); 168 169 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) 170 (void) printf("\tUnusable: -\n"); 171 else 172 (void) printf("\tUnusable: %s\n", 173 ret ? "true" : "false"); 174 } 175 } 176 177 static void 178 print_everstyle(tnode_t *node) 179 { 180 char buf[PATH_MAX], numbuf[64]; 181 nvlist_t *fmri, **hcl; 182 int i, err; 183 uint_t n; 184 185 if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, 186 TOPO_PROP_RESOURCE, &fmri, &err) < 0) { 187 (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n", 188 g_pname, topo_node_name(node), 189 topo_node_instance(node), topo_strerror(err)); 190 return; 191 } 192 193 if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &n) != 0) { 194 (void) fprintf(stderr, "%s: failed to find %s for %s=%d\n", 195 g_pname, FM_FMRI_HC_LIST, topo_node_name(node), 196 topo_node_instance(node)); 197 return; 198 } 199 200 buf[0] = '\0'; 201 202 for (i = 0; i < n; i++) { 203 char *name, *inst, *estr; 204 ulong_t ul; 205 206 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0 || 207 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &inst) != 0) { 208 (void) fprintf(stderr, "%s: failed to get " 209 "name-instance for %s=%d\n", g_pname, 210 topo_node_name(node), topo_node_instance(node)); 211 return; 212 } 213 214 errno = 0; 215 ul = strtoul(inst, &estr, 10); 216 217 if (errno != 0 || estr == inst) { 218 (void) fprintf(stderr, "%s: instance %s does not " 219 "convert to an unsigned integer\n", g_pname, inst); 220 } 221 222 (void) strlcat(buf, "/", sizeof (buf)); 223 (void) strlcat(buf, name, sizeof (buf)); 224 (void) snprintf(numbuf, sizeof (numbuf), "%u", ul); 225 (void) strlcat(buf, numbuf, sizeof (buf)); 226 } 227 228 (void) printf("%s\n", buf); 229 } 230 231 static void 232 print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl) 233 { 234 int err; 235 topo_type_t type; 236 char *tstr, *propn, buf[48]; 237 nvpair_t *pv_nvp; 238 int i; 239 uint_t nelem; 240 241 if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL) 242 return; 243 244 /* Print property name */ 245 if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL || 246 nvpair_name(pv_nvp) == NULL || 247 strcmp(TOPO_PROP_VAL_NAME, nvpair_name(pv_nvp)) != 0) { 248 (void) fprintf(stderr, "%s: malformed property name\n", 249 g_pname); 250 return; 251 } else { 252 (void) nvpair_value_string(pv_nvp, &propn); 253 } 254 255 if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL || 256 nvpair_name(pv_nvp) == NULL || 257 strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 || 258 nvpair_type(pv_nvp) != DATA_TYPE_UINT32) { 259 (void) fprintf(stderr, "%s: malformed property type for %s\n", 260 g_pname, propn); 261 return; 262 } else { 263 (void) nvpair_value_uint32(pv_nvp, (uint32_t *)&type); 264 } 265 266 switch (type) { 267 case TOPO_TYPE_BOOLEAN: tstr = "boolean"; break; 268 case TOPO_TYPE_INT32: tstr = "int32"; break; 269 case TOPO_TYPE_UINT32: tstr = "uint32"; break; 270 case TOPO_TYPE_INT64: tstr = "int64"; break; 271 case TOPO_TYPE_UINT64: tstr = "uint64"; break; 272 case TOPO_TYPE_STRING: tstr = "string"; break; 273 case TOPO_TYPE_FMRI: tstr = "fmri"; break; 274 case TOPO_TYPE_INT32_ARRAY: tstr = "int32[]"; break; 275 case TOPO_TYPE_UINT32_ARRAY: tstr = "uint32[]"; break; 276 case TOPO_TYPE_INT64_ARRAY: tstr = "int64[]"; break; 277 case TOPO_TYPE_UINT64_ARRAY: tstr = "uint64[]"; break; 278 case TOPO_TYPE_STRING_ARRAY: tstr = "string[]"; break; 279 case TOPO_TYPE_FMRI_ARRAY: tstr = "fmri[]"; break; 280 default: tstr = "unknown type"; 281 } 282 283 printf(" %-17s %-8s ", propn, tstr); 284 285 /* 286 * Get property value 287 */ 288 if (nvpair_name(pv_nvp) == NULL || 289 (pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL) { 290 (void) fprintf(stderr, "%s: malformed property value\n", 291 g_pname); 292 return; 293 } 294 295 switch (nvpair_type(pv_nvp)) { 296 case DATA_TYPE_INT32: { 297 int32_t val; 298 (void) nvpair_value_int32(pv_nvp, &val); 299 (void) printf(" %d", val); 300 break; 301 } 302 case DATA_TYPE_UINT32: { 303 uint32_t val; 304 (void) nvpair_value_uint32(pv_nvp, &val); 305 (void) printf(" 0x%x", val); 306 break; 307 } 308 case DATA_TYPE_INT64: { 309 int64_t val; 310 (void) nvpair_value_int64(pv_nvp, &val); 311 (void) printf(" %lld", (longlong_t)val); 312 break; 313 } 314 case DATA_TYPE_UINT64: { 315 uint64_t val; 316 (void) nvpair_value_uint64(pv_nvp, &val); 317 (void) printf(" 0x%llx", (u_longlong_t)val); 318 break; 319 } 320 case DATA_TYPE_STRING: { 321 char *val; 322 (void) nvpair_value_string(pv_nvp, &val); 323 if (!opt_V && strlen(val) > 48) { 324 (void) snprintf(buf, 48, "%s...", val); 325 (void) printf(" %s", buf); 326 } else { 327 (void) printf(" %s", val); 328 } 329 break; 330 } 331 case DATA_TYPE_NVLIST: { 332 nvlist_t *val; 333 char *fmri; 334 (void) nvpair_value_nvlist(pv_nvp, &val); 335 if (topo_fmri_nvl2str(thp, val, &fmri, &err) != 0) { 336 if (opt_V) 337 nvlist_print(stdout, nvl); 338 break; 339 } 340 341 if (!opt_V && strlen(fmri) > 48) { 342 (void) snprintf(buf, 48, "%s", fmri); 343 (void) snprintf(&buf[45], 4, "%s", DOTS); 344 (void) printf(" %s", buf); 345 } else { 346 (void) printf(" %s", fmri); 347 } 348 349 topo_hdl_strfree(thp, fmri); 350 break; 351 } 352 case DATA_TYPE_UINT32_ARRAY: { 353 uint32_t *val; 354 355 (void) nvpair_value_uint32_array(pv_nvp, &val, &nelem); 356 (void) printf(" [ "); 357 for (i = 0; i < nelem; i++) 358 (void) printf("%u ", val[i]); 359 (void) printf("]"); 360 break; 361 } 362 default: 363 (void) fprintf(stderr, " unknown data type (%d)", 364 nvpair_type(pv_nvp)); 365 break; 366 } 367 (void) printf("\n"); 368 } 369 370 static void 371 print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab, 372 char *nstab, int32_t version) 373 { 374 int err; 375 char buf[30]; 376 topo_pgroup_info_t *pgi = NULL; 377 378 if (pgn == NULL) 379 return; 380 381 if (node != NULL && (dstab == NULL || nstab == NULL || version == -1)) { 382 if ((pgi = topo_pgroup_info(node, pgn, &err)) != NULL) { 383 dstab = (char *)topo_stability2name(pgi->tpi_datastab); 384 nstab = (char *)topo_stability2name(pgi->tpi_namestab); 385 version = pgi->tpi_version; 386 } 387 } 388 389 if (dstab == NULL || nstab == NULL || version == -1) { 390 printf(" group: %-30s version: - stability: -/-\n", pgn); 391 } else if (!opt_V && strlen(pgn) > 30) { 392 (void) snprintf(buf, 26, "%s", pgn); 393 (void) snprintf(&buf[27], 4, "%s", DOTS); 394 printf(" group: %-30s version: %-3d stability: %s/%s\n", 395 buf, version, nstab, dstab); 396 } else { 397 printf(" group: %-30s version: %-3d stability: %s/%s\n", 398 pgn, version, nstab, dstab); 399 } 400 401 if (pgi != NULL) { 402 topo_hdl_strfree(thp, (char *)pgi->tpi_name); 403 topo_hdl_free(thp, pgi, sizeof (topo_pgroup_info_t)); 404 } 405 } 406 407 static void 408 print_all_props(topo_hdl_t *thp, tnode_t *node, nvlist_t *p_nv, 409 const char *group) 410 { 411 char *pgn = NULL, *dstab = NULL, *nstab = NULL; 412 int32_t version; 413 nvlist_t *pg_nv, *pv_nv; 414 nvpair_t *nvp, *pg_nvp; 415 int pg_done, match, all = strcmp(group, ALL) == 0; 416 417 for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL; 418 nvp = nvlist_next_nvpair(p_nv, nvp)) { 419 if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 || 420 nvpair_type(nvp) != DATA_TYPE_NVLIST) 421 continue; 422 423 nstab = NULL; 424 dstab = NULL; 425 version = -1; 426 pg_done = match = 0; 427 (void) nvpair_value_nvlist(nvp, &pg_nv); 428 for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL; 429 pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) { 430 /* 431 * Print property group name and stability levels 432 */ 433 if (strcmp(TOPO_PROP_GROUP_NAME, nvpair_name(pg_nvp)) 434 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 435 (void) nvpair_value_string(pg_nvp, &pgn); 436 match = strcmp(group, pgn) == 0; 437 continue; 438 } 439 440 if (strcmp(TOPO_PROP_GROUP_NSTAB, 441 nvpair_name(pg_nvp)) == 0 && 442 nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 443 (void) nvpair_value_string(pg_nvp, &nstab); 444 continue; 445 } 446 447 if (strcmp(TOPO_PROP_GROUP_DSTAB, 448 nvpair_name(pg_nvp)) == 0 && 449 nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 450 (void) nvpair_value_string(pg_nvp, &dstab); 451 continue; 452 } 453 454 if (strcmp(TOPO_PROP_GROUP_VERSION, 455 nvpair_name(pg_nvp)) == 0 && 456 nvpair_type(pg_nvp) == DATA_TYPE_INT32) { 457 (void) nvpair_value_int32(pg_nvp, &version); 458 continue; 459 } 460 461 if ((match || all) && !pg_done) { 462 print_pgroup(thp, node, pgn, dstab, nstab, 463 version); 464 pg_done++; 465 } 466 467 /* 468 * Print property group and property name-value pair 469 */ 470 if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) 471 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) { 472 (void) nvpair_value_nvlist(pg_nvp, &pv_nv); 473 if ((match || all) && pg_done) { 474 print_prop_nameval(thp, pv_nv); 475 } 476 477 } 478 479 } 480 if (match && !all) 481 return; 482 } 483 } 484 485 static void 486 set_prop(topo_hdl_t *thp, tnode_t *node, nvlist_t *fmri, struct prop_args *pp) 487 { 488 int ret, err = 0; 489 topo_type_t type; 490 nvlist_t *nvl, *f = NULL; 491 char *end; 492 493 if (pp->prop == NULL || pp->type == NULL || pp->value == NULL) 494 return; 495 496 if ((type = str2type(pp->type)) == TOPO_TYPE_INVALID) { 497 (void) fprintf(stderr, "%s: invalid property type %s for %s\n", 498 g_pname, pp->type, pp->prop); 499 return; 500 } 501 502 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 503 (void) fprintf(stderr, "%s: nvlist allocation failed for " 504 "%s=%s:%s\n", g_pname, pp->prop, pp->type, pp->value); 505 return; 506 } 507 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pp->prop); 508 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type); 509 if (ret != 0) { 510 (void) fprintf(stderr, "%s: invalid property type %s for %s\n", 511 g_pname, pp->type, pp->prop); 512 nvlist_free(nvl); 513 return; 514 } 515 516 errno = 0; 517 switch (type) { 518 case TOPO_TYPE_INT32: 519 { 520 int32_t val; 521 522 val = strtol(pp->value, &end, 0); 523 if (errno == ERANGE) { 524 ret = -1; 525 break; 526 } 527 ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val); 528 break; 529 } 530 case TOPO_TYPE_UINT32: 531 { 532 uint32_t val; 533 534 val = strtoul(pp->value, &end, 0); 535 if (errno == ERANGE) { 536 ret = -1; 537 break; 538 } 539 ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val); 540 break; 541 } 542 case TOPO_TYPE_INT64: 543 { 544 int64_t val; 545 546 val = strtoll(pp->value, &end, 0); 547 if (errno == ERANGE) { 548 ret = -1; 549 break; 550 } 551 ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val); 552 break; 553 } 554 case TOPO_TYPE_UINT64: 555 { 556 uint64_t val; 557 558 val = strtoull(pp->value, &end, 0); 559 if (errno == ERANGE) { 560 ret = -1; 561 break; 562 } 563 ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val); 564 break; 565 } 566 case TOPO_TYPE_STRING: 567 { 568 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, 569 pp->value); 570 break; 571 } 572 case TOPO_TYPE_FMRI: 573 { 574 if ((ret = topo_fmri_str2nvl(thp, pp->value, &f, &err)) 575 < 0) 576 break; 577 578 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, 579 f)) != 0) 580 err = ETOPO_PROP_NVL; 581 break; 582 } 583 default: 584 ret = -1; 585 } 586 587 if (ret != 0) { 588 (void) fprintf(stderr, "%s: unable to set property value for " 589 "%s: %s\n", g_pname, pp->prop, topo_strerror(err)); 590 nvlist_free(nvl); 591 return; 592 } 593 594 if (node != NULL) { 595 if (topo_prop_setprop(node, pp->group, nvl, TOPO_PROP_MUTABLE, 596 f, &ret) < 0) { 597 (void) fprintf(stderr, "%s: unable to set property " 598 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop, 599 pp->type, pp->value, topo_strerror(ret)); 600 nvlist_free(nvl); 601 nvlist_free(f); 602 return; 603 } 604 } else { 605 if (topo_fmri_setprop(thp, fmri, pp->group, nvl, 606 TOPO_PROP_MUTABLE, f, &ret) < 0) { 607 (void) fprintf(stderr, "%s: unable to set property " 608 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop, 609 pp->type, pp->value, topo_strerror(ret)); 610 nvlist_free(nvl); 611 nvlist_free(f); 612 return; 613 } 614 } 615 616 nvlist_free(nvl); 617 618 /* 619 * Now, get the property back for printing 620 */ 621 if (node != NULL) { 622 if (topo_prop_getprop(node, pp->group, pp->prop, f, &nvl, 623 &err) < 0) { 624 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n", 625 g_pname, pp->group, pp->prop, topo_strerror(err)); 626 nvlist_free(f); 627 return; 628 } 629 } else { 630 if (topo_fmri_getprop(thp, fmri, pp->group, pp->prop, 631 f, &nvl, &err) < 0) { 632 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n", 633 g_pname, pp->group, pp->prop, topo_strerror(err)); 634 nvlist_free(f); 635 return; 636 } 637 } 638 639 print_pgroup(thp, node, pp->group, NULL, NULL, 0); 640 print_prop_nameval(thp, nvl); 641 nvlist_free(nvl); 642 643 nvlist_free(f); 644 } 645 646 static void 647 print_props(topo_hdl_t *thp, tnode_t *node) 648 { 649 int i, err; 650 nvlist_t *nvl; 651 struct prop_args *pp; 652 653 if (pcnt == 0) 654 return; 655 656 for (i = 0; i < pcnt; ++i) { 657 pp = pargs[i]; 658 659 if (pp->group == NULL) 660 continue; 661 662 /* 663 * If we have a valid value, this is a request to 664 * set a property. Otherwise, just print the property 665 * group and any specified properties. 666 */ 667 if (pp->value == NULL) { 668 if (pp->prop == NULL) { 669 670 /* 671 * Print all properties in this group 672 */ 673 if ((nvl = topo_prop_getprops(node, &err)) 674 == NULL) { 675 (void) fprintf(stderr, "%s: failed to " 676 "get %s: %s\n", g_pname, 677 pp->group, 678 topo_strerror(err)); 679 continue; 680 } else { 681 print_all_props(thp, node, nvl, 682 pp->group); 683 nvlist_free(nvl); 684 continue; 685 } 686 } 687 if (topo_prop_getprop(node, pp->group, pp->prop, 688 NULL, &nvl, &err) < 0) { 689 (void) fprintf(stderr, "%s: failed to get " 690 "%s.%s: %s\n", g_pname, 691 pp->group, pp->prop, 692 topo_strerror(err)); 693 continue; 694 } else { 695 print_pgroup(thp, node, pp->group, NULL, 696 NULL, 0); 697 print_prop_nameval(thp, nvl); 698 nvlist_free(nvl); 699 } 700 } else { 701 set_prop(thp, node, NULL, pp); 702 } 703 } 704 } 705 706 /*ARGSUSED*/ 707 static int 708 walk_node(topo_hdl_t *thp, tnode_t *node, void *arg) 709 { 710 int err; 711 nvlist_t *nvl; 712 nvlist_t *rsrc; 713 char *s; 714 715 if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { 716 print_everstyle(node); 717 return (TOPO_WALK_NEXT); 718 } 719 720 if (topo_node_resource(node, &rsrc, &err) < 0) { 721 (void) fprintf(stderr, "%s: failed to get resource: " 722 "%s", g_pname, topo_strerror(err)); 723 return (TOPO_WALK_NEXT); 724 } 725 if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) { 726 (void) fprintf(stderr, "%s: failed to convert " 727 "resource to FMRI string: %s", g_pname, 728 topo_strerror(err)); 729 nvlist_free(rsrc); 730 return (TOPO_WALK_NEXT); 731 } 732 733 if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) { 734 nvlist_free(rsrc); 735 topo_hdl_strfree(thp, s); 736 return (TOPO_WALK_NEXT); 737 } 738 739 print_node(thp, node, rsrc, s); 740 topo_hdl_strfree(thp, s); 741 nvlist_free(rsrc); 742 743 if (opt_V || opt_all) { 744 if ((nvl = topo_prop_getprops(node, &err)) == NULL) { 745 (void) fprintf(stderr, "%s: failed to get " 746 "properties for %s=%d: %s\n", g_pname, 747 topo_node_name(node), topo_node_instance(node), 748 topo_strerror(err)); 749 } else { 750 print_all_props(thp, node, nvl, ALL); 751 nvlist_free(nvl); 752 } 753 } else if (pcnt > 0) { 754 print_props(thp, node); 755 } 756 757 printf("\n"); 758 759 return (TOPO_WALK_NEXT); 760 } 761 762 static void 763 get_pargs(int argc, char *argv[]) 764 { 765 struct prop_args *pp; 766 char c, *s, *p; 767 int i = 0; 768 769 if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) { 770 (void) fprintf(stderr, "%s: failed to allocate property " 771 "arguments\n", g_pname); 772 return; 773 } 774 775 for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) { 776 if (c == 'P') { 777 778 if (strcmp(optarg, ALL) == 0) { 779 opt_all++; 780 break; 781 } 782 783 if ((pp = pargs[i] = malloc(sizeof (struct prop_args))) 784 == NULL) { 785 (void) fprintf(stderr, "%s: failed to " 786 "allocate propertyarguments\n", g_pname); 787 return; 788 } 789 ++i; 790 pp->group = NULL; 791 pp->prop = NULL; 792 pp->type = NULL; 793 pp->value = NULL; 794 795 p = optarg; 796 if ((s = strchr(p, '.')) != NULL) { 797 *s++ = '\0'; /* strike out delimiter */ 798 pp->group = p; 799 p = s; 800 if ((s = strchr(p, '=')) != NULL) { 801 *s++ = '\0'; /* strike out delimiter */ 802 pp->prop = p; 803 p = s; 804 if ((s = strchr(p, ':')) != NULL) { 805 *s++ = '\0'; 806 pp->type = p; 807 pp->value = s; 808 } else { 809 (void) fprintf(stderr, "%s: " 810 "property type not " 811 "specified for assignment " 812 " of %s.%s\n", g_pname, 813 pp->group, pp->prop); 814 break; 815 } 816 } else { 817 pp->prop = p; 818 } 819 } else { 820 pp->group = p; 821 } 822 if (i >= pcnt) 823 break; 824 } 825 } 826 827 if (opt_all > 0) { 828 int j; 829 830 for (j = 0; j < i; ++j) 831 free(pargs[i]); 832 free(pargs); 833 pargs = NULL; 834 } 835 } 836 837 static int 838 walk_topo(topo_hdl_t *thp, char *uuid) 839 { 840 int err; 841 topo_walk_t *twp; 842 843 if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err)) 844 == NULL) { 845 (void) fprintf(stderr, "%s: failed to walk %s topology:" 846 " %s\n", g_pname, opt_s, topo_strerror(err)); 847 848 return (-1); 849 } 850 851 /* 852 * Print standard header 853 */ 854 if (!opt_e) { 855 char buf[32]; 856 time_t tod = time(NULL); 857 858 printf("TIME UUID\n"); 859 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); 860 (void) printf("%-15s %-32s\n", buf, uuid); 861 (void) printf("\n"); 862 } 863 864 if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { 865 (void) fprintf(stderr, "%s: failed to walk topology\n", 866 g_pname); 867 topo_walk_fini(twp); 868 return (-1); 869 } 870 871 topo_walk_fini(twp); 872 873 return (0); 874 } 875 876 static void 877 print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl) 878 { 879 char *dstab = NULL, *nstab = NULL; 880 int32_t version = -1; 881 nvlist_t *pnvl; 882 nvpair_t *pnvp; 883 884 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab); 885 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab); 886 (void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version); 887 888 print_pgroup(thp, NULL, pgn, dstab, nstab, version); 889 890 for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL; 891 pnvp = nvlist_next_nvpair(nvl, pnvp)) { 892 893 /* 894 * Print property group and property name-value pair 895 */ 896 if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp)) 897 == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) { 898 (void) nvpair_value_nvlist(pnvp, &pnvl); 899 print_prop_nameval(thp, pnvl); 900 901 } 902 903 } 904 } 905 906 static void 907 print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl) 908 { 909 int i, err; 910 struct prop_args *pp; 911 nvlist_t *pnvl; 912 913 for (i = 0; i < pcnt; ++i) { 914 pp = pargs[i]; 915 916 if (pp->group == NULL) 917 continue; 918 919 pnvl = NULL; 920 921 /* 922 * If we have a valid value, this is a request to 923 * set a property. Otherwise, just print the property 924 * group and any specified properties. 925 */ 926 if (pp->value == NULL) { 927 if (pp->prop == NULL) { 928 929 /* 930 * Print all properties in this group 931 */ 932 if (topo_fmri_getpgrp(thp, nvl, pp->group, 933 &pnvl, &err) < 0) { 934 (void) fprintf(stderr, "%s: failed to " 935 "get group %s: %s\n", g_pname, 936 pp->group, topo_strerror(err)); 937 continue; 938 } else { 939 print_fmri_pgroup(thp, pp->group, pnvl); 940 nvlist_free(pnvl); 941 continue; 942 } 943 } 944 if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop, 945 NULL, &pnvl, &err) < 0) { 946 (void) fprintf(stderr, "%s: failed to get " 947 "%s.%s: %s\n", g_pname, 948 pp->group, pp->prop, 949 topo_strerror(err)); 950 continue; 951 } else { 952 print_fmri_pgroup(thp, pp->group, pnvl); 953 print_prop_nameval(thp, pnvl); 954 nvlist_free(nvl); 955 } 956 } else { 957 set_prop(thp, NULL, nvl, pp); 958 } 959 } 960 } 961 962 void 963 print_fmri(topo_hdl_t *thp, char *uuid) 964 { 965 int ret, err; 966 nvlist_t *nvl; 967 char buf[32]; 968 time_t tod = time(NULL); 969 970 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { 971 (void) fprintf(stderr, "%s: failed to convert %s to nvlist: " 972 "%s\n", g_pname, g_fmri, topo_strerror(err)); 973 return; 974 } 975 976 printf("TIME UUID\n"); 977 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); 978 (void) printf("%-15s %-32s\n", buf, uuid); 979 (void) printf("\n"); 980 981 (void) printf("%s\n", (char *)g_fmri); 982 983 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { 984 char *aname = NULL, *fname = NULL, *lname = NULL; 985 nvlist_t *asru = NULL; 986 nvlist_t *fru = NULL; 987 988 if (topo_fmri_asru(thp, nvl, &asru, &err) == 0) 989 (void) topo_fmri_nvl2str(thp, asru, &aname, &err); 990 if (topo_fmri_fru(thp, nvl, &fru, &err) == 0) 991 (void) topo_fmri_nvl2str(thp, fru, &fname, &err); 992 (void) topo_fmri_label(thp, nvl, &lname, &err); 993 994 nvlist_free(fru); 995 nvlist_free(asru); 996 997 if (aname != NULL) { 998 (void) printf("\tASRU: %s\n", aname); 999 topo_hdl_strfree(thp, aname); 1000 } else { 1001 (void) printf("\tASRU: -\n"); 1002 } 1003 if (fname != NULL) { 1004 (void) printf("\tFRU: %s\n", fname); 1005 topo_hdl_strfree(thp, fname); 1006 } else { 1007 (void) printf("\tFRU: -\n"); 1008 } 1009 if (lname != NULL) { 1010 (void) printf("\tLabel: %s\n", lname); 1011 topo_hdl_strfree(thp, lname); 1012 } else { 1013 (void) printf("\tLabel: -\n"); 1014 } 1015 } 1016 1017 if (opt_S) { 1018 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { 1019 (void) printf("\tPresent: -\n"); 1020 (void) printf("\tUnusable: -\n"); 1021 return; 1022 } 1023 1024 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) 1025 (void) printf("\tPresent: -\n"); 1026 else 1027 (void) printf("\tPresent: %s\n", 1028 ret ? "true" : "false"); 1029 1030 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) 1031 (void) printf("\tUnusable: -\n"); 1032 else 1033 (void) printf("\tUnusable: %s\n", 1034 ret ? "true" : "false"); 1035 1036 nvlist_free(nvl); 1037 } 1038 1039 if (pcnt > 0) 1040 print_fmri_props(thp, nvl); 1041 } 1042 1043 int 1044 fmtopo_exit(topo_hdl_t *thp, char *uuid, int err) 1045 { 1046 if (uuid != NULL) 1047 topo_hdl_strfree(thp, uuid); 1048 1049 if (thp != NULL) { 1050 topo_snap_release(thp); 1051 topo_close(thp); 1052 } 1053 1054 if (pargs) { 1055 int i; 1056 for (i = 0; i < pcnt; ++i) 1057 free(pargs[i]); 1058 free(pargs); 1059 } 1060 1061 return (err); 1062 } 1063 1064 int 1065 main(int argc, char *argv[]) 1066 { 1067 topo_hdl_t *thp = NULL; 1068 char *uuid = NULL; 1069 int c, err = 0; 1070 1071 g_pname = argv[0]; 1072 1073 while (optind < argc) { 1074 while ((c = getopt(argc, argv, optstr)) != -1) { 1075 switch (c) { 1076 case 'C': 1077 atexit(abort); 1078 break; 1079 case 'd': 1080 opt_d++; 1081 break; 1082 case 'e': 1083 opt_e++; 1084 break; 1085 case 'P': 1086 pcnt++; 1087 break; 1088 case 'p': 1089 opt_p++; 1090 break; 1091 case 'V': 1092 opt_V++; 1093 break; 1094 case 'R': 1095 opt_R = optarg; 1096 break; 1097 case 's': 1098 opt_s = optarg; 1099 break; 1100 case 'S': 1101 opt_S++; 1102 break; 1103 case 't': 1104 opt_t++; 1105 break; 1106 case 'x': 1107 opt_x++; 1108 break; 1109 default: 1110 return (usage(stderr)); 1111 } 1112 } 1113 1114 if (optind < argc) { 1115 if (g_fmri != NULL) { 1116 (void) fprintf(stderr, "%s: illegal argument " 1117 "-- %s\n", g_pname, argv[optind]); 1118 return (FMTOPO_EXIT_USAGE); 1119 } else { 1120 g_fmri = argv[optind++]; 1121 } 1122 } 1123 } 1124 1125 if (pcnt > 0) 1126 get_pargs(argc, argv); 1127 1128 if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) { 1129 (void) fprintf(stderr, "%s: failed to open topology tree: %s\n", 1130 g_pname, topo_strerror(err)); 1131 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); 1132 } 1133 1134 if (opt_d) 1135 topo_debug_set(thp, "module", "stderr"); 1136 1137 if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) { 1138 (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n", 1139 g_pname, topo_strerror(err)); 1140 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); 1141 } else if (err != 0) { 1142 (void) fprintf(stderr, "%s: topology snapshot incomplete\n", 1143 g_pname); 1144 } 1145 1146 1147 if (opt_x) { 1148 err = 0; 1149 if (topo_xml_print(thp, stdout, opt_s, &err) < 0) 1150 (void) fprintf(stderr, "%s: failed to print xml " 1151 "formatted topology:%s", g_pname, 1152 topo_strerror(err)); 1153 1154 return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR : 1155 FMTOPO_EXIT_SUCCESS)); 1156 } 1157 1158 if (opt_t || walk_topo(thp, uuid) < 0) { 1159 if (g_fmri != NULL) 1160 /* 1161 * Try getting some useful information 1162 */ 1163 print_fmri(thp, uuid); 1164 1165 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); 1166 } 1167 1168 topo_hdl_strfree(thp, uuid); 1169 1170 return (FMTOPO_EXIT_SUCCESS); 1171 } 1172