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