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