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) 2019, 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 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, *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 (void) 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 nvlist_free(rsrc); 368 break; 369 } 370 case DATA_TYPE_INT64: { 371 int64_t val; 372 (void) nvpair_value_int64(pv_nvp, &val); 373 (void) printf(" %lld", (longlong_t)val); 374 break; 375 } 376 case DATA_TYPE_UINT64: { 377 uint64_t val; 378 (void) nvpair_value_uint64(pv_nvp, &val); 379 (void) printf(" 0x%llx", (u_longlong_t)val); 380 break; 381 } 382 case DATA_TYPE_DOUBLE: { 383 double val; 384 (void) nvpair_value_double(pv_nvp, &val); 385 (void) printf(" %lf", (double)val); 386 break; 387 } 388 case DATA_TYPE_STRING: { 389 char *val; 390 (void) nvpair_value_string(pv_nvp, &val); 391 (void) printf(" %s", val); 392 break; 393 } 394 case DATA_TYPE_NVLIST: { 395 nvlist_t *val; 396 char *fmri; 397 (void) nvpair_value_nvlist(pv_nvp, &val); 398 if (topo_fmri_nvl2str(thp, val, &fmri, &err) != 0) { 399 (void) fprintf(stderr, "failed to convert " 400 "FMRI to string: (%s)\n", 401 topo_strerror(err)); 402 nvlist_print(stdout, nvl); 403 break; 404 } 405 (void) printf(" %s", fmri); 406 topo_hdl_strfree(thp, fmri); 407 break; 408 } 409 case DATA_TYPE_INT32_ARRAY: { 410 int32_t *val; 411 412 (void) nvpair_value_int32_array(pv_nvp, &val, &nelem); 413 (void) printf(" [ "); 414 for (i = 0; i < nelem; i++) 415 (void) printf("%d ", val[i]); 416 (void) printf("]"); 417 break; 418 } 419 case DATA_TYPE_UINT32_ARRAY: { 420 uint32_t *val; 421 422 (void) nvpair_value_uint32_array(pv_nvp, &val, &nelem); 423 (void) printf(" [ "); 424 for (i = 0; i < nelem; i++) 425 (void) printf("%u ", val[i]); 426 (void) printf("]"); 427 break; 428 } 429 case DATA_TYPE_INT64_ARRAY: { 430 int64_t *val; 431 432 (void) nvpair_value_int64_array(pv_nvp, &val, &nelem); 433 (void) printf(" [ "); 434 for (i = 0; i < nelem; i++) 435 (void) printf("%lld ", val[i]); 436 (void) printf("]"); 437 break; 438 } 439 case DATA_TYPE_UINT64_ARRAY: { 440 uint64_t *val; 441 442 (void) nvpair_value_uint64_array(pv_nvp, &val, &nelem); 443 (void) printf(" [ "); 444 for (i = 0; i < nelem; i++) 445 (void) printf("%llu ", val[i]); 446 (void) printf("]"); 447 break; 448 } 449 case DATA_TYPE_STRING_ARRAY: { 450 char **val; 451 452 (void) nvpair_value_string_array(pv_nvp, &val, &nelem); 453 (void) printf(" [ "); 454 for (i = 0; i < nelem; i++) 455 (void) printf("\"%s\" ", val[i]); 456 (void) printf("]"); 457 break; 458 } 459 case DATA_TYPE_NVLIST_ARRAY: { 460 nvlist_t **val; 461 char *fmri; 462 int ret; 463 464 (void) nvpair_value_nvlist_array(pv_nvp, &val, &nelem); 465 (void) printf(" [ "); 466 for (i = 0; i < nelem; i++) { 467 ret = topo_fmri_nvl2str(thp, val[i], &fmri, 468 &err); 469 if (ret != 0) { 470 (void) fprintf(stderr, "failed to " 471 "convert FMRI to string (%s)\n", 472 topo_strerror(err)); 473 nvlist_print(stdout, val[i]); 474 break; 475 } 476 (void) printf("\"%s\" ", fmri); 477 topo_hdl_strfree(thp, fmri); 478 } 479 (void) printf("]"); 480 break; 481 } 482 default: 483 (void) fprintf(stderr, " unknown data type (%d)", 484 nvpair_type(pv_nvp)); 485 break; 486 } 487 (void) printf("\n"); 488 } 489 490 static void 491 print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab, 492 char *nstab, int32_t version) 493 { 494 int err; 495 topo_pgroup_info_t *pgi = NULL; 496 497 if (pgn == NULL) 498 return; 499 500 if (node != NULL && (dstab == NULL || nstab == NULL || version == -1)) { 501 if ((pgi = topo_pgroup_info(node, pgn, &err)) != NULL) { 502 dstab = (char *)topo_stability2name(pgi->tpi_datastab); 503 nstab = (char *)topo_stability2name(pgi->tpi_namestab); 504 version = pgi->tpi_version; 505 } 506 } 507 508 if (dstab == NULL || nstab == NULL || version == -1) { 509 (void) printf(" group: %-30s version: - stability: -/-\n", 510 pgn); 511 } else { 512 (void) printf(" group: %-30s version: %-3d stability: %s/%s\n", 513 pgn, version, nstab, dstab); 514 } 515 516 if (pgi != NULL) { 517 topo_hdl_strfree(thp, (char *)pgi->tpi_name); 518 topo_hdl_free(thp, pgi, sizeof (topo_pgroup_info_t)); 519 } 520 } 521 522 static void 523 print_all_props(topo_hdl_t *thp, tnode_t *node, nvlist_t *p_nv, 524 const char *group) 525 { 526 char *pgn = NULL, *dstab = NULL, *nstab = NULL; 527 int32_t version; 528 nvlist_t *pg_nv, *pv_nv; 529 nvpair_t *nvp, *pg_nvp; 530 int pg_done, match, all = strcmp(group, ALL) == 0; 531 532 for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL; 533 nvp = nvlist_next_nvpair(p_nv, nvp)) { 534 if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 || 535 nvpair_type(nvp) != DATA_TYPE_NVLIST) 536 continue; 537 538 nstab = NULL; 539 dstab = NULL; 540 version = -1; 541 pg_done = match = 0; 542 (void) nvpair_value_nvlist(nvp, &pg_nv); 543 for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL; 544 pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) { 545 /* 546 * Print property group name and stability levels 547 */ 548 if (strcmp(TOPO_PROP_GROUP_NAME, nvpair_name(pg_nvp)) 549 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 550 (void) nvpair_value_string(pg_nvp, &pgn); 551 match = strcmp(group, pgn) == 0; 552 continue; 553 } 554 555 if (strcmp(TOPO_PROP_GROUP_NSTAB, 556 nvpair_name(pg_nvp)) == 0 && 557 nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 558 (void) nvpair_value_string(pg_nvp, &nstab); 559 continue; 560 } 561 562 if (strcmp(TOPO_PROP_GROUP_DSTAB, 563 nvpair_name(pg_nvp)) == 0 && 564 nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 565 (void) nvpair_value_string(pg_nvp, &dstab); 566 continue; 567 } 568 569 if (strcmp(TOPO_PROP_GROUP_VERSION, 570 nvpair_name(pg_nvp)) == 0 && 571 nvpair_type(pg_nvp) == DATA_TYPE_INT32) { 572 (void) nvpair_value_int32(pg_nvp, &version); 573 continue; 574 } 575 576 if ((match || all) && !pg_done) { 577 print_pgroup(thp, node, pgn, dstab, nstab, 578 version); 579 pg_done++; 580 } 581 582 /* 583 * Print property group and property name-value pair 584 */ 585 if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) 586 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) { 587 (void) nvpair_value_nvlist(pg_nvp, &pv_nv); 588 if ((match || all) && pg_done) { 589 print_prop_nameval(thp, node, pv_nv); 590 } 591 592 } 593 594 } 595 if (match && !all) 596 return; 597 } 598 } 599 600 static void 601 set_prop(topo_hdl_t *thp, tnode_t *node, nvlist_t *fmri, struct prop_args *pp) 602 { 603 int ret, err = 0; 604 topo_type_t type; 605 nvlist_t *nvl = NULL; 606 char *end; 607 608 if (pp->prop == NULL || pp->type == NULL || pp->value == NULL) 609 goto out; 610 611 if ((type = str2type(pp->type)) == TOPO_TYPE_INVALID) { 612 (void) fprintf(stderr, "%s: invalid property type %s for %s\n", 613 g_pname, pp->type, pp->prop); 614 goto out; 615 } 616 617 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 618 (void) fprintf(stderr, "%s: nvlist allocation failed for " 619 "%s=%s:%s\n", g_pname, pp->prop, pp->type, pp->value); 620 goto out; 621 } 622 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pp->prop); 623 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type); 624 if (ret != 0) { 625 (void) fprintf(stderr, "%s: invalid property type %s for %s\n", 626 g_pname, pp->type, pp->prop); 627 goto out; 628 } 629 630 errno = 0; 631 switch (type) { 632 case TOPO_TYPE_INT32: 633 { 634 int32_t val; 635 636 val = strtol(pp->value, &end, 0); 637 if (errno == ERANGE) { 638 ret = -1; 639 break; 640 } 641 ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val); 642 break; 643 } 644 case TOPO_TYPE_UINT32: 645 { 646 uint32_t val; 647 648 val = strtoul(pp->value, &end, 0); 649 if (errno == ERANGE) { 650 ret = -1; 651 break; 652 } 653 ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val); 654 break; 655 } 656 case TOPO_TYPE_INT64: 657 { 658 int64_t val; 659 660 val = strtoll(pp->value, &end, 0); 661 if (errno == ERANGE) { 662 ret = -1; 663 break; 664 } 665 ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val); 666 break; 667 } 668 case TOPO_TYPE_UINT64: 669 { 670 uint64_t val; 671 672 val = strtoull(pp->value, &end, 0); 673 if (errno == ERANGE) { 674 ret = -1; 675 break; 676 } 677 ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val); 678 break; 679 } 680 case TOPO_TYPE_STRING: 681 { 682 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, 683 pp->value); 684 break; 685 } 686 case TOPO_TYPE_FMRI: 687 { 688 nvlist_t *val = NULL; 689 690 if ((ret = topo_fmri_str2nvl(thp, pp->value, &val, 691 &err)) < 0) 692 break; 693 694 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, 695 val)) != 0) 696 err = ETOPO_PROP_NVL; 697 698 nvlist_free(val); 699 break; 700 } 701 default: 702 ret = -1; 703 } 704 705 if (ret != 0) { 706 (void) fprintf(stderr, "%s: unable to set property value for " 707 "%s: %s\n", g_pname, pp->prop, topo_strerror(err)); 708 goto out; 709 } 710 711 if (node != NULL) { 712 if ((ret = topo_prop_setprop(node, pp->group, nvl, 713 TOPO_PROP_MUTABLE, nvl, &err)) < 0) { 714 (void) fprintf(stderr, "%s: unable to set property " 715 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop, 716 pp->type, pp->value, topo_strerror(err)); 717 goto out; 718 } 719 } else { 720 if ((ret = topo_fmri_setprop(thp, fmri, pp->group, nvl, 721 TOPO_PROP_MUTABLE, nvl, &err)) < 0) { 722 (void) fprintf(stderr, "%s: unable to set property " 723 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop, 724 pp->type, pp->value, topo_strerror(err)); 725 goto out; 726 } 727 } 728 729 nvlist_free(nvl); 730 nvl = NULL; 731 732 /* 733 * Now, get the property back for printing 734 */ 735 if (node != NULL) { 736 if ((ret = topo_prop_getprop(node, pp->group, pp->prop, NULL, 737 &nvl, &err)) < 0) { 738 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n", 739 g_pname, pp->group, pp->prop, topo_strerror(err)); 740 goto out; 741 } 742 } else { 743 if ((ret = topo_fmri_getprop(thp, fmri, pp->group, pp->prop, 744 NULL, &nvl, &err)) < 0) { 745 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n", 746 g_pname, pp->group, pp->prop, topo_strerror(err)); 747 goto out; 748 } 749 } 750 751 print_pgroup(thp, node, pp->group, NULL, NULL, 0); 752 print_prop_nameval(thp, node, nvl); 753 754 out: 755 nvlist_free(nvl); 756 } 757 758 static void 759 print_props(topo_hdl_t *thp, tnode_t *node) 760 { 761 int i, err; 762 nvlist_t *nvl; 763 struct prop_args *pp; 764 765 if (pcnt == 0) 766 return; 767 768 for (i = 0; i < pcnt; ++i) { 769 pp = pargs[i]; 770 771 if (pp->group == NULL) 772 continue; 773 774 /* 775 * If we have a valid value, this is a request to 776 * set a property. Otherwise, just print the property 777 * group and any specified properties. 778 */ 779 if (pp->value == NULL) { 780 if (pp->prop == NULL) { 781 782 /* 783 * Print all properties in this group 784 */ 785 if ((nvl = topo_prop_getprops(node, &err)) 786 == NULL) { 787 (void) fprintf(stderr, "%s: failed to " 788 "get %s: %s\n", g_pname, 789 pp->group, 790 topo_strerror(err)); 791 continue; 792 } else { 793 print_all_props(thp, node, nvl, 794 pp->group); 795 nvlist_free(nvl); 796 continue; 797 } 798 } 799 if (topo_prop_getprop(node, pp->group, pp->prop, 800 NULL, &nvl, &err) < 0) { 801 (void) fprintf(stderr, "%s: failed to get " 802 "%s.%s: %s\n", g_pname, 803 pp->group, pp->prop, 804 topo_strerror(err)); 805 continue; 806 } else { 807 print_pgroup(thp, node, pp->group, NULL, 808 NULL, 0); 809 print_prop_nameval(thp, node, nvl); 810 nvlist_free(nvl); 811 } 812 } else { 813 set_prop(thp, node, NULL, pp); 814 } 815 } 816 } 817 818 /*ARGSUSED*/ 819 static int 820 walk_node(topo_hdl_t *thp, tnode_t *node, void *arg) 821 { 822 int err; 823 nvlist_t *nvl; 824 nvlist_t *rsrc, *out; 825 char *s; 826 827 if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { 828 print_everstyle(node); 829 return (TOPO_WALK_NEXT); 830 } 831 832 if (topo_node_resource(node, &rsrc, &err) < 0) { 833 (void) fprintf(stderr, "%s: failed to get resource: " 834 "%s", g_pname, topo_strerror(err)); 835 return (TOPO_WALK_NEXT); 836 } 837 if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) { 838 (void) fprintf(stderr, "%s: failed to convert " 839 "resource to FMRI string: %s", g_pname, 840 topo_strerror(err)); 841 nvlist_free(rsrc); 842 return (TOPO_WALK_NEXT); 843 } 844 845 if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) { 846 nvlist_free(rsrc); 847 topo_hdl_strfree(thp, s); 848 return (TOPO_WALK_NEXT); 849 } 850 851 print_node(thp, node, rsrc, s); 852 topo_hdl_strfree(thp, s); 853 nvlist_free(rsrc); 854 855 if (opt_m != NULL) { 856 if (topo_method_invoke(node, opt_m, 0, NULL, &out, &err) == 0) { 857 nvlist_print(stdout, out); 858 nvlist_free(out); 859 } else if (err != ETOPO_METHOD_NOTSUP) 860 (void) fprintf(stderr, "%s: method failed unexpectedly " 861 "on %s=%d (%s)\n", g_pname, topo_node_name(node), 862 topo_node_instance(node), topo_strerror(err)); 863 } 864 865 if (opt_V || opt_all) { 866 if ((nvl = topo_prop_getprops(node, &err)) == NULL) { 867 (void) fprintf(stderr, "%s: failed to get " 868 "properties for %s=%d: %s\n", g_pname, 869 topo_node_name(node), topo_node_instance(node), 870 topo_strerror(err)); 871 } else { 872 print_all_props(thp, node, nvl, ALL); 873 nvlist_free(nvl); 874 } 875 } else if (pcnt > 0) 876 print_props(thp, node); 877 878 (void) printf("\n"); 879 880 return (TOPO_WALK_NEXT); 881 } 882 883 static void 884 get_pargs(int argc, char *argv[]) 885 { 886 struct prop_args *pp; 887 char c, *s, *p; 888 int i = 0; 889 890 if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) { 891 (void) fprintf(stderr, "%s: failed to allocate property " 892 "arguments\n", g_pname); 893 return; 894 } 895 896 for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) { 897 if (c == 'P') { 898 899 if (strcmp(optarg, ALL) == 0) { 900 opt_all++; 901 break; 902 } 903 904 if ((pp = pargs[i] = malloc(sizeof (struct prop_args))) 905 == NULL) { 906 (void) fprintf(stderr, "%s: failed to " 907 "allocate propertyarguments\n", g_pname); 908 return; 909 } 910 ++i; 911 pp->group = NULL; 912 pp->prop = NULL; 913 pp->type = NULL; 914 pp->value = NULL; 915 916 p = optarg; 917 if ((s = strchr(p, '.')) != NULL) { 918 *s++ = '\0'; /* strike out delimiter */ 919 pp->group = p; 920 p = s; 921 if ((s = strchr(p, '=')) != NULL) { 922 *s++ = '\0'; /* strike out delimiter */ 923 pp->prop = p; 924 p = s; 925 if ((s = strchr(p, ':')) != NULL) { 926 *s++ = '\0'; 927 pp->type = p; 928 pp->value = s; 929 } else { 930 (void) fprintf(stderr, "%s: " 931 "property type not " 932 "specified for assignment " 933 " of %s.%s\n", g_pname, 934 pp->group, pp->prop); 935 break; 936 } 937 } else { 938 pp->prop = p; 939 } 940 } else { 941 pp->group = p; 942 } 943 if (i >= pcnt) 944 break; 945 } 946 } 947 948 if (opt_all > 0) { 949 int j; 950 951 for (j = 0; j < i; ++j) 952 free(pargs[i]); 953 free(pargs); 954 pargs = NULL; 955 } 956 } 957 958 static int 959 walk_topo(topo_hdl_t *thp, char *uuid) 960 { 961 int err; 962 topo_walk_t *twp; 963 int flag; 964 965 if (getzoneid() != GLOBAL_ZONEID && 966 strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { 967 return (0); 968 } 969 970 if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err)) 971 == NULL) { 972 (void) fprintf(stderr, "%s: failed to walk %s topology:" 973 " %s\n", g_pname, opt_s, topo_strerror(err)); 974 975 return (-1); 976 } 977 978 /* 979 * Print standard header 980 */ 981 if (!opt_e) { 982 char buf[32]; 983 time_t tod = time(NULL); 984 985 (void) printf("TIME UUID\n"); 986 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); 987 (void) printf("%-15s %-32s\n", buf, uuid); 988 (void) printf("\n"); 989 } 990 991 flag = opt_b != 0 ? TOPO_WALK_SIBLING : TOPO_WALK_CHILD; 992 993 if (topo_walk_step(twp, flag) == TOPO_WALK_ERR) { 994 (void) fprintf(stderr, "%s: failed to walk topology\n", 995 g_pname); 996 topo_walk_fini(twp); 997 return (-1); 998 } 999 1000 topo_walk_fini(twp); 1001 1002 return (0); 1003 } 1004 1005 static void 1006 print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl) 1007 { 1008 char *dstab = NULL, *nstab = NULL; 1009 int32_t version = -1; 1010 nvlist_t *pnvl; 1011 nvpair_t *pnvp; 1012 1013 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab); 1014 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab); 1015 (void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version); 1016 1017 print_pgroup(thp, NULL, pgn, dstab, nstab, version); 1018 1019 for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL; 1020 pnvp = nvlist_next_nvpair(nvl, pnvp)) { 1021 1022 /* 1023 * Print property group and property name-value pair 1024 */ 1025 if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp)) 1026 == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) { 1027 (void) nvpair_value_nvlist(pnvp, &pnvl); 1028 print_prop_nameval(thp, NULL, pnvl); 1029 1030 } 1031 1032 } 1033 } 1034 1035 static void 1036 print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl) 1037 { 1038 int i, err; 1039 struct prop_args *pp; 1040 nvlist_t *pnvl; 1041 1042 for (i = 0; i < pcnt; ++i) { 1043 pp = pargs[i]; 1044 1045 if (pp->group == NULL) 1046 continue; 1047 1048 pnvl = NULL; 1049 1050 /* 1051 * If we have a valid value, this is a request to 1052 * set a property. Otherwise, just print the property 1053 * group and any specified properties. 1054 */ 1055 if (pp->value == NULL) { 1056 if (pp->prop == NULL) { 1057 1058 /* 1059 * Print all properties in this group 1060 */ 1061 if (topo_fmri_getpgrp(thp, nvl, pp->group, 1062 &pnvl, &err) < 0) { 1063 (void) fprintf(stderr, "%s: failed to " 1064 "get group %s: %s\n", g_pname, 1065 pp->group, topo_strerror(err)); 1066 continue; 1067 } else { 1068 print_fmri_pgroup(thp, pp->group, 1069 pnvl); 1070 nvlist_free(pnvl); 1071 continue; 1072 } 1073 } 1074 if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop, 1075 NULL, &pnvl, &err) < 0) { 1076 (void) fprintf(stderr, "%s: failed to get " 1077 "%s.%s: %s\n", g_pname, 1078 pp->group, pp->prop, 1079 topo_strerror(err)); 1080 continue; 1081 } else { 1082 print_fmri_pgroup(thp, pp->group, pnvl); 1083 print_prop_nameval(thp, NULL, pnvl); 1084 nvlist_free(nvl); 1085 } 1086 } else { 1087 set_prop(thp, NULL, nvl, pp); 1088 } 1089 } 1090 } 1091 1092 void 1093 print_fmri(topo_hdl_t *thp, char *uuid) 1094 { 1095 int ret, err; 1096 nvlist_t *nvl; 1097 char buf[32]; 1098 time_t tod = time(NULL); 1099 1100 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { 1101 (void) fprintf(stderr, "%s: failed to convert %s to nvlist: " 1102 "%s\n", g_pname, g_fmri, topo_strerror(err)); 1103 return; 1104 } 1105 1106 (void) printf("TIME UUID\n"); 1107 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); 1108 (void) printf("%-15s %-32s\n", buf, uuid); 1109 (void) printf("\n"); 1110 1111 (void) printf("%s\n", (char *)g_fmri); 1112 1113 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) { 1114 char *aname = NULL, *fname = NULL, *lname = NULL; 1115 nvlist_t *asru = NULL; 1116 nvlist_t *fru = NULL; 1117 1118 if (topo_fmri_asru(thp, nvl, &asru, &err) == 0) 1119 (void) topo_fmri_nvl2str(thp, asru, &aname, &err); 1120 if (topo_fmri_fru(thp, nvl, &fru, &err) == 0) 1121 (void) topo_fmri_nvl2str(thp, fru, &fname, &err); 1122 (void) topo_fmri_label(thp, nvl, &lname, &err); 1123 1124 nvlist_free(fru); 1125 nvlist_free(asru); 1126 1127 if (aname != NULL) { 1128 (void) printf("\tASRU: %s\n", aname); 1129 topo_hdl_strfree(thp, aname); 1130 } else { 1131 (void) printf("\tASRU: -\n"); 1132 } 1133 if (fname != NULL) { 1134 (void) printf("\tFRU: %s\n", fname); 1135 topo_hdl_strfree(thp, fname); 1136 } else { 1137 (void) printf("\tFRU: -\n"); 1138 } 1139 if (lname != NULL) { 1140 (void) printf("\tLabel: %s\n", lname); 1141 topo_hdl_strfree(thp, lname); 1142 } else { 1143 (void) printf("\tLabel: -\n"); 1144 } 1145 } 1146 1147 if (opt_S) { 1148 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) { 1149 (void) printf("\tPresent: -\n"); 1150 (void) printf("\tUnusable: -\n"); 1151 return; 1152 } 1153 1154 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0) 1155 (void) printf("\tPresent: -\n"); 1156 else 1157 (void) printf("\tPresent: %s\n", 1158 ret ? "true" : "false"); 1159 1160 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0) 1161 (void) printf("\tUnusable: -\n"); 1162 else 1163 (void) printf("\tUnusable: %s\n", 1164 ret ? "true" : "false"); 1165 1166 nvlist_free(nvl); 1167 } 1168 1169 if (pargs && pcnt > 0) 1170 print_fmri_props(thp, nvl); 1171 } 1172 1173 int 1174 fmtopo_exit(topo_hdl_t *thp, char *uuid, int err) 1175 { 1176 if (uuid != NULL) 1177 topo_hdl_strfree(thp, uuid); 1178 1179 if (thp != NULL) { 1180 topo_snap_release(thp); 1181 topo_close(thp); 1182 } 1183 1184 if (pargs) { 1185 int i; 1186 for (i = 0; i < pcnt; ++i) 1187 free(pargs[i]); 1188 free(pargs); 1189 } 1190 1191 return (err); 1192 } 1193 1194 int 1195 main(int argc, char *argv[]) 1196 { 1197 topo_hdl_t *thp = NULL; 1198 char *uuid = NULL; 1199 int c, err = 0; 1200 1201 g_pname = argv[0]; 1202 1203 while (optind < argc) { 1204 while ((c = getopt(argc, argv, optstr)) != -1) { 1205 switch (c) { 1206 case 'b': 1207 opt_b++; 1208 break; 1209 case 'C': 1210 (void) atexit(abort); 1211 break; 1212 case 'd': 1213 opt_d++; 1214 break; 1215 case 'e': 1216 opt_e++; 1217 break; 1218 case 'm': 1219 opt_m = optarg; 1220 break; 1221 case 'P': 1222 pcnt++; 1223 break; 1224 case 'p': 1225 opt_p++; 1226 break; 1227 case 'V': 1228 opt_V++; 1229 break; 1230 case 'R': 1231 opt_R = optarg; 1232 break; 1233 case 's': 1234 opt_s = optarg; 1235 break; 1236 case 'S': 1237 opt_S++; 1238 break; 1239 case 't': 1240 opt_t++; 1241 break; 1242 case 'x': 1243 opt_x++; 1244 break; 1245 default: 1246 return (usage(stderr)); 1247 } 1248 } 1249 1250 if (optind < argc) { 1251 if (g_fmri != NULL) { 1252 (void) fprintf(stderr, "%s: illegal argument " 1253 "-- %s\n", g_pname, argv[optind]); 1254 return (FMTOPO_EXIT_USAGE); 1255 } else { 1256 g_fmri = argv[optind++]; 1257 } 1258 } 1259 } 1260 1261 if (pcnt > 0) 1262 get_pargs(argc, argv); 1263 1264 if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) { 1265 (void) fprintf(stderr, "%s: failed to open topology tree: %s\n", 1266 g_pname, topo_strerror(err)); 1267 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); 1268 } 1269 1270 if (opt_d) 1271 topo_debug_set(thp, "module", "stderr"); 1272 1273 if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) { 1274 (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n", 1275 g_pname, topo_strerror(err)); 1276 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); 1277 } else if (err != 0) { 1278 (void) fprintf(stderr, "%s: topology snapshot incomplete%s\n", 1279 g_pname, getzoneid() != GLOBAL_ZONEID && 1280 strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0 ? 1281 " (" FM_FMRI_SCHEME_HC " scheme does not enumerate " 1282 "in a non-global zone)": ""); 1283 } 1284 1285 if (opt_x) { 1286 if (opt_b) { 1287 (void) fprintf(stderr, 1288 "%s: -b and -x cannot be specified together\n", 1289 g_pname); 1290 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_USAGE)); 1291 } 1292 1293 err = 0; 1294 if (topo_xml_print(thp, stdout, opt_s, &err) < 0) 1295 (void) fprintf(stderr, "%s: failed to print xml " 1296 "formatted topology:%s", g_pname, 1297 topo_strerror(err)); 1298 1299 return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR : 1300 FMTOPO_EXIT_SUCCESS)); 1301 } 1302 1303 if (opt_t || walk_topo(thp, uuid) < 0) { 1304 if (g_fmri != NULL) 1305 /* 1306 * Try getting some useful information 1307 */ 1308 print_fmri(thp, uuid); 1309 1310 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR)); 1311 } 1312 1313 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_SUCCESS)); 1314 } 1315