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) 2013, 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 DOTS    "..."
  46 #define ALL     "all"
  47 
  48 static const char *g_pname;
  49 static const char *g_fmri = NULL;
  50 
  51 static const char *opt_R = "/";
  52 static const char *opt_s = FM_FMRI_SCHEME_HC;
  53 static const char optstr[] = "bCdem:P:pR:s:StVx";
  54 static const char *opt_m;
  55 
  56 static int opt_b = 0;
  57 static int opt_d = 0;
  58 static int opt_e = 0;
  59 static int opt_p = 0;
  60 static int opt_S = 0;
  61 static int opt_t = 0;
  62 static int opt_V = 0;
  63 static int opt_x = 0;
  64 static int opt_all = 0;
  65 
  66 struct prop_args {
  67         const char *group;
  68         const char *prop;
  69         const char *type;
  70         const char *value;
  71 };
  72 
  73 static struct prop_args **pargs = NULL;
  74 static int pcnt = 0;
  75 
  76 static int
  77 usage(FILE *fp)
  78 {
  79         (void) fprintf(fp,
  80             "Usage: %s [-bCedpSVx] [-P group.property[=type:value]] "
  81             "[-R root] [-m method] [-s scheme] [fmri]\n", g_pname);
  82 
  83         (void) fprintf(fp,
  84             "\t-b  walk in sibling-first order (default is child-first)\n"
  85             "\t-C  dump core after completing execution\n"
  86             "\t-d  set debug mode for libtopo modules\n"
  87             "\t-e  display FMRIs as paths using esc/eft notation\n"
  88             "\t-m  execute given method\n"
  89             "\t-P  get/set specified properties\n"
  90             "\t-p  display of FMRI protocol properties\n"
  91             "\t-R  set root directory for libtopo plug-ins and other files\n"
  92             "\t-s  display topology for the specified FMRI scheme\n"
  93             "\t-S  display FMRI status (present/usable)\n"
  94             "\t-V  set verbose mode\n"
  95             "\t-x  display a xml formatted topology\n");
  96 
  97         return (FMTOPO_EXIT_USAGE);
  98 }
  99 
 100 static topo_type_t
 101 str2type(const char *tstr)
 102 {
 103         topo_type_t type;
 104 
 105         if (tstr == NULL)
 106                 return (TOPO_TYPE_INVALID);
 107 
 108         if (strcmp(tstr, "int32") == 0)
 109                 type = TOPO_TYPE_INT32;
 110         else if (strcmp(tstr, "uint32") == 0)
 111                 type = TOPO_TYPE_UINT32;
 112         else if (strcmp(tstr, "int64") == 0)
 113                 type = TOPO_TYPE_INT64;
 114         else if (strcmp(tstr, "uint64") == 0)
 115                 type = TOPO_TYPE_UINT64;
 116         else if (strcmp(tstr, "string") == 0)
 117                 type = TOPO_TYPE_STRING;
 118         else if (strcmp(tstr, "fmri") == 0)
 119                 type = TOPO_TYPE_FMRI;
 120         else {
 121                 type = TOPO_TYPE_INVALID;
 122         }
 123 
 124         return (type);
 125 }
 126 
 127 static void
 128 print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri)
 129 {
 130         int err, ret;
 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 }
 180 
 181 static void
 182 print_everstyle(tnode_t *node)
 183 {
 184         char buf[PATH_MAX], numbuf[64];
 185         nvlist_t *fmri, **hcl;
 186         int i, err;
 187         uint_t n;
 188 
 189         if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL,
 190             TOPO_PROP_RESOURCE, &fmri, &err) < 0) {
 191                 (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n",
 192                     g_pname, topo_node_name(node),
 193                     topo_node_instance(node), topo_strerror(err));
 194                 return;
 195         }
 196 
 197         if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
 198                 (void) fprintf(stderr, "%s: failed to find %s for %s=%d\n",
 199                     g_pname, FM_FMRI_HC_LIST, topo_node_name(node),
 200                     topo_node_instance(node));
 201                 nvlist_free(fmri);
 202                 return;
 203         }
 204 
 205         buf[0] = '\0';
 206 
 207         for (i = 0; i < n; i++) {
 208                 char *name, *inst, *estr;
 209                 ulong_t ul;
 210 
 211                 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0 ||
 212                     nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &inst) != 0) {
 213                         (void) fprintf(stderr, "%s: failed to get "
 214                             "name-instance for %s=%d\n", g_pname,
 215                             topo_node_name(node), topo_node_instance(node));
 216                         nvlist_free(fmri);
 217                         return;
 218                 }
 219 
 220                 errno = 0;
 221                 ul = strtoul(inst, &estr, 10);
 222 
 223                 if (errno != 0 || estr == inst) {
 224                         (void) fprintf(stderr, "%s: instance %s does not "
 225                             "convert to an unsigned integer\n", g_pname, inst);
 226                 }
 227 
 228                 (void) strlcat(buf, "/", sizeof (buf));
 229                 (void) strlcat(buf, name, sizeof (buf));
 230                 (void) snprintf(numbuf, sizeof (numbuf), "%u", ul);
 231                 (void) strlcat(buf, numbuf, sizeof (buf));
 232         }
 233         nvlist_free(fmri);
 234 
 235         (void) printf("%s\n", buf);
 236 }
 237 
 238 static void
 239 print_prop_nameval(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl)
 240 {
 241         int err;
 242         topo_type_t type;
 243         char *tstr, *propn, buf[48], *factype;
 244         nvpair_t *pv_nvp;
 245         int i;
 246         uint_t nelem;
 247 
 248         if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL)
 249                 return;
 250 
 251         /* Print property name */
 252         if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL ||
 253             nvpair_name(pv_nvp) == NULL ||
 254             strcmp(TOPO_PROP_VAL_NAME, nvpair_name(pv_nvp)) != 0) {
 255                 (void) fprintf(stderr, "%s: malformed property name\n",
 256                     g_pname);
 257                 return;
 258         } else {
 259                 (void) nvpair_value_string(pv_nvp, &propn);
 260         }
 261 
 262         if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL ||
 263             nvpair_name(pv_nvp) == NULL ||
 264             strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 ||
 265             nvpair_type(pv_nvp) != DATA_TYPE_UINT32)  {
 266                 (void) fprintf(stderr, "%s: malformed property type for %s\n",
 267                     g_pname, propn);
 268                 return;
 269         } else {
 270                 (void) nvpair_value_uint32(pv_nvp, (uint32_t *)&type);
 271         }
 272 
 273         switch (type) {
 274                 case TOPO_TYPE_BOOLEAN: tstr = "boolean"; break;
 275                 case TOPO_TYPE_INT32: tstr = "int32"; break;
 276                 case TOPO_TYPE_UINT32: tstr = "uint32"; break;
 277                 case TOPO_TYPE_INT64: tstr = "int64"; break;
 278                 case TOPO_TYPE_UINT64: tstr = "uint64"; break;
 279                 case TOPO_TYPE_DOUBLE: tstr = "double"; break;
 280                 case TOPO_TYPE_STRING: tstr = "string"; break;
 281                 case TOPO_TYPE_FMRI: tstr = "fmri"; break;
 282                 case TOPO_TYPE_INT32_ARRAY: tstr = "int32[]"; break;
 283                 case TOPO_TYPE_UINT32_ARRAY: tstr = "uint32[]"; break;
 284                 case TOPO_TYPE_INT64_ARRAY: tstr = "int64[]"; break;
 285                 case TOPO_TYPE_UINT64_ARRAY: tstr = "uint64[]"; break;
 286                 case TOPO_TYPE_STRING_ARRAY: tstr = "string[]"; break;
 287                 case TOPO_TYPE_FMRI_ARRAY: tstr = "fmri[]"; break;
 288                 default: tstr = "unknown type";
 289         }
 290 
 291         (void) printf("    %-17s %-8s ", propn, tstr);
 292 
 293         /*
 294          * Get property value
 295          */
 296         if (nvpair_name(pv_nvp) == NULL ||
 297             (pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL) {
 298                 (void) fprintf(stderr, "%s: malformed property value\n",
 299                     g_pname);
 300                 return;
 301         }
 302 
 303         switch (nvpair_type(pv_nvp)) {
 304                 case DATA_TYPE_INT32: {
 305                         int32_t val;
 306                         (void) nvpair_value_int32(pv_nvp, &val);
 307                         (void) printf(" %d", val);
 308                         break;
 309                 }
 310                 case DATA_TYPE_UINT32: {
 311                         uint32_t val, type;
 312                         char val_str[49];
 313                         nvlist_t *fac, *rsrc = NULL;
 314 
 315                         (void) nvpair_value_uint32(pv_nvp, &val);
 316                         if (node == NULL || topo_node_flags(node) !=
 317                             TOPO_NODE_FACILITY)
 318                                 goto uint32_def;
 319 
 320                         if (topo_node_resource(node, &rsrc, &err) != 0)
 321                                 goto uint32_def;
 322 
 323                         if (nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0)
 324                                 goto uint32_def;
 325 
 326                         if (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE,
 327                             &factype) != 0)
 328                                 goto uint32_def;
 329 
 330                         nvlist_free(rsrc);
 331                         rsrc = NULL;
 332 
 333                         /*
 334                          * Special case code to do friendlier printing of
 335                          * facility node properties
 336                          */
 337                         if ((strcmp(propn, TOPO_FACILITY_TYPE) == 0) &&
 338                             (strcmp(factype, TOPO_FAC_TYPE_SENSOR) == 0)) {
 339                                 topo_sensor_type_name(val, val_str, 48);
 340                                 (void) printf(" 0x%x (%s)", val, val_str);
 341                                 break;
 342                         } else if ((strcmp(propn, TOPO_FACILITY_TYPE) == 0) &&
 343                             (strcmp(factype, TOPO_FAC_TYPE_INDICATOR) == 0)) {
 344                                 topo_led_type_name(val, val_str, 48);
 345                                 (void) printf(" 0x%x (%s)", val, val_str);
 346                                 break;
 347                         } else if (strcmp(propn, TOPO_SENSOR_UNITS) == 0) {
 348                                 topo_sensor_units_name(val, val_str, 48);
 349                                 (void) printf(" 0x%x (%s)", val, val_str);
 350                                 break;
 351                         } else if (strcmp(propn, TOPO_LED_MODE) == 0) {
 352                                 topo_led_state_name(val, val_str, 48);
 353                                 (void) printf(" 0x%x (%s)", val, val_str);
 354                                 break;
 355                         } else if ((strcmp(propn, TOPO_SENSOR_STATE) == 0) &&
 356                             (strcmp(factype, TOPO_FAC_TYPE_SENSOR) == 0)) {
 357                                 if (topo_prop_get_uint32(node,
 358                                     TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
 359                                     &type, &err) != 0) {
 360                                         goto uint32_def;
 361                                 }
 362                                 topo_sensor_state_name(type, val, val_str, 48);
 363                                 (void) printf(" 0x%x (%s)", val, val_str);
 364                                 break;
 365                         }
 366 uint32_def:
 367                         (void) printf(" 0x%x", val);
 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 = NULL;
 601         char *end;
 602 
 603         if (pp->prop == NULL || pp->type == NULL || pp->value == NULL)
 604                 goto out;
 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                 goto out;
 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                 goto out;
 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                 goto out;
 623         }
 624 
 625         errno = 0;
 626         switch (type) {
 627                 case TOPO_TYPE_INT32:
 628                 {
 629                         int32_t val;
 630 
 631                         val = strtol(pp->value, &end, 0);
 632                         if (errno == ERANGE) {
 633                                 ret = -1;
 634                                 break;
 635                         }
 636                         ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val);
 637                         break;
 638                 }
 639                 case TOPO_TYPE_UINT32:
 640                 {
 641                         uint32_t val;
 642 
 643                         val = strtoul(pp->value, &end, 0);
 644                         if (errno == ERANGE) {
 645                                 ret = -1;
 646                                 break;
 647                         }
 648                         ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val);
 649                         break;
 650                 }
 651                 case TOPO_TYPE_INT64:
 652                 {
 653                         int64_t val;
 654 
 655                         val = strtoll(pp->value, &end, 0);
 656                         if (errno == ERANGE) {
 657                                 ret = -1;
 658                                 break;
 659                         }
 660                         ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val);
 661                         break;
 662                 }
 663                 case TOPO_TYPE_UINT64:
 664                 {
 665                         uint64_t val;
 666 
 667                         val = strtoull(pp->value, &end, 0);
 668                         if (errno == ERANGE) {
 669                                 ret = -1;
 670                                 break;
 671                         }
 672                         ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val);
 673                         break;
 674                 }
 675                 case TOPO_TYPE_STRING:
 676                 {
 677                         ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
 678                             pp->value);
 679                         break;
 680                 }
 681                 case TOPO_TYPE_FMRI:
 682                 {
 683                         nvlist_t *val = NULL;
 684 
 685                         if ((ret = topo_fmri_str2nvl(thp, pp->value, &val,
 686                             &err)) < 0)
 687                                 break;
 688 
 689                         if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
 690                             val)) != 0)
 691                                 err = ETOPO_PROP_NVL;
 692 
 693                         nvlist_free(val);
 694                         break;
 695                 }
 696                 default:
 697                         ret = -1;
 698         }
 699 
 700         if (ret != 0) {
 701                 (void) fprintf(stderr, "%s: unable to set property value for "
 702                     "%s: %s\n", g_pname, pp->prop,  topo_strerror(err));
 703                 goto out;
 704         }
 705 
 706         if (node != NULL) {
 707                 if ((ret = topo_prop_setprop(node, pp->group, nvl,
 708                     TOPO_PROP_MUTABLE, nvl, &err)) < 0) {
 709                         (void) fprintf(stderr, "%s: unable to set property "
 710                             "value for " "%s=%s:%s: %s\n", g_pname, pp->prop,
 711                             pp->type, pp->value, topo_strerror(err));
 712                         goto out;
 713                 }
 714         } else {
 715                 if ((ret = topo_fmri_setprop(thp, fmri,  pp->group, nvl,
 716                     TOPO_PROP_MUTABLE, nvl, &err)) < 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(err));
 720                         goto out;
 721                 }
 722         }
 723 
 724         nvlist_free(nvl);
 725         nvl = NULL;
 726 
 727         /*
 728          * Now, get the property back for printing
 729          */
 730         if (node != NULL) {
 731                 if ((ret = topo_prop_getprop(node, pp->group, pp->prop, NULL,
 732                     &nvl, &err)) < 0) {
 733                         (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
 734                             g_pname, pp->group, pp->prop, topo_strerror(err));
 735                         goto out;
 736                 }
 737         } else {
 738                 if ((ret = topo_fmri_getprop(thp, fmri, pp->group, pp->prop,
 739                     NULL, &nvl, &err)) < 0) {
 740                         (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
 741                             g_pname, pp->group, pp->prop, topo_strerror(err));
 742                         goto out;
 743                 }
 744         }
 745 
 746         print_pgroup(thp, node, pp->group, NULL, NULL, 0);
 747         print_prop_nameval(thp, node, nvl);
 748 
 749 out:
 750         nvlist_free(nvl);
 751 }
 752 
 753 static void
 754 print_props(topo_hdl_t *thp, tnode_t *node)
 755 {
 756         int i, err;
 757         nvlist_t *nvl;
 758         struct prop_args *pp;
 759 
 760         if (pcnt == 0)
 761                 return;
 762 
 763         for (i = 0; i < pcnt; ++i) {
 764                 pp = pargs[i];
 765 
 766                 if (pp->group == NULL)
 767                         continue;
 768 
 769                 /*
 770                  * If we have a valid value, this is a request to
 771                  * set a property.  Otherwise, just print the property
 772                  * group and any specified properties.
 773                  */
 774                 if (pp->value == NULL) {
 775                         if (pp->prop == NULL) {
 776 
 777                                 /*
 778                                  * Print all properties in this group
 779                                  */
 780                                 if ((nvl = topo_prop_getprops(node, &err))
 781                                     == NULL) {
 782                                         (void) fprintf(stderr, "%s: failed to "
 783                                             "get %s: %s\n", g_pname,
 784                                             pp->group,
 785                                             topo_strerror(err));
 786                                         continue;
 787                                 } else {
 788                                         print_all_props(thp, node, nvl,
 789                                             pp->group);
 790                                         nvlist_free(nvl);
 791                                         continue;
 792                                 }
 793                         }
 794                         if (topo_prop_getprop(node, pp->group, pp->prop,
 795                             NULL, &nvl, &err) < 0) {
 796                                 (void) fprintf(stderr, "%s: failed to get "
 797                                     "%s.%s: %s\n", g_pname,
 798                                     pp->group, pp->prop,
 799                                     topo_strerror(err));
 800                                 continue;
 801                         } else {
 802                                 print_pgroup(thp, node, pp->group, NULL,
 803                                     NULL, 0);
 804                                 print_prop_nameval(thp, node, nvl);
 805                                 nvlist_free(nvl);
 806                         }
 807                 } else {
 808                         set_prop(thp, node, NULL, pp);
 809                 }
 810         }
 811 }
 812 
 813 /*ARGSUSED*/
 814 static int
 815 walk_node(topo_hdl_t *thp, tnode_t *node, void *arg)
 816 {
 817         int err;
 818         nvlist_t *nvl;
 819         nvlist_t *rsrc, *out;
 820         char *s;
 821 
 822         if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
 823                 print_everstyle(node);
 824                 return (TOPO_WALK_NEXT);
 825         }
 826 
 827         if (topo_node_resource(node, &rsrc, &err) < 0) {
 828                 (void) fprintf(stderr, "%s: failed to get resource: "
 829                     "%s", g_pname, topo_strerror(err));
 830                 return (TOPO_WALK_NEXT);
 831         }
 832         if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) {
 833                 (void) fprintf(stderr, "%s: failed to convert "
 834                     "resource to FMRI string: %s", g_pname,
 835                     topo_strerror(err));
 836                 nvlist_free(rsrc);
 837                 return (TOPO_WALK_NEXT);
 838         }
 839 
 840         if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) {
 841                 nvlist_free(rsrc);
 842                 topo_hdl_strfree(thp, s);
 843                 return (TOPO_WALK_NEXT);
 844         }
 845 
 846         print_node(thp, node, rsrc, s);
 847         topo_hdl_strfree(thp, s);
 848         nvlist_free(rsrc);
 849 
 850         if (opt_m != NULL) {
 851                 if (topo_method_invoke(node, opt_m, 0, NULL, &out, &err) == 0) {
 852                         nvlist_print(stdout, out);
 853                         nvlist_free(out);
 854                 } else if (err != ETOPO_METHOD_NOTSUP)
 855                         (void) fprintf(stderr, "%s: method failed unexpectedly "
 856                             "on %s=%d (%s)\n", g_pname, topo_node_name(node),
 857                             topo_node_instance(node), topo_strerror(err));
 858         }
 859 
 860         if (opt_V || opt_all) {
 861                 if ((nvl = topo_prop_getprops(node, &err)) == NULL) {
 862                         (void) fprintf(stderr, "%s: failed to get "
 863                             "properties for %s=%d: %s\n", g_pname,
 864                             topo_node_name(node), topo_node_instance(node),
 865                             topo_strerror(err));
 866                 } else {
 867                         print_all_props(thp, node, nvl, ALL);
 868                         nvlist_free(nvl);
 869                 }
 870         } else if (pcnt > 0)
 871                 print_props(thp, node);
 872 
 873         (void) printf("\n");
 874 
 875         return (TOPO_WALK_NEXT);
 876 }
 877 
 878 static void
 879 get_pargs(int argc, char *argv[])
 880 {
 881         struct prop_args *pp;
 882         char c, *s, *p;
 883         int i = 0;
 884 
 885         if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) {
 886                 (void) fprintf(stderr, "%s: failed to allocate property "
 887                     "arguments\n", g_pname);
 888                 return;
 889         }
 890 
 891         for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) {
 892                 if (c == 'P') {
 893 
 894                         if (strcmp(optarg, ALL) == 0) {
 895                                 opt_all++;
 896                                 break;
 897                         }
 898 
 899                         if ((pp = pargs[i] = malloc(sizeof (struct prop_args)))
 900                             == NULL) {
 901                                 (void) fprintf(stderr, "%s: failed to "
 902                                     "allocate propertyarguments\n", g_pname);
 903                                 return;
 904                         }
 905                         ++i;
 906                         pp->group = NULL;
 907                         pp->prop = NULL;
 908                         pp->type = NULL;
 909                         pp->value = NULL;
 910 
 911                         p = optarg;
 912                         if ((s = strchr(p, '.')) != NULL) {
 913                                 *s++ = '\0'; /* strike out delimiter */
 914                                 pp->group = p;
 915                                 p = s;
 916                                 if ((s = strchr(p, '=')) != NULL) {
 917                                         *s++ = '\0'; /* strike out delimiter */
 918                                         pp->prop = p;
 919                                         p = s;
 920                                         if ((s = strchr(p, ':')) != NULL) {
 921                                                 *s++ = '\0';
 922                                                 pp->type = p;
 923                                                 pp->value = s;
 924                                         } else {
 925                                                 (void) fprintf(stderr, "%s: "
 926                                                     "property type not "
 927                                                     "specified for assignment "
 928                                                     " of %s.%s\n", g_pname,
 929                                                     pp->group, pp->prop);
 930                                                 break;
 931                                         }
 932                                 } else {
 933                                         pp->prop = p;
 934                                 }
 935                         } else {
 936                                 pp->group = p;
 937                         }
 938                         if (i >= pcnt)
 939                                 break;
 940                 }
 941         }
 942 
 943         if (opt_all > 0) {
 944                 int j;
 945 
 946                 for (j = 0; j < i; ++j)
 947                         free(pargs[i]);
 948                 free(pargs);
 949                 pargs = NULL;
 950         }
 951 }
 952 
 953 static int
 954 walk_topo(topo_hdl_t *thp, char *uuid)
 955 {
 956         int err;
 957         topo_walk_t *twp;
 958         int flag;
 959 
 960         if (getzoneid() != GLOBAL_ZONEID &&
 961             strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
 962                 return (0);
 963         }
 964 
 965         if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err))
 966             == NULL) {
 967                 (void) fprintf(stderr, "%s: failed to walk %s topology:"
 968                     " %s\n", g_pname, opt_s, topo_strerror(err));
 969 
 970                 return (-1);
 971         }
 972 
 973         /*
 974          * Print standard header
 975          */
 976         if (!opt_e) {
 977                 char buf[32];
 978                 time_t tod = time(NULL);
 979 
 980                 (void) printf("TIME                 UUID\n");
 981                 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
 982                 (void) printf("%-15s %-32s\n", buf, uuid);
 983                 (void) printf("\n");
 984         }
 985 
 986         flag = opt_b != 0 ? TOPO_WALK_SIBLING : TOPO_WALK_CHILD;
 987 
 988         if (topo_walk_step(twp, flag) == TOPO_WALK_ERR) {
 989                 (void) fprintf(stderr, "%s: failed to walk topology\n",
 990                     g_pname);
 991                 topo_walk_fini(twp);
 992                 return (-1);
 993         }
 994 
 995         topo_walk_fini(twp);
 996 
 997         return (0);
 998 }
 999 
