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