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
47 static const char *g_pname;
48 static const char *g_fmri = NULL;
49
50 static const char *opt_R = "/";
51 static const char *opt_s = FM_FMRI_SCHEME_HC;
52 static const char optstr[] = "bCdem:P:pR:s:StVx";
53 static const char *opt_m;
54
55 static int opt_b = 0;
56 static int opt_d = 0;
57 static int opt_e = 0;
58 static int opt_p = 0;
59 static int opt_S = 0;
60 static int opt_t = 0;
61 static int opt_V = 0;
62 static int opt_x = 0;
63 static int opt_all = 0;
64
65 struct prop_args {
66 const char *group;
67 const char *prop;
68 const char *type;
69 const char *value;
70 };
71
72 static struct prop_args **pargs = NULL;
73 static int pcnt = 0;
74
75 static int
usage(FILE * fp)76 usage(FILE *fp)
77 {
78 (void) fprintf(fp,
79 "Usage: %s [-bCedpSVx] [-P group.property[=type:value]] "
80 "[-R root] [-m method] [-s scheme] [fmri]\n", g_pname);
81
82 (void) fprintf(fp,
83 "\t-b walk in sibling-first order (default is child-first)\n"
84 "\t-C dump core after completing execution\n"
85 "\t-d set debug mode for libtopo modules\n"
86 "\t-e display FMRIs as paths using esc/eft notation\n"
87 "\t-m execute given method\n"
88 "\t-P get/set specified properties\n"
89 "\t-p display of FMRI protocol properties\n"
90 "\t-R set root directory for libtopo plug-ins and other files\n"
91 "\t-s display topology for the specified FMRI scheme\n"
92 "\t-S display FMRI status (present/usable)\n"
93 "\t-V set verbose mode\n"
94 "\t-x display a xml formatted topology\n");
95
96 return (FMTOPO_EXIT_USAGE);
97 }
98
99 static topo_type_t
str2type(const char * tstr)100 str2type(const char *tstr)
101 {
102 topo_type_t type;
103
104 if (tstr == NULL)
105 return (TOPO_TYPE_INVALID);
106
107 if (strcmp(tstr, "int32") == 0)
108 type = TOPO_TYPE_INT32;
109 else if (strcmp(tstr, "uint32") == 0)
110 type = TOPO_TYPE_UINT32;
111 else if (strcmp(tstr, "int64") == 0)
112 type = TOPO_TYPE_INT64;
113 else if (strcmp(tstr, "uint64") == 0)
114 type = TOPO_TYPE_UINT64;
115 else if (strcmp(tstr, "string") == 0)
116 type = TOPO_TYPE_STRING;
117 else if (strcmp(tstr, "fmri") == 0)
118 type = TOPO_TYPE_FMRI;
119 else {
120 type = TOPO_TYPE_INVALID;
121 }
122
123 return (type);
124 }
125
126 static void
print_node(topo_hdl_t * thp,tnode_t * node,nvlist_t * nvl,const char * fmri)127 print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri)
128 {
129 int err, ret;
130
131 (void) printf("%s\n", (char *)fmri);
132
133 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
134 char *aname = NULL, *fname = NULL, *lname = NULL;
135 nvlist_t *asru = NULL;
136 nvlist_t *fru = NULL;
137
138 if (topo_node_asru(node, &asru, NULL, &err) == 0)
139 (void) topo_fmri_nvl2str(thp, asru, &aname, &err);
140 if (topo_node_fru(node, &fru, NULL, &err) == 0)
141 (void) topo_fmri_nvl2str(thp, fru, &fname, &err);
142 (void) topo_node_label(node, &lname, &err);
143 if (aname != NULL) {
144 nvlist_free(asru);
145 (void) printf("\tASRU: %s\n", aname);
146 topo_hdl_strfree(thp, aname);
147 } else {
148 (void) printf("\tASRU: -\n");
149 }
150 if (fname != NULL) {
151 nvlist_free(fru);
152 (void) printf("\tFRU: %s\n", fname);
153 topo_hdl_strfree(thp, fname);
154 } else {
155 (void) printf("\tFRU: -\n");
156 }
157 if (lname != NULL) {
158 (void) printf("\tLabel: %s\n", lname);
159 topo_hdl_strfree(thp, lname);
160 } else {
161 (void) printf("\tLabel: -\n");
162 }
163 }
164
165 if (opt_S) {
166 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
167 (void) printf("\tPresent: -\n");
168 else
169 (void) printf("\tPresent: %s\n",
170 ret ? "true" : "false");
171
172 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
173 (void) printf("\tUnusable: -\n");
174 else
175 (void) printf("\tUnusable: %s\n",
176 ret ? "true" : "false");
177 }
178 }
179
180 static void
print_everstyle(tnode_t * node)181 print_everstyle(tnode_t *node)
182 {
183 char buf[PATH_MAX], numbuf[64];
184 nvlist_t *fmri, **hcl;
185 int i, err;
186 uint_t n;
187
188 if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL,
189 TOPO_PROP_RESOURCE, &fmri, &err) < 0) {
190 (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n",
191 g_pname, topo_node_name(node),
192 topo_node_instance(node), topo_strerror(err));
193 return;
194 }
195
196 if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
197 (void) fprintf(stderr, "%s: failed to find %s for %s=%d\n",
198 g_pname, FM_FMRI_HC_LIST, topo_node_name(node),
199 topo_node_instance(node));
200 nvlist_free(fmri);
201 return;
202 }
203
204 buf[0] = '\0';
205
206 for (i = 0; i < n; i++) {
207 char *name, *inst, *estr;
208 ulong_t ul;
209
210 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0 ||
211 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &inst) != 0) {
212 (void) fprintf(stderr, "%s: failed to get "
213 "name-instance for %s=%d\n", g_pname,
214 topo_node_name(node), topo_node_instance(node));
215 nvlist_free(fmri);
216 return;
217 }
218
219 errno = 0;
220 ul = strtoul(inst, &estr, 10);
221
222 if (errno != 0 || estr == inst) {
223 (void) fprintf(stderr, "%s: instance %s does not "
224 "convert to an unsigned integer\n", g_pname, inst);
225 }
226
227 (void) strlcat(buf, "/", sizeof (buf));
228 (void) strlcat(buf, name, sizeof (buf));
229 (void) snprintf(numbuf, sizeof (numbuf), "%u", ul);
230 (void) strlcat(buf, numbuf, sizeof (buf));
231 }
232 nvlist_free(fmri);
233
234 (void) printf("%s\n", buf);
235 }
236
237 static void
print_prop_nameval(topo_hdl_t * thp,tnode_t * node,nvlist_t * nvl)238 print_prop_nameval(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl)
239 {
240 int err;
241 topo_type_t type;
242 char *tstr, *propn, 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 }
365 uint32_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
479 static void
print_pgroup(topo_hdl_t * thp,tnode_t * node,const char * pgn,char * dstab,char * nstab,int32_t version)480 print_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
517 static void
print_all_props(topo_hdl_t * thp,tnode_t * node,nvlist_t * p_nv,const char * group)518 print_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
595 static void
set_prop(topo_hdl_t * thp,tnode_t * node,nvlist_t * fmri,struct prop_args * pp)596 set_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
756 static void
print_props(topo_hdl_t * thp,tnode_t * node)757 print_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*/
817 static int
walk_node(topo_hdl_t * thp,tnode_t * node,void * arg)818 walk_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
881 static void
get_pargs(int argc,char * argv[])882 get_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
956 static int
walk_topo(topo_hdl_t * thp,char * uuid)957 walk_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
1003 static void
print_fmri_pgroup(topo_hdl_t * thp,const char * pgn,nvlist_t * nvl)1004 print_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
1033 static void
print_fmri_props(topo_hdl_t * thp,nvlist_t * nvl)1034 print_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
1090 void
print_fmri(topo_hdl_t * thp,char * uuid)1091 print_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
1171 int
fmtopo_exit(topo_hdl_t * thp,char * uuid,int err)1172 fmtopo_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
1192 int
main(int argc,char * argv[])1193 main(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