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