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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/fm/protocol.h> 30 #include <fm/libtopo.h> 31 #include <ctype.h> 32 #include <limits.h> 33 #include <strings.h> 34 #include <stdio.h> 35 #include <errno.h> 36 #include <sys/param.h> 37 38 #define FMTOPO_EXIT_SUCCESS 0 39 #define FMTOPO_EXIT_ERROR 1 40 #define FMTOPO_EXIT_USAGE 2 41 42 #define STDERR "stderr" 43 #define DOTS "..." 44 #define ALL "all" 45 46 static const char *g_pname; 47 48 static const char *opt_R = "/"; 49 static const char *opt_P = NULL; 50 static const char *opt_s = FM_FMRI_SCHEME_HC; 51 52 static int opt_e = 0; 53 static int opt_d = 0; 54 static int opt_V = 0; 55 static int opt_p = 0; 56 static int opt_x = 0; 57 58 static int 59 usage(FILE *fp) 60 { 61 (void) fprintf(fp, 62 "Usage: %s [-edpvVx] [-Cdev] [-P properties] [-R root] " 63 "[-s scheme]\n", g_pname); 64 65 (void) fprintf(fp, 66 "\t-C dump core after completing execution\n" 67 "\t-d set debug mode for libtopo modules\n" 68 "\t-e display FMRIs as paths using esc/eft notation\n" 69 "\t-P display of FMRI with the specified properties\n" 70 "\t-p display of FMRI protocol properties\n" 71 "\t-R set root directory for libtopo plug-ins and other files\n" 72 "\t-s display topology for the specified FMRI scheme\n" 73 "\t-V set verbose mode\n" 74 "\t-x display a xml formatted topology\n"); 75 76 return (FMTOPO_EXIT_USAGE); 77 } 78 79 static void 80 print_fmri(topo_hdl_t *thp, tnode_t *node) 81 { 82 int err; 83 char *name; 84 nvlist_t *fmri; 85 86 if (topo_node_resource(node, &fmri, &err) < 0) { 87 (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n", 88 g_pname, topo_node_name(node), 89 topo_node_instance(node), topo_strerror(err)); 90 return; 91 } 92 93 if (topo_fmri_nvl2str(thp, fmri, &name, &err) < 0) { 94 (void) fprintf(stderr, "%s: failed to convert fmri for %s=%d " 95 "to a string: %s\n", g_pname, topo_node_name(node), 96 topo_node_instance(node), topo_strerror(err)); 97 nvlist_free(fmri); 98 return; 99 } 100 101 (void) printf("%s\n", name); 102 103 if (opt_p) { 104 char *aname = NULL, *fname = NULL, *lname = NULL; 105 nvlist_t *asru = NULL; 106 nvlist_t *fru = NULL; 107 108 if (topo_node_asru(node, &asru, NULL, &err) == 0) 109 (void) topo_fmri_nvl2str(thp, asru, &aname, &err); 110 if (topo_node_fru(node, &fru, NULL, &err) == 0) 111 (void) topo_fmri_nvl2str(thp, fru, &fname, &err); 112 (void) topo_node_label(node, &lname, &err); 113 if (aname != NULL) { 114 nvlist_free(asru); 115 (void) printf("\tASRU: %s\n", aname); 116 topo_hdl_strfree(thp, aname); 117 } else { 118 (void) printf("\tASRU: -\n"); 119 } 120 if (fname != NULL) { 121 nvlist_free(fru); 122 (void) printf("\tFRU: %s\n", fname); 123 topo_hdl_strfree(thp, fname); 124 } else { 125 (void) printf("\tFRU: -\n"); 126 } 127 if (lname != NULL) { 128 (void) printf("\tLabel: %s\n", lname); 129 topo_hdl_strfree(thp, lname); 130 } else { 131 (void) printf("\tLabel: -\n"); 132 } 133 } 134 nvlist_free(fmri); 135 136 topo_hdl_strfree(thp, name); 137 } 138 139 static void 140 print_everstyle(tnode_t *node) 141 { 142 char buf[PATH_MAX], numbuf[64]; 143 nvlist_t *fmri, **hcl; 144 int i, err; 145 uint_t n; 146 147 if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, 148 TOPO_PROP_RESOURCE, &fmri, &err) < 0) { 149 (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n", 150 g_pname, topo_node_name(node), 151 topo_node_instance(node), topo_strerror(err)); 152 return; 153 } 154 155 if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &n) != 0) { 156 (void) fprintf(stderr, "%s: failed to find %s for %s=%d\n", 157 g_pname, FM_FMRI_HC_LIST, topo_node_name(node), 158 topo_node_instance(node)); 159 return; 160 } 161 162 buf[0] = '\0'; 163 164 for (i = 0; i < n; i++) { 165 char *name, *inst, *estr; 166 ulong_t ul; 167 168 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0 || 169 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &inst) != 0) { 170 (void) fprintf(stderr, "%s: failed to get " 171 "name-instance for %s=%d\n", g_pname, 172 topo_node_name(node), topo_node_instance(node)); 173 return; 174 } 175 176 errno = 0; 177 ul = strtoul(inst, &estr, 10); 178 179 if (errno != 0 || estr == inst) { 180 (void) fprintf(stderr, "%s: instance %s does not " 181 "convert to an unsigned integer\n", g_pname, inst); 182 } 183 184 (void) strlcat(buf, "/", sizeof (buf)); 185 (void) strlcat(buf, name, sizeof (buf)); 186 (void) snprintf(numbuf, sizeof (numbuf), "%u", ul); 187 (void) strlcat(buf, numbuf, sizeof (buf)); 188 } 189 190 (void) printf("%s\n", buf); 191 } 192 193 static void 194 print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl, int skip) 195 { 196 int err; 197 topo_type_t type; 198 char *tstr, *propn, buf[48]; 199 nvpair_t *pv_nvp; 200 int i; 201 uint_t nelem; 202 203 if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL) 204 return; 205 206 /* Print property name */ 207 if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL || 208 nvpair_name(pv_nvp) == NULL || 209 strcmp(TOPO_PROP_VAL_NAME, nvpair_name(pv_nvp)) != 0) { 210 (void) fprintf(stderr, "%s: malformed property name\n", 211 g_pname); 212 return; 213 } else { 214 (void) nvpair_value_string(pv_nvp, &propn); 215 } 216 217 if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL || 218 nvpair_name(pv_nvp) == NULL || 219 strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 || 220 nvpair_type(pv_nvp) != DATA_TYPE_INT32) { 221 (void) fprintf(stderr, "%s: malformed property type for %s\n", 222 g_pname, propn); 223 return; 224 } else { 225 (void) nvpair_value_int32(pv_nvp, (int32_t *)&type); 226 } 227 228 switch (type) { 229 case TOPO_TYPE_BOOLEAN: tstr = "boolean"; break; 230 case TOPO_TYPE_INT32: tstr = "int32"; break; 231 case TOPO_TYPE_UINT32: tstr = "uint32"; break; 232 case TOPO_TYPE_INT64: tstr = "int64"; break; 233 case TOPO_TYPE_UINT64: tstr = "uint64"; break; 234 case TOPO_TYPE_STRING: tstr = "string"; break; 235 case TOPO_TYPE_FMRI: tstr = "fmri"; break; 236 case TOPO_TYPE_INT32_ARRAY: tstr = "int32[]"; break; 237 case TOPO_TYPE_UINT32_ARRAY: tstr = "uint32[]"; break; 238 case TOPO_TYPE_INT64_ARRAY: tstr = "int64[]"; break; 239 case TOPO_TYPE_UINT64_ARRAY: tstr = "uint64[]"; break; 240 case TOPO_TYPE_STRING_ARRAY: tstr = "string[]"; break; 241 case TOPO_TYPE_FMRI_ARRAY: tstr = "fmri[]"; break; 242 default: tstr = "unknown type"; 243 } 244 245 if (!skip) 246 printf(" %-17s %-8s ", propn, tstr); 247 248 /* 249 * Get property value 250 */ 251 if (nvpair_name(pv_nvp) == NULL || 252 (pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL) { 253 (void) fprintf(stderr, "%s: malformed property value\n", 254 g_pname); 255 return; 256 } 257 258 if (skip) 259 return; 260 261 switch (nvpair_type(pv_nvp)) { 262 case DATA_TYPE_INT32: { 263 int32_t val; 264 (void) nvpair_value_int32(pv_nvp, &val); 265 (void) printf(" %d", val); 266 break; 267 } 268 case DATA_TYPE_UINT32: { 269 uint32_t val; 270 (void) nvpair_value_uint32(pv_nvp, &val); 271 (void) printf(" 0x%x", val); 272 break; 273 } 274 case DATA_TYPE_INT64: { 275 int64_t val; 276 (void) nvpair_value_int64(pv_nvp, &val); 277 (void) printf(" %lld", (longlong_t)val); 278 break; 279 } 280 case DATA_TYPE_UINT64: { 281 uint64_t val; 282 (void) nvpair_value_uint64(pv_nvp, &val); 283 (void) printf(" 0x%llx", (u_longlong_t)val); 284 break; 285 } 286 case DATA_TYPE_STRING: { 287 char *val; 288 (void) nvpair_value_string(pv_nvp, &val); 289 if (!opt_V && strlen(val) > 48) { 290 (void) snprintf(buf, 48, "%s...", val); 291 (void) printf(" %s", buf); 292 } else { 293 (void) printf(" %s", val); 294 } 295 break; 296 } 297 case DATA_TYPE_NVLIST: { 298 nvlist_t *val; 299 char *fmri; 300 (void) nvpair_value_nvlist(pv_nvp, &val); 301 if (topo_fmri_nvl2str(thp, val, &fmri, &err) != 0) { 302 if (opt_V) 303 nvlist_print(stdout, nvl); 304 break; 305 } 306 307 if (!opt_V && strlen(fmri) > 48) { 308 (void) snprintf(buf, 48, "%s", fmri); 309 (void) snprintf(&buf[45], 4, "%s", DOTS); 310 (void) printf(" %s", buf); 311 } else { 312 (void) printf(" %s", fmri); 313 } 314 315 topo_hdl_strfree(thp, fmri); 316 break; 317 } 318 case DATA_TYPE_UINT32_ARRAY: { 319 uint32_t *val; 320 321 (void) nvpair_value_uint32_array(pv_nvp, &val, &nelem); 322 (void) printf(" [ "); 323 for (i = 0; i < nelem; i++) 324 (void) printf("%u ", val[i]); 325 (void) printf("]"); 326 break; 327 } 328 default: 329 (void) fprintf(stderr, " unknown data type (%d)", 330 nvpair_type(pv_nvp)); 331 break; 332 } 333 (void) printf("\n"); 334 } 335 336 static void 337 print_pgroup(char *pgn, char *dstab, char *nstab, int32_t version, int skip) 338 { 339 char buf[30]; 340 341 if (skip) 342 return; 343 344 if (!opt_V && strlen(pgn) > 30) { 345 (void) snprintf(buf, 26, "%s", pgn); 346 (void) snprintf(&buf[27], 4, "%s", DOTS); 347 printf(" group: %-30s version: %-3d stability: %s/%s\n", 348 buf, version, nstab, dstab); 349 } else { 350 printf(" group: %-30s version: %-3d stability: %s/%s\n", 351 pgn, version, nstab, dstab); 352 } 353 } 354 355 static int 356 cmp_name(const char *props, char *pgn) 357 { 358 char buf[MAXNAMELEN]; 359 size_t count; 360 char *begin, *end, *value, *next; 361 char *np; 362 363 if (props == NULL) 364 return (0); 365 366 if (strcmp(props, ALL) == 0) 367 return (0); 368 369 370 value = np = strdup(props); 371 372 for (end = np; *end != '\0'; value = next) { 373 end = strchr(value, ','); 374 if (end != NULL) 375 next = end + 1; /* skip the comma */ 376 else 377 next = end = value + strlen(value); 378 379 /* 380 * Eat up white space at beginning or end of the 381 * property group name 382 */ 383 begin = value; 384 while (begin < end && isspace(*begin)) 385 begin++; 386 while (begin < end && isspace(*(end - 1))) 387 end--; 388 389 if (begin >= end) 390 return (1); 391 392 count = end - begin; 393 count += 1; 394 395 if (count > sizeof (buf)) 396 return (1); 397 398 (void) snprintf(buf, count, "%s", begin); 399 if (strcmp(pgn, buf) == 0) { 400 free(np); 401 return (0); 402 } 403 } 404 405 free(np); 406 return (1); 407 } 408 409 static void 410 print_props(topo_hdl_t *thp, nvlist_t *p_nv, const char *props) 411 { 412 char *pgn = NULL, *dstab = NULL, *nstab = NULL; 413 int32_t version = 0; 414 nvlist_t *pg_nv, *pv_nv; 415 nvpair_t *nvp, *pg_nvp; 416 int pg_done = 0, skip = 0; 417 418 for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL; 419 nvp = nvlist_next_nvpair(p_nv, nvp)) { 420 if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 || 421 nvpair_type(nvp) != DATA_TYPE_NVLIST) 422 continue; 423 424 (void) nvpair_value_nvlist(nvp, &pg_nv); 425 for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL; 426 pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) { 427 /* 428 * Print property group name and stability levels 429 */ 430 if (strcmp(TOPO_PROP_GROUP_NAME, nvpair_name(pg_nvp)) 431 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 432 (void) nvpair_value_string(pg_nvp, &pgn); 433 434 skip = cmp_name(props, pgn); 435 436 } else if (strcmp(TOPO_PROP_GROUP_NSTAB, 437 nvpair_name(pg_nvp)) == 0 && 438 nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 439 (void) nvpair_value_string(pg_nvp, &nstab); 440 } else if (strcmp(TOPO_PROP_GROUP_DSTAB, 441 nvpair_name(pg_nvp)) == 0 && 442 nvpair_type(pg_nvp) == DATA_TYPE_STRING) { 443 (void) nvpair_value_string(pg_nvp, &dstab); 444 } else if (strcmp(TOPO_PROP_GROUP_VERSION, 445 nvpair_name(pg_nvp)) == 0 && 446 nvpair_type(pg_nvp) == DATA_TYPE_INT32) { 447 (void) nvpair_value_int32(pg_nvp, &version); 448 } 449 450 if (!pg_done) { 451 if (pgn && dstab && nstab && version) { 452 print_pgroup(pgn, dstab, nstab, 453 version, skip); 454 pg_done++; 455 } else { 456 continue; 457 } 458 /* 459 * Print property name-value pair 460 */ 461 } else if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp)) 462 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) { 463 (void) nvpair_value_nvlist(pg_nvp, &pv_nv); 464 print_prop_nameval(thp, pv_nv, skip); 465 466 } 467 } 468 pg_done = 0; 469 skip = 0; 470 } 471 } 472 473 /*ARGSUSED*/ 474 static int 475 print_tnode(topo_hdl_t *thp, tnode_t *node, void *arg) 476 { 477 int err; 478 nvlist_t *nvl; 479 480 if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) { 481 print_everstyle(node); 482 return (TOPO_WALK_NEXT); 483 } 484 485 print_fmri(thp, node); 486 487 if (opt_V || opt_P) { 488 if ((nvl = topo_prop_getprops(node, &err)) == NULL) { 489 (void) fprintf(stderr, "%s: failed to get " 490 "properties for %s=%d: %s\n", g_pname, 491 topo_node_name(node), topo_node_instance(node), 492 topo_strerror(err)); 493 } else { 494 print_props(thp, nvl, opt_P); 495 nvlist_free(nvl); 496 } 497 } 498 499 printf("\n"); 500 501 return (TOPO_WALK_NEXT); 502 } 503 504 int 505 main(int argc, char *argv[]) 506 { 507 topo_hdl_t *thp; 508 topo_walk_t *twp; 509 char *uuid; 510 int c, err = 0; 511 512 g_pname = argv[0]; 513 514 while (optind < argc) { 515 while ((c = getopt(argc, argv, "aCdeP:pR:s:vVx")) != -1) { 516 switch (c) { 517 case 'C': 518 atexit(abort); 519 break; 520 case 'd': 521 opt_d++; 522 break; 523 case 'e': 524 opt_e++; 525 break; 526 case 'P': 527 opt_P = optarg; 528 break; 529 case 'p': 530 opt_p++; 531 break; 532 case 'V': 533 opt_V++; 534 break; 535 case 'R': 536 opt_R = optarg; 537 break; 538 case 's': 539 opt_s = optarg; 540 break; 541 case 'x': 542 opt_x++; 543 break; 544 default: 545 return (usage(stderr)); 546 } 547 } 548 549 if (optind < argc) { 550 (void) fprintf(stderr, "%s: illegal argument -- %s\n", 551 g_pname, argv[optind]); 552 return (FMTOPO_EXIT_USAGE); 553 } 554 } 555 556 if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) { 557 (void) fprintf(stderr, "%s: failed to open topology tree: %s\n", 558 g_pname, topo_strerror(err)); 559 return (FMTOPO_EXIT_ERROR); 560 } 561 562 if (opt_d) 563 topo_debug_set(thp, "module", "stderr"); 564 565 if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) { 566 (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n", 567 g_pname, topo_strerror(err)); 568 topo_close(thp); 569 return (FMTOPO_EXIT_ERROR); 570 } else if (err != 0) { 571 (void) fprintf(stderr, "%s: topology snapshot incomplete\n", 572 g_pname); 573 } 574 575 576 if (opt_x) { 577 err = 0; 578 if (topo_xml_print(thp, stdout, opt_s, &err) < 0) 579 (void) fprintf(stderr, "%s: failed to print xml " 580 "formatted topology:%s", g_pname, 581 topo_strerror(err)); 582 583 topo_hdl_strfree(thp, uuid); 584 topo_snap_release(thp); 585 topo_close(thp); 586 return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS); 587 } 588 if ((twp = topo_walk_init(thp, opt_s, print_tnode, NULL, &err)) 589 == NULL) { 590 (void) fprintf(stderr, "%s: failed to walk %s topology:" 591 " %s\n", g_pname, opt_s, topo_strerror(err)); 592 593 topo_hdl_strfree(thp, uuid); 594 topo_snap_release(thp); 595 topo_close(thp); 596 597 return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS); 598 } 599 600 /* 601 * Print standard header 602 */ 603 if (!opt_e) { 604 char buf[32]; 605 time_t tod = time(NULL); 606 607 printf("TIME UUID\n"); 608 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod)); 609 (void) printf("%-15s %-32s\n", buf, uuid); 610 (void) printf("\n"); 611 } 612 613 topo_hdl_strfree(thp, uuid); 614 615 if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { 616 (void) fprintf(stderr, "%s: failed to walk topology\n", 617 g_pname); 618 topo_walk_fini(twp); 619 topo_snap_release(thp); 620 topo_close(thp); 621 return (FMTOPO_EXIT_ERROR); 622 } 623 624 topo_walk_fini(twp); 625 topo_snap_release(thp); 626 topo_close(thp); 627 628 return (FMTOPO_EXIT_SUCCESS); 629 } 630