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 if (rsrc != NULL)
369 nvlist_free(rsrc);
370 break;
371 }
372 case DATA_TYPE_INT64: {
373 int64_t val;
374 (void) nvpair_value_int64(pv_nvp, &val);
375 (void) printf(" %lld", (longlong_t)val);
376 break;
377 }
378 case DATA_TYPE_UINT64: {
379 uint64_t val;
380 (void) nvpair_value_uint64(pv_nvp, &val);
381 (void) printf(" 0x%llx", (u_longlong_t)val);
382 break;
383 }
384 case DATA_TYPE_DOUBLE: {
385 double val;
386 (void) nvpair_value_double(pv_nvp, &val);
387 (void) printf(" %lf", (double)val);
388 break;
389 }
390 case DATA_TYPE_STRING: {
391 char *val;
392 (void) nvpair_value_string(pv_nvp, &val);
393 if (!opt_V && strlen(val) > 48) {
394 (void) snprintf(buf, 48, "%s...", val);
395 (void) printf(" %s", buf);
396 } else {
397 (void) printf(" %s", val);
398 }
399 break;
400 }
401 case DATA_TYPE_NVLIST: {
402 nvlist_t *val;
403 char *fmri;
404 (void) nvpair_value_nvlist(pv_nvp, &val);
405 if (topo_fmri_nvl2str(thp, val, &fmri, &err) != 0) {
406 if (opt_V)
407 nvlist_print(stdout, nvl);
408 break;
409 }
410
411 if (!opt_V && strlen(fmri) > 48) {
412 (void) snprintf(buf, 48, "%s", fmri);
413 (void) snprintf(&buf[45], 4, "%s", DOTS);
414 (void) printf(" %s", buf);
415 } else {
416 (void) printf(" %s", fmri);
417 }
418
419 topo_hdl_strfree(thp, fmri);
420 break;
421 }
422 case DATA_TYPE_INT32_ARRAY: {
423 int32_t *val;
424
425 (void) nvpair_value_int32_array(pv_nvp, &val, &nelem);
426 (void) printf(" [ ");
427 for (i = 0; i < nelem; i++)
428 (void) printf("%d ", val[i]);
429 (void) printf("]");
430 break;
431 }
432 case DATA_TYPE_UINT32_ARRAY: {
433 uint32_t *val;
434
435 (void) nvpair_value_uint32_array(pv_nvp, &val, &nelem);
436 (void) printf(" [ ");
437 for (i = 0; i < nelem; i++)
438 (void) printf("%u ", val[i]);
439 (void) printf("]");
440 break;
441 }
442 case DATA_TYPE_INT64_ARRAY: {
443 int64_t *val;
444
445 (void) nvpair_value_int64_array(pv_nvp, &val, &nelem);
446 (void) printf(" [ ");
447 for (i = 0; i < nelem; i++)
448 (void) printf("%lld ", val[i]);
449 (void) printf("]");
450 break;
451 }
452 case DATA_TYPE_UINT64_ARRAY: {
453 uint64_t *val;
454
455 (void) nvpair_value_uint64_array(pv_nvp, &val, &nelem);
456 (void) printf(" [ ");
457 for (i = 0; i < nelem; i++)
458 (void) printf("%llu ", val[i]);
459 (void) printf("]");
460 break;
461 }
462 case DATA_TYPE_STRING_ARRAY: {
463 char **val;
464
465 (void) nvpair_value_string_array(pv_nvp, &val, &nelem);
466 (void) printf(" [ ");
467 for (i = 0; i < nelem; i++)
468 (void) printf("\"%s\" ", val[i]);
469 (void) printf("]");
470 break;
471 }
472 default:
473 (void) fprintf(stderr, " unknown data type (%d)",
474 nvpair_type(pv_nvp));
475 break;
476 }
477 (void) printf("\n");
478 }
479
480 static void
print_pgroup(topo_hdl_t * thp,tnode_t * node,const char * pgn,char * dstab,char * nstab,int32_t version)481 print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab,
482 char *nstab, int32_t version)
483 {
484 int err;
485 char buf[30];
486 topo_pgroup_info_t *pgi = NULL;
487
488 if (pgn == NULL)
489 return;
490
491 if (node != NULL && (dstab == NULL || nstab == NULL || version == -1)) {
492 if ((pgi = topo_pgroup_info(node, pgn, &err)) != NULL) {
493 dstab = (char *)topo_stability2name(pgi->tpi_datastab);
494 nstab = (char *)topo_stability2name(pgi->tpi_namestab);
495 version = pgi->tpi_version;
496 }
497 }
498
499 if (dstab == NULL || nstab == NULL || version == -1) {
500 (void) printf(" group: %-30s version: - stability: -/-\n",
501 pgn);
502 } else if (!opt_V && strlen(pgn) > 30) {
503 (void) snprintf(buf, 26, "%s", pgn);
504 (void) snprintf(&buf[27], 4, "%s", DOTS);
505 (void) printf(" group: %-30s version: %-3d stability: %s/%s\n",
506 buf, version, nstab, dstab);
507 } else {
508 (void) printf(" group: %-30s version: %-3d stability: %s/%s\n",
509 pgn, version, nstab, dstab);
510 }
511
512 if (pgi != NULL) {
513 topo_hdl_strfree(thp, (char *)pgi->tpi_name);
514 topo_hdl_free(thp, pgi, sizeof (topo_pgroup_info_t));
515 }
516 }
517
518 static void
print_all_props(topo_hdl_t * thp,tnode_t * node,nvlist_t * p_nv,const char * group)519 print_all_props(topo_hdl_t *thp, tnode_t *node, nvlist_t *p_nv,
520 const char *group)
521 {
522 char *pgn = NULL, *dstab = NULL, *nstab = NULL;
523 int32_t version;
524 nvlist_t *pg_nv, *pv_nv;
525 nvpair_t *nvp, *pg_nvp;
526 int pg_done, match, all = strcmp(group, ALL) == 0;
527
528 for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL;
529 nvp = nvlist_next_nvpair(p_nv, nvp)) {
530 if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 ||
531 nvpair_type(nvp) != DATA_TYPE_NVLIST)
532 continue;
533
534 nstab = NULL;
535 dstab = NULL;
536 version = -1;
537 pg_done = match = 0;
538 (void) nvpair_value_nvlist(nvp, &pg_nv);
539 for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL;
540 pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) {
541 /*
542 * Print property group name and stability levels
543 */
544 if (strcmp(TOPO_PROP_GROUP_NAME, nvpair_name(pg_nvp))
545 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) {
546 (void) nvpair_value_string(pg_nvp, &pgn);
547 match = strcmp(group, pgn) == 0;
548 continue;
549 }
550
551 if (strcmp(TOPO_PROP_GROUP_NSTAB,
552 nvpair_name(pg_nvp)) == 0 &&
553 nvpair_type(pg_nvp) == DATA_TYPE_STRING) {
554 (void) nvpair_value_string(pg_nvp, &nstab);
555 continue;
556 }
557
558 if (strcmp(TOPO_PROP_GROUP_DSTAB,
559 nvpair_name(pg_nvp)) == 0 &&
560 nvpair_type(pg_nvp) == DATA_TYPE_STRING) {
561 (void) nvpair_value_string(pg_nvp, &dstab);
562 continue;
563 }
564
565 if (strcmp(TOPO_PROP_GROUP_VERSION,
566 nvpair_name(pg_nvp)) == 0 &&
567 nvpair_type(pg_nvp) == DATA_TYPE_INT32) {
568 (void) nvpair_value_int32(pg_nvp, &version);
569 continue;
570 }
571
572 if ((match || all) && !pg_done) {
573 print_pgroup(thp, node, pgn, dstab, nstab,
574 version);
575 pg_done++;
576 }
577
578 /*
579 * Print property group and property name-value pair
580 */
581 if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp))
582 == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) {
583 (void) nvpair_value_nvlist(pg_nvp, &pv_nv);
584 if ((match || all) && pg_done) {
585 print_prop_nameval(thp, node, pv_nv);
586 }
587
588 }
589
590 }
591 if (match && !all)
592 return;
593 }
594 }
595
596 static void
set_prop(topo_hdl_t * thp,tnode_t * node,nvlist_t * fmri,struct prop_args * pp)597 set_prop(topo_hdl_t *thp, tnode_t *node, nvlist_t *fmri, struct prop_args *pp)
598 {
599 int ret, err = 0;
600 topo_type_t type;
601 nvlist_t *nvl = NULL;
602 char *end;
603
604 if (pp->prop == NULL || pp->type == NULL || pp->value == NULL)
605 goto out;
606
607 if ((type = str2type(pp->type)) == TOPO_TYPE_INVALID) {
608 (void) fprintf(stderr, "%s: invalid property type %s for %s\n",
609 g_pname, pp->type, pp->prop);
610 goto out;
611 }
612
613 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
614 (void) fprintf(stderr, "%s: nvlist allocation failed for "
615 "%s=%s:%s\n", g_pname, pp->prop, pp->type, pp->value);
616 goto out;
617 }
618 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pp->prop);
619 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
620 if (ret != 0) {
621 (void) fprintf(stderr, "%s: invalid property type %s for %s\n",
622 g_pname, pp->type, pp->prop);
623 goto out;
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 nvlist_t *val = NULL;
685
686 if ((ret = topo_fmri_str2nvl(thp, pp->value, &val,
687 &err)) < 0)
688 break;
689
690 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
691 val)) != 0)
692 err = ETOPO_PROP_NVL;
693
694 nvlist_free(val);
695 break;
696 }
697 default:
698 ret = -1;
699 }
700
701 if (ret != 0) {
702 (void) fprintf(stderr, "%s: unable to set property value for "
703 "%s: %s\n", g_pname, pp->prop, topo_strerror(err));
704 goto out;
705 }
706
707 if (node != NULL) {
708 if ((ret = topo_prop_setprop(node, pp->group, nvl,
709 TOPO_PROP_MUTABLE, nvl, &err)) < 0) {
710 (void) fprintf(stderr, "%s: unable to set property "
711 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop,
712 pp->type, pp->value, topo_strerror(err));
713 goto out;
714 }
715 } else {
716 if ((ret = topo_fmri_setprop(thp, fmri, pp->group, nvl,
717 TOPO_PROP_MUTABLE, nvl, &err)) < 0) {
718 (void) fprintf(stderr, "%s: unable to set property "
719 "value for " "%s=%s:%s: %s\n", g_pname, pp->prop,
720 pp->type, pp->value, topo_strerror(err));
721 goto out;
722 }
723 }
724
725 nvlist_free(nvl);
726 nvl = NULL;
727
728 /*
729 * Now, get the property back for printing
730 */
731 if (node != NULL) {
732 if ((ret = topo_prop_getprop(node, pp->group, pp->prop, NULL,
733 &nvl, &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 goto out;
737 }
738 } else {
739 if ((ret = topo_fmri_getprop(thp, fmri, pp->group, pp->prop,
740 NULL, &nvl, &err)) < 0) {
741 (void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
742 g_pname, pp->group, pp->prop, topo_strerror(err));
743 goto out;
744 }
745 }
746
747 print_pgroup(thp, node, pp->group, NULL, NULL, 0);
748 print_prop_nameval(thp, node, nvl);
749
750 out:
751 nvlist_free(nvl);
752 }
753
754 static void
print_props(topo_hdl_t * thp,tnode_t * node)755 print_props(topo_hdl_t *thp, tnode_t *node)
756 {
757 int i, err;
758 nvlist_t *nvl;
759 struct prop_args *pp;
760
761 if (pcnt == 0)
762 return;
763
764 for (i = 0; i < pcnt; ++i) {
765 pp = pargs[i];
766
767 if (pp->group == NULL)
768 continue;
769
770 /*
771 * If we have a valid value, this is a request to
772 * set a property. Otherwise, just print the property
773 * group and any specified properties.
774 */
775 if (pp->value == NULL) {
776 if (pp->prop == NULL) {
777
778 /*
779 * Print all properties in this group
780 */
781 if ((nvl = topo_prop_getprops(node, &err))
782 == NULL) {
783 (void) fprintf(stderr, "%s: failed to "
784 "get %s: %s\n", g_pname,
785 pp->group,
786 topo_strerror(err));
787 continue;
788 } else {
789 print_all_props(thp, node, nvl,
790 pp->group);
791 nvlist_free(nvl);
792 continue;
793 }
794 }
795 if (topo_prop_getprop(node, pp->group, pp->prop,
796 NULL, &nvl, &err) < 0) {
797 (void) fprintf(stderr, "%s: failed to get "
798 "%s.%s: %s\n", g_pname,
799 pp->group, pp->prop,
800 topo_strerror(err));
801 continue;
802 } else {
803 print_pgroup(thp, node, pp->group, NULL,
804 NULL, 0);
805 print_prop_nameval(thp, node, nvl);
806 nvlist_free(nvl);
807 }
808 } else {
809 set_prop(thp, node, NULL, pp);
810 }
811 }
812 }
813
814 /*ARGSUSED*/
815 static int
walk_node(topo_hdl_t * thp,tnode_t * node,void * arg)816 walk_node(topo_hdl_t *thp, tnode_t *node, void *arg)
817 {
818 int err;
819 nvlist_t *nvl;
820 nvlist_t *rsrc, *out;
821 char *s;
822
823 if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
824 print_everstyle(node);
825 return (TOPO_WALK_NEXT);
826 }
827
828 if (topo_node_resource(node, &rsrc, &err) < 0) {
829 (void) fprintf(stderr, "%s: failed to get resource: "
830 "%s", g_pname, topo_strerror(err));
831 return (TOPO_WALK_NEXT);
832 }
833 if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) {
834 (void) fprintf(stderr, "%s: failed to convert "
835 "resource to FMRI string: %s", g_pname,
836 topo_strerror(err));
837 nvlist_free(rsrc);
838 return (TOPO_WALK_NEXT);
839 }
840
841 if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) {
842 nvlist_free(rsrc);
843 topo_hdl_strfree(thp, s);
844 return (TOPO_WALK_NEXT);
845 }
846
847 print_node(thp, node, rsrc, s);
848 topo_hdl_strfree(thp, s);
849 nvlist_free(rsrc);
850
851 if (opt_m != NULL) {
852 if (topo_method_invoke(node, opt_m, 0, NULL, &out, &err) == 0) {
853 nvlist_print(stdout, out);
854 nvlist_free(out);
855 } else if (err != ETOPO_METHOD_NOTSUP)
856 (void) fprintf(stderr, "%s: method failed unexpectedly "
857 "on %s=%d (%s)\n", g_pname, topo_node_name(node),
858 topo_node_instance(node), topo_strerror(err));
859 }
860
861 if (opt_V || opt_all) {
862 if ((nvl = topo_prop_getprops(node, &err)) == NULL) {
863 (void) fprintf(stderr, "%s: failed to get "
864 "properties for %s=%d: %s\n", g_pname,
865 topo_node_name(node), topo_node_instance(node),
866 topo_strerror(err));
867 } else {
868 print_all_props(thp, node, nvl, ALL);
869 nvlist_free(nvl);
870 }
871 } else if (pcnt > 0)
872 print_props(thp, node);
873
874 (void) printf("\n");
875
876 return (TOPO_WALK_NEXT);
877 }
878
879 static void
get_pargs(int argc,char * argv[])880 get_pargs(int argc, char *argv[])
881 {
882 struct prop_args *pp;
883 char c, *s, *p;
884 int i = 0;
885
886 if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) {
887 (void) fprintf(stderr, "%s: failed to allocate property "
888 "arguments\n", g_pname);
889 return;
890 }
891
892 for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) {
893 if (c == 'P') {
894
895 if (strcmp(optarg, ALL) == 0) {
896 opt_all++;
897 break;
898 }
899
900 if ((pp = pargs[i] = malloc(sizeof (struct prop_args)))
901 == NULL) {
902 (void) fprintf(stderr, "%s: failed to "
903 "allocate propertyarguments\n", g_pname);
904 return;
905 }
906 ++i;
907 pp->group = NULL;
908 pp->prop = NULL;
909 pp->type = NULL;
910 pp->value = NULL;
911
912 p = optarg;
913 if ((s = strchr(p, '.')) != NULL) {
914 *s++ = '\0'; /* strike out delimiter */
915 pp->group = p;
916 p = s;
917 if ((s = strchr(p, '=')) != NULL) {
918 *s++ = '\0'; /* strike out delimiter */
919 pp->prop = p;
920 p = s;
921 if ((s = strchr(p, ':')) != NULL) {
922 *s++ = '\0';
923 pp->type = p;
924 pp->value = s;
925 } else {
926 (void) fprintf(stderr, "%s: "
927 "property type not "
928 "specified for assignment "
929 " of %s.%s\n", g_pname,
930 pp->group, pp->prop);
931 break;
932 }
933 } else {
934 pp->prop = p;
935 }
936 } else {
937 pp->group = p;
938 }
939 if (i >= pcnt)
940 break;
941 }
942 }
943
944 if (opt_all > 0) {
945 int j;
946
947 for (j = 0; j < i; ++j)
948 free(pargs[i]);
949 free(pargs);
950 pargs = NULL;
951 }
952 }
953
954 static int
walk_topo(topo_hdl_t * thp,char * uuid)955 walk_topo(topo_hdl_t *thp, char *uuid)
956 {
957 int err;
958 topo_walk_t *twp;
959 int flag;
960
961 if (getzoneid() != GLOBAL_ZONEID &&
962 strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
963 return (0);
964 }
965
966 if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err))
967 == NULL) {
968 (void) fprintf(stderr, "%s: failed to walk %s topology:"
969 " %s\n", g_pname, opt_s, topo_strerror(err));
970
971 return (-1);
972 }
973
974 /*
975 * Print standard header
976 */
977 if (!opt_e) {
978 char buf[32];
979 time_t tod = time(NULL);
980
981 (void) printf("TIME UUID\n");
982 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
983 (void) printf("%-15s %-32s\n", buf, uuid);
984 (void) printf("\n");
985 }
986
987 flag = opt_b != 0 ? TOPO_WALK_SIBLING : TOPO_WALK_CHILD;
988
989 if (topo_walk_step(twp, flag) == TOPO_WALK_ERR) {
990 (void) fprintf(stderr, "%s: failed to walk topology\n",
991 g_pname);
992 topo_walk_fini(twp);
993 return (-1);
994 }
995
996 topo_walk_fini(twp);
997
998 return (0);
999 }
1000
1001 static void
print_fmri_pgroup(topo_hdl_t * thp,const char * pgn,nvlist_t * nvl)1002 print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl)
1003 {
1004 char *dstab = NULL, *nstab = NULL;
1005 int32_t version = -1;
1006 nvlist_t *pnvl;
1007 nvpair_t *pnvp;
1008
1009 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab);
1010 (void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab);
1011 (void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version);
1012
1013 print_pgroup(thp, NULL, pgn, dstab, nstab, version);
1014
1015 for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL;
1016 pnvp = nvlist_next_nvpair(nvl, pnvp)) {
1017
1018 /*
1019 * Print property group and property name-value pair
1020 */
1021 if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp))
1022 == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) {
1023 (void) nvpair_value_nvlist(pnvp, &pnvl);
1024 print_prop_nameval(thp, NULL, pnvl);
1025
1026 }
1027
1028 }
1029 }
1030
1031 static void
print_fmri_props(topo_hdl_t * thp,nvlist_t * nvl)1032 print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl)
1033 {
1034 int i, err;
1035 struct prop_args *pp;
1036 nvlist_t *pnvl;
1037
1038 for (i = 0; i < pcnt; ++i) {
1039 pp = pargs[i];
1040
1041 if (pp->group == NULL)
1042 continue;
1043
1044 pnvl = NULL;
1045
1046 /*
1047 * If we have a valid value, this is a request to
1048 * set a property. Otherwise, just print the property
1049 * group and any specified properties.
1050 */
1051 if (pp->value == NULL) {
1052 if (pp->prop == NULL) {
1053
1054 /*
1055 * Print all properties in this group
1056 */
1057 if (topo_fmri_getpgrp(thp, nvl, pp->group,
1058 &pnvl, &err) < 0) {
1059 (void) fprintf(stderr, "%s: failed to "
1060 "get group %s: %s\n", g_pname,
1061 pp->group, topo_strerror(err));
1062 continue;
1063 } else {
1064 print_fmri_pgroup(thp, pp->group,
1065 pnvl);
1066 nvlist_free(pnvl);
1067 continue;
1068 }
1069 }
1070 if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop,
1071 NULL, &pnvl, &err) < 0) {
1072 (void) fprintf(stderr, "%s: failed to get "
1073 "%s.%s: %s\n", g_pname,
1074 pp->group, pp->prop,
1075 topo_strerror(err));
1076 continue;
1077 } else {
1078 print_fmri_pgroup(thp, pp->group, pnvl);
1079 print_prop_nameval(thp, NULL, pnvl);
1080 nvlist_free(nvl);
1081 }
1082 } else {
1083 set_prop(thp, NULL, nvl, pp);
1084 }
1085 }
1086 }
1087
1088 void
print_fmri(topo_hdl_t * thp,char * uuid)1089 print_fmri(topo_hdl_t *thp, char *uuid)
1090 {
1091 int ret, err;
1092 nvlist_t *nvl;
1093 char buf[32];
1094 time_t tod = time(NULL);
1095
1096 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
1097 (void) fprintf(stderr, "%s: failed to convert %s to nvlist: "
1098 "%s\n", g_pname, g_fmri, topo_strerror(err));
1099 return;
1100 }
1101
1102 (void) printf("TIME UUID\n");
1103 (void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
1104 (void) printf("%-15s %-32s\n", buf, uuid);
1105 (void) printf("\n");
1106
1107 (void) printf("%s\n", (char *)g_fmri);
1108
1109 if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
1110 char *aname = NULL, *fname = NULL, *lname = NULL;
1111 nvlist_t *asru = NULL;
1112 nvlist_t *fru = NULL;
1113
1114 if (topo_fmri_asru(thp, nvl, &asru, &err) == 0)
1115 (void) topo_fmri_nvl2str(thp, asru, &aname, &err);
1116 if (topo_fmri_fru(thp, nvl, &fru, &err) == 0)
1117 (void) topo_fmri_nvl2str(thp, fru, &fname, &err);
1118 (void) topo_fmri_label(thp, nvl, &lname, &err);
1119
1120 nvlist_free(fru);
1121 nvlist_free(asru);
1122
1123 if (aname != NULL) {
1124 (void) printf("\tASRU: %s\n", aname);
1125 topo_hdl_strfree(thp, aname);
1126 } else {
1127 (void) printf("\tASRU: -\n");
1128 }
1129 if (fname != NULL) {
1130 (void) printf("\tFRU: %s\n", fname);
1131 topo_hdl_strfree(thp, fname);
1132 } else {
1133 (void) printf("\tFRU: -\n");
1134 }
1135 if (lname != NULL) {
1136 (void) printf("\tLabel: %s\n", lname);
1137 topo_hdl_strfree(thp, lname);
1138 } else {
1139 (void) printf("\tLabel: -\n");
1140 }
1141 }
1142
1143 if (opt_S) {
1144 if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
1145 (void) printf("\tPresent: -\n");
1146 (void) printf("\tUnusable: -\n");
1147 return;
1148 }
1149
1150 if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
1151 (void) printf("\tPresent: -\n");
1152 else
1153 (void) printf("\tPresent: %s\n",
1154 ret ? "true" : "false");
1155
1156 if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
1157 (void) printf("\tUnusable: -\n");
1158 else
1159 (void) printf("\tUnusable: %s\n",
1160 ret ? "true" : "false");
1161
1162 nvlist_free(nvl);
1163 }
1164
1165 if (pargs && pcnt > 0)
1166 print_fmri_props(thp, nvl);
1167 }
1168
1169 int
fmtopo_exit(topo_hdl_t * thp,char * uuid,int err)1170 fmtopo_exit(topo_hdl_t *thp, char *uuid, int err)
1171 {
1172 if (uuid != NULL)
1173 topo_hdl_strfree(thp, uuid);
1174
1175 if (thp != NULL) {
1176 topo_snap_release(thp);
1177 topo_close(thp);
1178 }
1179
1180 if (pargs) {
1181 int i;
1182 for (i = 0; i < pcnt; ++i)
1183 free(pargs[i]);
1184 free(pargs);
1185 }
1186
1187 return (err);
1188 }
1189
1190 int
main(int argc,char * argv[])1191 main(int argc, char *argv[])
1192 {
1193 topo_hdl_t *thp = NULL;
1194 char *uuid = NULL;
1195 int c, err = 0;
1196
1197 g_pname = argv[0];
1198
1199 while (optind < argc) {
1200 while ((c = getopt(argc, argv, optstr)) != -1) {
1201 switch (c) {
1202 case 'b':
1203 opt_b++;
1204 break;
1205 case 'C':
1206 (void) atexit(abort);
1207 break;
1208 case 'd':
1209 opt_d++;
1210 break;
1211 case 'e':
1212 opt_e++;
1213 break;
1214 case 'm':
1215 opt_m = optarg;
1216 break;
1217 case 'P':
1218 pcnt++;
1219 break;
1220 case 'p':
1221 opt_p++;
1222 break;
1223 case 'V':
1224 opt_V++;
1225 break;
1226 case 'R':
1227 opt_R = optarg;
1228 break;
1229 case 's':
1230 opt_s = optarg;
1231 break;
1232 case 'S':
1233 opt_S++;
1234 break;
1235 case 't':
1236 opt_t++;
1237 break;
1238 case 'x':
1239 opt_x++;
1240 break;
1241 default:
1242 return (usage(stderr));
1243 }
1244 }
1245
1246 if (optind < argc) {
1247 if (g_fmri != NULL) {
1248 (void) fprintf(stderr, "%s: illegal argument "
1249 "-- %s\n", g_pname, argv[optind]);
1250 return (FMTOPO_EXIT_USAGE);
1251 } else {
1252 g_fmri = argv[optind++];
1253 }
1254 }
1255 }
1256
1257 if (pcnt > 0)
1258 get_pargs(argc, argv);
1259
1260 if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) {
1261 (void) fprintf(stderr, "%s: failed to open topology tree: %s\n",
1262 g_pname, topo_strerror(err));
1263 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1264 }
1265
1266 if (opt_d)
1267 topo_debug_set(thp, "module", "stderr");
1268
1269 if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) {
1270 (void) fprintf(stderr, "%s: failed to snapshot topology: %s\n",
1271 g_pname, topo_strerror(err));
1272 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1273 } else if (err != 0) {
1274 (void) fprintf(stderr, "%s: topology snapshot incomplete%s\n",
1275 g_pname, getzoneid() != GLOBAL_ZONEID &&
1276 strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0 ?
1277 " (" FM_FMRI_SCHEME_HC " scheme does not enumerate "
1278 "in a non-global zone)": "");
1279 }
1280
1281 if (opt_x) {
1282 if (opt_b) {
1283 (void) fprintf(stderr,
1284 "%s: -b and -x cannot be specified together\n",
1285 g_pname);
1286 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_USAGE));
1287 }
1288
1289 err = 0;
1290 if (topo_xml_print(thp, stdout, opt_s, &err) < 0)
1291 (void) fprintf(stderr, "%s: failed to print xml "
1292 "formatted topology:%s", g_pname,
1293 topo_strerror(err));
1294
1295 return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR :
1296 FMTOPO_EXIT_SUCCESS));
1297 }
1298
1299 if (opt_t || walk_topo(thp, uuid) < 0) {
1300 if (g_fmri != NULL)
1301 /*
1302 * Try getting some useful information
1303 */
1304 print_fmri(thp, uuid);
1305
1306 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
1307 }
1308
1309 return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_SUCCESS));
1310 }
1311