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