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