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