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