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