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 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
25 */
26
27
28 #include <sys/fm/protocol.h>
29 #include <fm/libtopo.h>
30 #include <ctype.h>
31 #include <fnmatch.h>
32 #include <limits.h>
33 #include <strings.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #include <umem.h>
37 #include <zone.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[] = "bCdem:P:pR:s:StVx";
54 static const char *opt_m;
55
56 static int opt_b = 0;
57 static int opt_d = 0;
58 static int opt_e = 0;
59 static int opt_p = 0;
60 static int opt_S = 0;
61 static int opt_t = 0;
62 static int opt_V = 0;
63 static int opt_x = 0;
64 static int opt_all = 0;
65
66 struct prop_args {
67 const char *group;
68 const char *prop;
69 const char *type;
70 const char *value;
71 };
72
73 static struct prop_args **pargs = NULL;
74 static int pcnt = 0;
75
76 static int
usage(FILE * fp)77 usage(FILE *fp)
78 {
79 (void) fprintf(fp,
80 "Usage: %s [-bCedpSVx] [-P group.property[=type:value]] "
81 "[-R root] [-m method] [-s scheme] [fmri]\n", g_pname);
82
83 (void) fprintf(fp,
84 "\t-b walk in sibling-first order (default is child-first)\n"
85 "\t-C dump core after completing execution\n"
86 "\t-d set debug mode for libtopo modules\n"
87 "\t-e display FMRIs as paths using esc/eft notation\n"
88 "\t-m execute given method\n"
89 "\t-P get/set specified properties\n"
90 "\t-p display of FMRI protocol properties\n"
91 "\t-R set root directory for libtopo plug-ins and other files\n"
92 "\t-s display topology for the specified FMRI scheme\n"
93 "\t-S display FMRI status (present/usable)\n"
94 "\t-V set verbose mode\n"
95 "\t-x display a xml formatted topology\n");
96
97 return (FMTOPO_EXIT_USAGE);
98 }
99
100 static topo_type_t
str2type(const char * tstr)101 str2type(const char *tstr)
102 {
103 topo_type_t type;
104
105 if (tstr == NULL)
106 return (TOPO_TYPE_INVALID);
107
108 if (strcmp(tstr, "int32") == 0)
109 type = TOPO_TYPE_INT32;
110 else if (strcmp(tstr, "uint32") == 0)
111 type = TOPO_TYPE_UINT32;
112 else if (strcmp(tstr, "int64") == 0)
113 type = TOPO_TYPE_INT64;
114 else if (strcmp(tstr, "uint64") == 0)
115 type = TOPO_TYPE_UINT64;
116 else if (strcmp(tstr, "string") == 0)
117 type = TOPO_TYPE_STRING;
118 else if (strcmp(tstr, "fmri") == 0)
119 type = TOPO_TYPE_FMRI;
120 else {
121 type = TOPO_TYPE_INVALID;
122 }
123
124 return (type);
125 }
126
127 static void
print_node(topo_hdl_t * thp,tnode_t * node,nvlist_t * nvl,const char * fmri)128 print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri)
129 {
130 int err, ret;
131
132 (void) printf("%s\n", (char *)fmri);
133
134 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
135 char *aname = NULL, *fname = NULL, *lname = NULL;
136 nvlist_t *asru = NULL;
137 nvlist_t *fru = NULL;
138
139 if (topo_node_asru(node, &asru, NULL, &err) == 0)
140 (void) topo_fmri_nvl2str(thp, asru, &aname, &err);
141 if (topo_node_fru(node, &fru, NULL, &err) == 0)
142 (void) topo_fmri_nvl2str(thp, fru, &fname, &err);
143 (void) topo_node_label(node, &lname, &err);
144 if (aname != NULL) {
145 nvlist_free(asru);
146 (void) printf("\tASRU: %s\n", aname);
147 topo_hdl_strfree(thp, aname);
148 } else {
149 (void) printf("\tASRU: -\n");
150 }
151 if (fname != NULL) {
152 nvlist_free(fru);
153 (void) printf("\tFRU: %s\n", fname);
154 topo_hdl_strfree(thp, fname);
155 } else {
156 (void) printf("\tFRU: -\n");
157 }
158 if (lname != NULL) {
159 (void) printf("\tLabel: %s\n", lname);
160 topo_hdl_strfree(thp, lname);
161 } else {
162 (void) printf("\tLabel: -\n");
163 }
164 }
165
166 if (opt_S) {
167 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
168 (void) printf("\tPresent: -\n");
169 else
170 (void) printf("\tPresent: %s\n",
171 ret ? "true" : "false");
172
173 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
174 (void) printf("\tUnusable: -\n");
175 else
176 (void) printf("\tUnusable: %s\n",
177 ret ? "true" : "false");
178 }
179 }
180
181 static void
print_everstyle(tnode_t * node)182 print_everstyle(tnode_t *node)
183 {
184 char buf[PATH_MAX], numbuf[64];
185 nvlist_t *fmri, **hcl;
186 int i, err;
187 uint_t n;
188
189 if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL,
190 TOPO_PROP_RESOURCE, &fmri, &err) < 0) {
191 (void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n",
192 g_pname, topo_node_name(node),
193 topo_node_instance(node), topo_strerror(err));
194 return;
195 }
196
197 if (nvlist_lookup_nvlist_array(fmri, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
198 (void) fprintf(stderr, "%s: failed to find %s for %s=%d\n",
199 g_pname, FM_FMRI_HC_LIST, topo_node_name(node),
200 topo_node_instance(node));
201 nvlist_free(fmri);
202 return;
203 }
204
205 buf[0] = '\0';
206
207 for (i = 0; i < n; i++) {
208 char *name, *inst, *estr;
209 ulong_t ul;
210
211 if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &name) != 0 ||
212 nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &inst) != 0) {
213 (void) fprintf(stderr, "%s: failed to get "
214 "name-instance for %s=%d\n", g_pname,
215 topo_node_name(node), topo_node_instance(node));
216 nvlist_free(fmri);
217 return;
218 }
219
220 errno = 0;
221 ul = strtoul(inst, &estr, 10);
222
223 if (errno != 0 || estr == inst) {
224 (void) fprintf(stderr, "%s: instance %s does not "
225 "convert to an unsigned integer\n", g_pname, inst);
226 }
227
228 (void) strlcat(buf, "/", sizeof (buf));
229 (void) strlcat(buf, name, sizeof (buf));
230 (void) snprintf(numbuf, sizeof (numbuf), "%u", ul);
231 (void) strlcat(buf, numbuf, sizeof (buf));
232 }
233 nvlist_free(fmri);
234
235 (void) printf("%s\n", buf);
236 }
237
238 static void
print_prop_nameval(topo_hdl_t * thp,tnode_t * node,nvlist_t * nvl)239 print_prop_nameval(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl)
240 {
241 int err;
242 topo_type_t type;
243 char *tstr, *propn, buf[48], *factype;
244 nvpair_t *pv_nvp;
245 int i;
246 uint_t nelem;
247
248 if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL)
249 return;
250
251 /* Print property name */
252 if ((pv_nvp = nvlist_next_nvpair(nvl, NULL)) == NULL ||
253 nvpair_name(pv_nvp) == NULL ||
254 strcmp(TOPO_PROP_VAL_NAME, nvpair_name(pv_nvp)) != 0) {
255 (void) fprintf(stderr, "%s: malformed property name\n",
256 g_pname);
257 return;
258 } else {
259 (void) nvpair_value_string(pv_nvp, &propn);
260 }
261
262 if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL ||
263 nvpair_name(pv_nvp) == NULL ||
264 strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 ||
265 nvpair_type(pv_nvp) != DATA_TYPE_UINT32) {
266 (void) fprintf(stderr, "%s: malformed property type for %s\n",
267 g_pname, propn);
268 return;
269 } else {
270 (void) nvpair_value_uint32(pv_nvp, (uint32_t *)&type);
271 }
272
273 switch (type) {
274 case TOPO_TYPE_BOOLEAN: tstr = "boolean"; break;
275 case TOPO_TYPE_INT32: tstr = "int32"; break;
276 case TOPO_TYPE_UINT32: tstr = "uint32"; break;
277 case TOPO_TYPE_INT64: tstr = "int64"; break;
278 case TOPO_TYPE_UINT64: tstr = "uint64"; break;
279 case TOPO_TYPE_DOUBLE: tstr = "double"; break;
280 case TOPO_TYPE_STRING: tstr = "string"; break;
281 case TOPO_TYPE_FMRI: tstr = "fmri"; break;
282 case TOPO_TYPE_INT32_ARRAY: tstr = "int32[]"; break;
283 case TOPO_TYPE_UINT32_ARRAY: tstr = "uint32[]"; break;
284 case TOPO_TYPE_INT64_ARRAY: tstr = "int64[]"; break;
285 case TOPO_TYPE_UINT64_ARRAY: tstr = "uint64[]"; break;
286 case TOPO_TYPE_STRING_ARRAY: tstr = "string[]"; break;
287 case TOPO_TYPE_FMRI_ARRAY: tstr = "fmri[]"; break;
288 default: tstr = "unknown type";
289 }
290
291 (void) printf(" %-17s %-8s ", propn, tstr);
292
293 /*
294 * Get property value
295 */
296 if (nvpair_name(pv_nvp) == NULL ||
297 (pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL) {
298 (void) fprintf(stderr, "%s: malformed property value\n",
299 g_pname);
300 return;
301 }
302
303 switch (nvpair_type(pv_nvp)) {
304 case DATA_TYPE_INT32: {
305 int32_t val;
306 (void) nvpair_value_int32(pv_nvp, &val);
307 (void) printf(" %d", val);
308 break;
309 }
310 case DATA_TYPE_UINT32: {
311 uint32_t val, type;
312 char val_str[49];
313 nvlist_t *fac, *rsrc = NULL;
314
315 (void) nvpair_value_uint32(pv_nvp, &val);
316 if (node == NULL || topo_node_flags(node) !=
317 TOPO_NODE_FACILITY)
318 goto uint32_def;
319
320 if (topo_node_resource(node, &rsrc, &err) != 0)
321 goto uint32_def;
322
323 if (nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0)
324 goto uint32_def;
325
326 if (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE,
327 &factype) != 0)
328 goto uint32_def;
329
330 nvlist_free(rsrc);
331 rsrc = NULL;
332
333 /*
334 * Special case code to do friendlier printing of
335 * facility node properties
336 */
337 if ((strcmp(propn, TOPO_FACILITY_TYPE) == 0) &&
338 (strcmp(factype, TOPO_FAC_TYPE_SENSOR) == 0)) {
339 topo_sensor_type_name(val, val_str, 48);
340 (void) printf(" 0x%x (%s)", val, val_str);
341 break;
342 } else if ((strcmp(propn, TOPO_FACILITY_TYPE) == 0) &&
343 (strcmp(factype, TOPO_FAC_TYPE_INDICATOR) == 0)) {
344 topo_led_type_name(val, val_str, 48);
345 (void) printf(" 0x%x (%s)", val, val_str);
346 break;
347 } else if (strcmp(propn, TOPO_SENSOR_UNITS) == 0) {
348 topo_sensor_units_name(val, val_str, 48);
349 (void) printf(" 0x%x (%s)", val, val_str);
350 break;
351 } else if (strcmp(propn, TOPO_LED_MODE) == 0) {
352 topo_led_state_name(val, val_str, 48);
353 (void) printf(" 0x%x (%s)", val, val_str);
354 break;
355 } else if ((strcmp(propn, TOPO_SENSOR_STATE) == 0) &&
356 (strcmp(factype, TOPO_FAC_TYPE_SENSOR) == 0)) {
357 if (topo_prop_get_uint32(node,
358 TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
359 &type, &err) != 0) {
360 goto uint32_def;
361 }
362 topo_sensor_state_name(type, val, val_str, 48);
363 (void) printf(" 0x%x (%s)", val, val_str);
364 break;
365 }
366 uint32_def:
367 (void) printf(" 0x%x", val);
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 = NULL;
601 char *end;
602
603 if (pp->prop == NULL || pp->type == NULL || pp->value == NULL)
604 goto out;
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 goto out;
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 goto out;
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 goto out;
623 }
624
625 errno = 0;
626 switch (type) {
627 case TOPO_TYPE_INT32:
628 {
629 int32_t val;
630
631 val = strtol(pp->value, &end, 0);
632 if (errno == ERANGE) {
633 ret = -1;
634 break;
635 }
636 ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val);
637 break;
638 }
639 case TOPO_TYPE_UINT32:
640 {
641 uint32_t val;
642
643 val = strtoul(pp->value, &end, 0);
644 if (errno == ERANGE) {
645 ret = -1;
646 break;
647 }
648 ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val);
649 break;
650 }
651 case TOPO_TYPE_INT64:
652 {
653 int64_t val;
654
655 val = strtoll(pp->value, &end, 0);
656 if (errno == ERANGE) {
657 ret = -1;
658 break;
659 }
660 ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val);
661 break;
662 }
663 case TOPO_TYPE_UINT64:
664 {
665 uint64_t val;
666
667 val = strtoull(pp->value, &end, 0);
668 if (errno == ERANGE) {
669 ret = -1;
670 break;
671 }
672 ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val);
673 break;
674 }
675 case TOPO_TYPE_STRING:
676 {
677 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
678 pp->value);
679 break;
680 }
681 case TOPO_TYPE_FMRI:
682 {
683 nvlist_t *val = NULL;
684
685 if ((ret = topo_fmri_str2nvl(thp, pp->value, &val,
686 &err)) < 0)
687 break;
688
689 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
690 val)) != 0)
691 err = ETOPO_PROP_NVL;
692
693 nvlist_free(val);
694 break;
695 }
696 default:
697 ret = -1;
698 }
699
700 if (ret != 0) {
701 (void) fprintf(stderr, "%s: unable to set property value for "
702 "%s: %s\n", g_pname, pp->prop, topo_strerror(err));
703 goto out;
704 }
705
706 if (node != NULL) {
707 if ((ret = topo_prop_setprop(node, pp->group, nvl,
708 TOPO_PROP_MUTABLE, nvl, &err)) < 0) {
709 (void) fprintf(stderr, "%s: unable to set property "
710 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop,
711 pp->type, pp->value, topo_strerror(err));
712 goto out;
713 }
714 } else {
715 if ((ret = topo_fmri_setprop(thp, fmri, pp->group, nvl,
716 TOPO_PROP_MUTABLE, nvl, &err)) < 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(err));
720 goto out;
721 }
722 }
723
724 nvlist_free(nvl);
725 nvl = NULL;
726
727 /*
728 * Now, get the property back for printing
729 */
730 if (node != NULL) {
731 if ((ret = topo_prop_getprop(node, pp->group, pp->prop, NULL,
732 &nvl, &err)) < 0) {
733 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
734 g_pname, pp->group, pp->prop, topo_strerror(err));
735 goto out;
736 }
737 } else {
738 if ((ret = topo_fmri_getprop(thp, fmri, pp->group, pp->prop,
739 NULL, &nvl, &err)) < 0) {
740 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
741 g_pname, pp->group, pp->prop, topo_strerror(err));
742 goto out;
743 }
744 }
745
746 print_pgroup(thp, node, pp->group, NULL, NULL, 0);
747 print_prop_nameval(thp, node, nvl);
748
749 out:
750 nvlist_free(nvl);
751 }
752
753 static void
print_props(topo_hdl_t * thp,tnode_t * node)754 print_props(topo_hdl_t *thp, tnode_t *node)
755 {
756 int i, err;
757 nvlist_t *nvl;
758 struct prop_args *pp;
759
760 if (pcnt == 0)
761 return;
762
763 for (i = 0; i < pcnt; ++i) {
764 pp = pargs[i];
765
766 if (pp->group == NULL)
767 continue;
768
769 /*
770 * If we have a valid value, this is a request to
771 * set a property. Otherwise, just print the property
772 * group and any specified properties.
773 */
774 if (pp->value == NULL) {
775 if (pp->prop == NULL) {
776
777 /*
778 * Print all properties in this group
779 */
780 if ((nvl = topo_prop_getprops(node, &err))
781 == NULL) {
782 (void) fprintf(stderr, "%s: failed to "
783 "get %s: %s\n", g_pname,
784 pp->group,
785 topo_strerror(err));
786 continue;
787 } else {
788 print_all_props(thp, node, nvl,
789 pp->group);
790 nvlist_free(nvl);
791 continue;
792 }
793 }
794 if (topo_prop_getprop(node, pp->group, pp->prop,
795 NULL, &nvl, &err) < 0) {
796 (void) fprintf(stderr, "%s: failed to get "
797 "%s.%s: %s\n", g_pname,
798 pp->group, pp->prop,
799 topo_strerror(err));
800 continue;
801 } else {
802 print_pgroup(thp, node, pp->group, NULL,
803 NULL, 0);
804 print_prop_nameval(thp, node, nvl);
805 nvlist_free(nvl);
806 }
807 } else {
808 set_prop(thp, node, NULL, pp);
809 }
810 }
811 }
812
813 /*ARGSUSED*/
814 static int
walk_node(topo_hdl_t * thp,tnode_t * node,void * arg)815 walk_node(topo_hdl_t *thp, tnode_t *node, void *arg)
816 {
817 int err;
818 nvlist_t *nvl;
819 nvlist_t *rsrc, *out;
820 char *s;
821
822 if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
823 print_everstyle(node);
824 return (TOPO_WALK_NEXT);
825 }
826
827 if (topo_node_resource(node, &rsrc, &err) < 0) {
828 (void) fprintf(stderr, "%s: failed to get resource: "
829 "%s", g_pname, topo_strerror(err));
830 return (TOPO_WALK_NEXT);
831 }
832 if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) {
833 (void) fprintf(stderr, "%s: failed to convert "
834 "resource to FMRI string: %s", g_pname,
835 topo_strerror(err));
836 nvlist_free(rsrc);
837 return (TOPO_WALK_NEXT);
838 }
839
840 if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) {
841 nvlist_free(rsrc);
842 topo_hdl_strfree(thp, s);
843 return (TOPO_WALK_NEXT);
844 }
845
846 print_node(thp, node, rsrc, s);
847 topo_hdl_strfree(thp, s);
848 nvlist_free(rsrc);
849
850 if (opt_m != NULL) {
851 if (topo_method_invoke(node, opt_m, 0, NULL, &out, &err) == 0) {
852 nvlist_print(stdout, out);
853 nvlist_free(out);
854 } else if (err != ETOPO_METHOD_NOTSUP)
855 (void) fprintf(stderr, "%s: method failed unexpectedly "
856 "on %s=%d (%s)\n", g_pname, topo_node_name(node),
857 topo_node_instance(node), topo_strerror(err));
858 }
859
860 if (opt_V || opt_all) {
861 if ((nvl = topo_prop_getprops(node, &err)) == NULL) {
862 (void) fprintf(stderr, "%s: failed to get "
863 "properties for %s=%d: %s\n", g_pname,
864 topo_node_name(node), topo_node_instance(node),
865 topo_strerror(err));
866 } else {
867 print_all_props(thp, node, nvl, ALL);
868 nvlist_free(nvl);
869 }
870 } else if (pcnt > 0)
871 print_props(thp, node);
872
873 (void) printf("\n");
874
875 return (TOPO_WALK_NEXT);
876 }
877
878 static void
get_pargs(int argc,char * argv[])879 get_pargs(int argc, char *argv[])
880 {
881 struct prop_args *pp;
882 char c, *s, *p;
883 int i = 0;
884
885 if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) {
886 (void) fprintf(stderr, "%s: failed to allocate property "
887 "arguments\n", g_pname);
888 return;
889 }
890
891 for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) {
892 if (c == 'P') {
893
894 if (strcmp(optarg, ALL) == 0) {
895 opt_all++;
896 break;
897 }
898
899 if ((pp = pargs[i] = malloc(sizeof (struct prop_args)))
900 == NULL) {
901 (void) fprintf(stderr, "%s: failed to "
902 "allocate propertyarguments\n", g_pname);
903 return;
904 }
905 ++i;
906 pp->group = NULL;
907 pp->prop = NULL;
908 pp->type = NULL;
909 pp->value = NULL;
910
911 p = optarg;
912 if ((s = strchr(p, '.')) != NULL) {
913 *s++ = '\0'; /* strike out delimiter */
914 pp->group = p;
915 p = s;
916 if ((s = strchr(p, '=')) != NULL) {
917 *s++ = '\0'; /* strike out delimiter */
918 pp->prop = p;
919 p = s;
920 if ((s = strchr(p, ':')) != NULL) {
921 *s++ = '\0';
922 pp->type = p;
923 pp->value = s;
924 } else {
925 (void) fprintf(stderr, "%s: "
926 "property type not "
927 "specified for assignment "
928 " of %s.%s\n", g_pname,
929 pp->group, pp->prop);
930 break;
931 }
932 } else {
933 pp->prop = p;
934 }
935 } else {
936 pp->group = p;
937 }
938 if (i >= pcnt)
939 break;
940 }
941 }
942
943 if (opt_all > 0) {
944 int j;
945
946 for (j = 0; j < i; ++j)
947 free(pargs[i]);
948 free(pargs);
949 pargs = NULL;
950 }
951 }
952
953 static int
walk_topo(topo_hdl_t * thp,char * uuid)954 walk_topo(topo_hdl_t *thp, char *uuid)
955 {
956 int err;
957 topo_walk_t *twp;
958 int flag;
959
960 if (getzoneid() != GLOBAL_ZONEID &&
961 strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
962 return (0);
963 }
964
965 if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err))
966 == NULL) {
967 (void) fprintf(stderr, "%s: failed to walk %s topology:"
968 " %s\n", g_pname, opt_s, topo_strerror(err));
969
970 return (-1);
971 }
972
973 /*
974 * Print standard header
975 */
976 if (!opt_e) {
977 char buf[32];
978 time_t tod = time(NULL);
979
980 (void) printf("TIME UUID\n");
981 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
982 (void) printf("%-15s %-32s\n", buf, uuid);
983 (void) printf("\n");
984 }
985
986 flag = opt_b != 0 ? TOPO_WALK_SIBLING : TOPO_WALK_CHILD;
987
988 if (topo_walk_step(twp, flag) == TOPO_WALK_ERR) {
989 (void) fprintf(stderr, "%s: failed to walk topology\n",
990 g_pname);
991 topo_walk_fini(twp);
992 return (-1);
993 }
994
995 topo_walk_fini(twp);
996
997 return (0);
998 }
999
1000 static void
print_fmri_pgroup(topo_hdl_t * thp,const char * pgn,nvlist_t * nvl)1001 print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl)
1002 {
1003 char *dstab = NULL, *nstab = NULL;
1004 int32_t version = -1;
1005 nvlist_t *pnvl;
1006 nvpair_t *pnvp;
1007
1008 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab);
1009 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab);
1010 (void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version);
1011
1012 print_pgroup(thp, NULL, pgn, dstab, nstab, version);
1013
1014 for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL;
1015 pnvp = nvlist_next_nvpair(nvl, pnvp)) {
1016
1017 /*
1018 * Print property group and property name-value pair
1019 */
1020 if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp))
1021 == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) {
1022 (void) nvpair_value_nvlist(pnvp, &pnvl);
1023 print_prop_nameval(thp, NULL, pnvl);
1024
1025 }
1026
1027 }
1028 }
1029
1030 static void
print_fmri_props(topo_hdl_t * thp,nvlist_t * nvl)1031 print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl)
1032 {
1033 int i, err;
1034 struct prop_args *pp;
1035 nvlist_t *pnvl;
1036
1037 for (i = 0; i < pcnt; ++i) {
1038 pp = pargs[i];
1039
1040 if (pp->group == NULL)
1041 continue;
1042
1043 pnvl = NULL;
1044
1045 /*
1046 * If we have a valid value, this is a request to
1047 * set a property. Otherwise, just print the property
1048 * group and any specified properties.
1049 */
1050 if (pp->value == NULL) {
1051 if (pp->prop == NULL) {
1052
1053 /*
1054 * Print all properties in this group
1055 */
1056 if (topo_fmri_getpgrp(thp, nvl, pp->group,
1057 &pnvl, &err) < 0) {
1058 (void) fprintf(stderr, "%s: failed to "
1059 "get group %s: %s\n", g_pname,
1060 pp->group, topo_strerror(err));
1061 continue;
1062 } else {
1063 print_fmri_pgroup(thp, pp->group,
1064 pnvl);
1065 nvlist_free(pnvl);
1066 continue;
1067 }
1068 }
1069 if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop,
1070 NULL, &pnvl, &err) < 0) {
1071 (void) fprintf(stderr, "%s: failed to get "
1072 "%s.%s: %s\n", g_pname,
1073 pp->group, pp->prop,
1074 topo_strerror(err));
1075 continue;
1076 } else {
1077 print_fmri_pgroup(thp, pp->group, pnvl);
1078 print_prop_nameval(thp, NULL, pnvl);
1079 nvlist_free(nvl);
1080 }
1081 } else {
1082 set_prop(thp, NULL, nvl, pp);
1083 }
1084 }
1085 }
1086
1087 void
print_fmri(topo_hdl_t * thp,char * uuid)1088 print_fmri(topo_hdl_t *thp, char *uuid)
1089 {
1090 int ret, err;
1091 nvlist_t *nvl;
1092 char buf[32];
1093 time_t tod = time(NULL);
1094
1095 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
1096 (void) fprintf(stderr, "%s: failed to convert %s to nvlist: "
1097 "%s\n", g_pname, g_fmri, topo_strerror(err));
1098 return;
1099 }
1100
1101 (void) printf("TIME UUID\n");
1102 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
1103 (void) printf("%-15s %-32s\n", buf, uuid);
1104 (void) printf("\n");
1105
1106 (void) printf("%s\n", (char *)g_fmri);
1107
1108 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
1109 char *aname = NULL, *fname = NULL, *lname = NULL;
1110 nvlist_t *asru = NULL;
1111 nvlist_t *fru = NULL;
1112
1113 if (topo_fmri_asru(thp, nvl, &asru, &err) == 0)
1114 (void) topo_fmri_nvl2str(thp, asru, &aname, &err);
1115 if (topo_fmri_fru(thp, nvl, &fru, &err) == 0)
1116 (void) topo_fmri_nvl2str(thp, fru, &fname, &err);
1117 (void) topo_fmri_label(thp, nvl, &lname, &err);
1118
1119 nvlist_free(fru);
1120 nvlist_free(asru);
1121
1122 if (aname != NULL) {
1123 (void) printf("\tASRU: %s\n", aname);
1124 topo_hdl_strfree(thp, aname);
1125 } else {
1126 (void) printf("\tASRU: -\n");
1127 }
1128 if (fname != NULL) {
1129 (void) printf("\tFRU: %s\n", fname);
1130 topo_hdl_strfree(thp, fname);
1131 } else {
1132 (void) printf("\tFRU: -\n");
1133 }
1134 if (lname != NULL) {
1135 (void) printf("\tLabel: %s\n", lname);
1136 topo_hdl_strfree(thp, lname);
1137 } else {
1138 (void) printf("\tLabel: -\n");
1139 }
1140 }
1141
1142 if (opt_S) {
1143 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
1144 (void) printf("\tPresent: -\n");
1145 (void) printf("\tUnusable: -\n");
1146 return;
1147 }
1148
1149 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
1150 (void) printf("\tPresent: -\n");
1151 else
1152 (void) printf("\tPresent: %s\n",
1153 ret ? "true" : "false");
1154
1155 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
1156 (void) printf("\tUnusable: -\n");
1157 else
1158 (void) printf("\tUnusable: %s\n",
1159 ret ? "true" : "false");
1160
1161 nvlist_free(nvl);
1162 }
1163
1164 if (pargs && pcnt > 0)
1165 print_fmri_props(thp, nvl);
1166 }
1167
1168 int
fmtopo_exit(topo_hdl_t * thp,char * uuid,int err)1169 fmtopo_exit(topo_hdl_t *thp, char *uuid, int err)
1170 {
1171 if (uuid != NULL)
1172 topo_hdl_strfree(thp, uuid);
1173
1174 if (thp != NULL) {
1175 topo_snap_release(thp);
1176 topo_close(thp);
1177 }
1178
1179 if (pargs) {
1180 int i;
1181 for (i = 0; i < pcnt; ++i)
1182 free(pargs[i]);
1183 free(pargs);
1184 }
1185
1186 return (err);
1187 }
1188
1189 int
main(int argc,char * argv[])1190 main(int argc, char *argv[])
1191 {
1192 topo_hdl_t *thp = NULL;
1193 char *uuid = NULL;
1194 int c, err = 0;
1195
1196 g_pname = argv[0];
1197
1198 while (optind < argc) {
1199 while ((c = getopt(argc, argv, optstr)) != -1) {
1200 switch (c) {
1201 case 'b':
1202 opt_b++;
1203 break;
1204 case 'C':
1205 (void) atexit(abort);
1206 break;
1207 case 'd':
1208 opt_d++;
1209 break;
1210 case 'e':
1211 opt_e++;
1212 break;
1213 case 'm':
1214 opt_m = optarg;
1215 break;
1216 case 'P':
1217 pcnt++;
1218 break;
1219 case 'p':
1220 opt_p++;
1221 break;
1222 case 'V':
1223 opt_V++;
1224 break;
1225 case 'R':
1226 opt_R = optarg;
1227 break;
1228 case 's':
1229 opt_s = optarg;
1230 break;
1231 case 'S':
1232 opt_S++;
1233 break;
1234 case 't':
1235 opt_t++;
1236 break;
1237 case 'x':
1238 opt_x++;
1239 break;
1240 default:
1241 return (usage(stderr));
1242 }
1243 }
1244
1245 if (optind < argc) {
1246 if (g_fmri != NULL) {
1247 (void) fprintf(stderr, "%s: illegal argument "
1248 "-- %s\n", g_pname, argv[optind]);
1249 return (FMTOPO_EXIT_USAGE);
1250 } else {
1251 g_fmri = argv[optind++];
1252 }
1253 }
1254 }
1255
1256 if (pcnt > 0)
1257 get_pargs(argc, argv);
1258
1259 if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) {
1260 (void) fprintf(stderr, "%s: failed to open topology tree: %s\n",
1261 g_pname, topo_strerror(err));
1262 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1263 }
1264
1265 if (opt_d)
1266 topo_debug_set(thp, "module", "stderr");
1267
1268 if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) {
1269 (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n",
1270 g_pname, topo_strerror(err));
1271 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1272 } else if (err != 0) {
1273 (void) fprintf(stderr, "%s: topology snapshot incomplete%s\n",
1274 g_pname, getzoneid() != GLOBAL_ZONEID &&
1275 strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0 ?
1276 " (" FM_FMRI_SCHEME_HC " scheme does not enumerate "
1277 "in a non-global zone)": "");
1278 }
1279
1280 if (opt_x) {
1281 if (opt_b) {
1282 (void) fprintf(stderr,
1283 "%s: -b and -x cannot be specified together\n",
1284 g_pname);
1285 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_USAGE));
1286 }
1287
1288 err = 0;
1289 if (topo_xml_print(thp, stdout, opt_s, &err) < 0)
1290 (void) fprintf(stderr, "%s: failed to print xml "
1291 "formatted topology:%s", g_pname,
1292 topo_strerror(err));
1293
1294 return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR :
1295 FMTOPO_EXIT_SUCCESS));
1296 }
1297
1298 if (opt_t || walk_topo(thp, uuid) < 0) {
1299 if (g_fmri != NULL)
1300 /*
1301 * Try getting some useful information
1302 */
1303 print_fmri(thp, uuid);
1304
1305 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1306 }
1307
1308 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_SUCCESS));
1309 }
1310