xref: /titanic_50/usr/src/cmd/fm/fmtopo/common/fmtopo.c (revision 6aa4fc89ec1cf2cdf7d7c3b9ec059802ac9abe65)
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 }
1311