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