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