1000 static void
1001 print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl)
1002 {
1003         char *dstab = NULL, *nstab = NULL;
1004         int32_t version = -1;
1005         nvlist_t *pnvl;
1006         nvpair_t *pnvp;
1007 
1008         (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab);
1009         (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab);
1010         (void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version);
1011 
1012         print_pgroup(thp, NULL, pgn, dstab, nstab, version);
1013 
1014         for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL;
1015             pnvp = nvlist_next_nvpair(nvl, pnvp)) {
1016 
1017                 /*
1018                  * Print property group and property name-value pair
1019                  */
1020                 if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp))
1021                     == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) {
1022                         (void) nvpair_value_nvlist(pnvp, &pnvl);
1023                                 print_prop_nameval(thp, NULL, pnvl);
1024 
1025                 }
1026 
1027         }
1028 }
1029 
1030 static void
1031 print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl)
1032 {
1033         int i, err;
1034         struct prop_args *pp;
1035         nvlist_t *pnvl;
1036 
1037         for (i = 0; i < pcnt; ++i) {
1038                 pp = pargs[i];
1039 
1040                 if (pp->group == NULL)
1041                         continue;
1042 
1043                 pnvl = NULL;
1044 
1045                 /*
1046                  * If we have a valid value, this is a request to
1047                  * set a property.  Otherwise, just print the property
1048                  * group and any specified properties.
1049                  */
1050                 if (pp->value == NULL) {
1051                         if (pp->prop == NULL) {
1052 
1053                                 /*
1054                                  * Print all properties in this group
1055                                  */
1056                                 if (topo_fmri_getpgrp(thp, nvl, pp->group,
1057                                     &pnvl, &err) < 0) {
1058                                         (void) fprintf(stderr, "%s: failed to "
1059                                             "get group %s: %s\n", g_pname,
1060                                             pp->group, topo_strerror(err));
1061                                         continue;
1062                                 } else {
1063                                         print_fmri_pgroup(thp, pp->group,
1064                                             pnvl);
1065                                         nvlist_free(pnvl);
1066                                         continue;
1067                                 }
1068                         }
1069                         if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop,
1070                             NULL, &pnvl, &err) < 0) {
1071                                 (void) fprintf(stderr, "%s: failed to get "
1072                                     "%s.%s: %s\n", g_pname,
1073                                     pp->group, pp->prop,
1074                                     topo_strerror(err));
1075                                 continue;
1076                         } else {
1077                                 print_fmri_pgroup(thp, pp->group, pnvl);
1078                                 print_prop_nameval(thp, NULL, pnvl);
1079                                 nvlist_free(nvl);
1080                         }
1081                 } else {
1082                         set_prop(thp, NULL, nvl, pp);
1083                 }
1084         }
1085 }
1086 
1087 void
1088 print_fmri(topo_hdl_t *thp, char *uuid)
1089 {
1090         int ret, err;
1091         nvlist_t *nvl;
1092         char buf[32];
1093         time_t tod = time(NULL);
1094 
1095         if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
1096                 (void) fprintf(stderr, "%s: failed to convert %s to nvlist: "
1097                     "%s\n", g_pname, g_fmri, topo_strerror(err));
1098                 return;
1099         }
1100 
1101         (void) printf("TIME                 UUID\n");
1102         (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
1103         (void) printf("%-15s %-32s\n", buf, uuid);
1104         (void) printf("\n");
1105 
1106         (void) printf("%s\n", (char *)g_fmri);
1107 
1108         if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
1109                 char *aname = NULL, *fname = NULL, *lname = NULL;
1110                 nvlist_t *asru = NULL;
1111                 nvlist_t *fru = NULL;
1112 
1113                 if (topo_fmri_asru(thp, nvl, &asru, &err) == 0)
1114                         (void) topo_fmri_nvl2str(thp, asru, &aname, &err);
1115                 if (topo_fmri_fru(thp, nvl, &fru, &err) == 0)
1116                         (void) topo_fmri_nvl2str(thp, fru, &fname, &err);
1117                 (void) topo_fmri_label(thp, nvl, &lname, &err);
1118 
1119                 nvlist_free(fru);
1120                 nvlist_free(asru);
1121 
1122                 if (aname != NULL) {
1123                         (void) printf("\tASRU: %s\n", aname);
1124                         topo_hdl_strfree(thp, aname);
1125                 } else {
1126                         (void) printf("\tASRU: -\n");
1127                 }
1128                 if (fname != NULL) {
1129                         (void) printf("\tFRU: %s\n", fname);
1130                         topo_hdl_strfree(thp, fname);
1131                 } else {
1132                         (void) printf("\tFRU: -\n");
1133                 }
1134                 if (lname != NULL) {
1135                         (void) printf("\tLabel: %s\n", lname);
1136                         topo_hdl_strfree(thp, lname);
1137                 } else {
1138                         (void) printf("\tLabel: -\n");
1139                 }
1140         }
1141 
1142         if (opt_S) {
1143                 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
1144                         (void) printf("\tPresent: -\n");
1145                         (void) printf("\tUnusable: -\n");
1146                         return;
1147                 }
1148 
1149                 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
1150                         (void) printf("\tPresent: -\n");
1151                 else
1152                         (void) printf("\tPresent: %s\n",
1153                             ret ? "true" : "false");
1154 
1155                 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
1156                         (void) printf("\tUnusable: -\n");
1157                 else
1158                         (void) printf("\tUnusable: %s\n",
1159                             ret ? "true" : "false");
1160 
1161                 nvlist_free(nvl);
1162         }
1163 
1164         if (pargs && pcnt > 0)
1165                 print_fmri_props(thp, nvl);
1166 }
1167 
1168 int
1169 fmtopo_exit(topo_hdl_t *thp, char *uuid, int err)
1170 {
1171         if (uuid != NULL)
1172                 topo_hdl_strfree(thp, uuid);
1173 
1174         if (thp != NULL) {
1175                 topo_snap_release(thp);
1176                 topo_close(thp);
1177         }
1178 
1179         if (pargs) {
1180                 int i;
1181                 for (i = 0; i < pcnt; ++i)
1182                         free(pargs[i]);
1183                 free(pargs);
1184         }
1185 
1186         return (err);
1187 }
1188 
1189 int
1190 main(int argc, char *argv[])
1191 {
1192         topo_hdl_t *thp = NULL;
1193         char *uuid = NULL;
1194         int c, err = 0;
1195 
1196         g_pname = argv[0];
1197 
1198         while (optind < argc) {
1199                 while ((c = getopt(argc, argv, optstr)) != -1) {
1200                         switch (c) {
1201                         case 'b':
1202                                 opt_b++;
1203                                 break;
1204                         case 'C':
1205                                 (void) atexit(abort);
1206                                 break;
1207                         case 'd':
1208                                 opt_d++;
1209                                 break;
1210                         case 'e':
1211                                 opt_e++;
1212                                 break;
1213                         case 'm':
1214                                 opt_m = optarg;
1215                                 break;
1216                         case 'P':
1217                                 pcnt++;
1218                                 break;
1219                         case 'p':
1220                                 opt_p++;
1221                                 break;
1222                         case 'V':
1223                                 opt_V++;
1224                                 break;
1225                         case 'R':
1226                                 opt_R = optarg;
1227                                 break;
1228                         case 's':
1229                                 opt_s = optarg;
1230                                 break;
1231                         case 'S':
1232                                 opt_S++;
1233                                 break;
1234                         case 't':
1235                                 opt_t++;
1236                                 break;
1237                         case 'x':
1238                                 opt_x++;
1239                                 break;
1240                         default:
1241                                 return (usage(stderr));
1242                         }
1243                 }
1244 
1245                 if (optind < argc) {
1246                         if (g_fmri != NULL) {
1247                                 (void) fprintf(stderr, "%s: illegal argument "
1248                                     "-- %s\n", g_pname, argv[optind]);
1249                                 return (FMTOPO_EXIT_USAGE);
1250                         } else {
1251                                 g_fmri = argv[optind++];
1252                         }
1253                 }
1254         }
1255 
1256         if (pcnt > 0)
1257                 get_pargs(argc, argv);
1258 
1259         if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) {
1260                 (void) fprintf(stderr, "%s: failed to open topology tree: %s\n",
1261                     g_pname, topo_strerror(err));
1262                 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1263         }
1264 
1265         if (opt_d)
1266                 topo_debug_set(thp, "module", "stderr");
1267 
1268         if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) {
1269                 (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n",
1270                     g_pname, topo_strerror(err));
1271                 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1272         } else if (err != 0) {
1273                 (void) fprintf(stderr, "%s: topology snapshot incomplete%s\n",
1274                     g_pname, getzoneid() != GLOBAL_ZONEID &&
1275                     strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0 ?
1276                     " (" FM_FMRI_SCHEME_HC " scheme does not enumerate "
1277                     "in a non-global zone)": "");
1278         }
1279 
1280         if (opt_x) {
1281                 if (opt_b) {
1282                         (void) fprintf(stderr,
1283                             "%s: -b and -x cannot be specified together\n",
1284                             g_pname);
1285                         return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_USAGE));
1286                 }
1287 
1288                 err = 0;
1289                 if (topo_xml_print(thp, stdout, opt_s, &err) < 0)
1290                         (void) fprintf(stderr, "%s: failed to print xml "
1291                             "formatted topology:%s",  g_pname,
1292                             topo_strerror(err));
1293 
1294                 return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR :
1295                     FMTOPO_EXIT_SUCCESS));
1296         }
1297 
1298         if (opt_t || walk_topo(thp, uuid) < 0) {
1299                 if (g_fmri != NULL)
1300                         /*
1301                          * Try getting some useful information
1302                          */
1303                         print_fmri(thp, uuid);
1304 
1305                 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1306         }
1307 
1308         return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_SUCCESS));
1309 }