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