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