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