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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <alloca.h>
31 #include <libintl.h>
32 #include <locale.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include <inttypes.h>
36 #include <sys/termios.h>
37 #include <picl.h>
38
39 /*
40 * Constant definitions and macros
41 */
42 #define COL_DELIM "|"
43 #define ROOT_LEVEL 0
44 #define LEVEL_INDENT 4
45 #define PROP_INDENT 2
46 #define NCOLS 80
47 #define NODEINFO_LEFT_MARGIN(x) (x * LEVEL_INDENT)
48 #define PROPINFO_LEFT_MARGIN(x) (x * LEVEL_INDENT + PROP_INDENT)
49
50 #define PRIxPICLTBL PRIx64
51 #define PRIxPICLHDL PRIx64
52
53 /*
54 * Program variables
55 */
56 static char *prog;
57 static int verbose_mode = 0;
58
59 /*
60 * Error codes
61 */
62 #define EM_USAGE 0
63 #define EM_INIT 1
64 #define EM_GETROOT 2
65 #define EM_GETPVAL 3
66 #define EM_GETNXTBYCOL 4
67 #define EM_GETNXTBYROW 5
68 #define EM_GETPINFO 6
69 #define EM_GETPVALBYNAME 7
70 #define EM_GETPROPBYNAME 8
71 #define EM_INT_INVSIZE 9
72 #define EM_UINT_INVSIZE 10
73 #define EM_FLOAT_INVSIZE 11
74 #define EM_TS_INVALID 12
75 #define EM_TABLE_INVSIZE 13
76 #define EM_REF_INVSIZE 14
77 #define EM_TYPE_UNKNOWN 15
78 #define EM_TS_OVERFLOW 16
79 #define EM_TS_INVSIZE 17
80
81 /*
82 * Error mesage texts
83 */
84 static char *err_msg[] = {
85 /* program usage */
86 "Usage: %s [-v] [-c <picl_class>]\n", /* 0 */
87 /* picl call failed messages */
88 "picl_initialize failed: %s\n", /* 1 */
89 "picl_get_root failed: %s\n", /* 2 */
90 "picl_get_propval failed: %s\n", /* 3 */
91 "picl_get_next_by_col failed: %s\n", /* 4 */
92 "picl_get_next_by_row failed: %s\n", /* 5 */
93 "picl_get_propinfo failed: %s\n", /* 6 */
94 "picl_get_propval_by_name failed: %s\n", /* 7 */
95 "picl_get_prop_by_name failed: %s\n", /* 8 */
96 /* invalid data error messages */
97 "picl_get_propval: invalid int size %d\n", /* 9 */
98 "picl_get_propval: invalid unsigned int size %d\n", /* 10 */
99 "picl_get_propval: invalid float size %d\n", /* 11 */
100 "picl_get_propval: invalid timestamp\n", /* 12 */
101 "picl_get_propval: invalid table handle size %d\n", /* 13 */
102 "picl_get_propval: invalid reference size %d\n", /* 14 */
103 "picl_get_propval: unknown type\n", /* 15 */
104 "picl_get_propval: timestamp value too large\n", /* 16 */
105 "picl_get_propval: invalid timestamp size\n" /* 17 */
106 };
107
108 /*PRINTFLIKE1*/
109 static void
print_errmsg(char * message,...)110 print_errmsg(char *message, ...)
111 {
112 va_list ap;
113
114 va_start(ap, message);
115 (void) fprintf(stderr, "%s: ", prog);
116 (void) vfprintf(stderr, message, ap);
117 va_end(ap);
118 }
119
120 /*
121 * Print prtpicl usage
122 */
123 static void
usage(void)124 usage(void)
125 {
126 print_errmsg(gettext(err_msg[EM_USAGE]), prog);
127 exit(1);
128 }
129
130 /*
131 * print a bytearray value and format it to fit in 80 columns
132 */
133 static void
print_bytearray(int lvl,uint8_t * vbuf,size_t nbytes)134 print_bytearray(int lvl, uint8_t *vbuf, size_t nbytes)
135 {
136 int cnum;
137 int columns;
138 char *s;
139 struct winsize winsize;
140 size_t i;
141
142 /*
143 * The COLUMNS_PER_BYTE is set to 4 to match the printf
144 * format used below, i.e. " %02x ", to print a byte
145 */
146 #define COLUMNS_PER_BYTE 4
147
148 /*
149 * Kind of a hack to determine the width of the output...
150 */
151 columns = NCOLS;
152 if ((s = getenv("COLUMNS")) != NULL && (cnum = atoi(s)) > 0)
153 columns = cnum;
154 else if (isatty(fileno(stdout)) &&
155 ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0 &&
156 winsize.ws_col != 0)
157 columns = winsize.ws_col;
158
159
160 cnum = PROPINFO_LEFT_MARGIN(lvl);
161 if ((nbytes * COLUMNS_PER_BYTE + cnum) > columns) {
162 (void) printf("\n");
163 cnum = 0;
164 }
165 for (i = 0; i < nbytes; ++i) {
166 if (cnum > columns - COLUMNS_PER_BYTE) {
167 (void) printf("\n");
168 cnum = 0;
169 }
170 (void) printf(" %02x ", vbuf[i]);
171 cnum += COLUMNS_PER_BYTE;
172 }
173 }
174
175 /*
176 * Print a property's value
177 * If the property is read protected, return success.
178 * If an invalid/stale handle error is encountered, return the error. For
179 * other errors, print a message and return success.
180 */
181 static int
print_propval(int lvl,picl_prophdl_t proph,const picl_propinfo_t * propinfo)182 print_propval(int lvl, picl_prophdl_t proph, const picl_propinfo_t *propinfo)
183 {
184 int err;
185 void *vbuf;
186 char *str;
187 uint64_t val64;
188 time_t tmp;
189
190 /*
191 * If property is read protected, print a message and continue
192 */
193 if (!(propinfo->accessmode & PICL_READ)) {
194 (void) printf("<%s>", gettext("WRITE-ONLY"));
195 return (PICL_SUCCESS);
196 }
197
198 vbuf = alloca(propinfo->size);
199 if (propinfo->type == PICL_PTYPE_VOID)
200 return (PICL_SUCCESS);
201
202 err = picl_get_propval(proph, vbuf, propinfo->size);
203 /*
204 * If the error is not a stale/invalid handle or noresponse, continue
205 * by ignoring the error/skipping the property.
206 */
207 if ((err == PICL_INVALIDHANDLE) || (err == PICL_STALEHANDLE) ||
208 (err == PICL_NORESPONSE))
209 return (err);
210 else if (err != PICL_SUCCESS) {
211 (void) printf("<%s: %s>", gettext("ERROR"), picl_strerror(err));
212 return (PICL_SUCCESS);
213 }
214
215 switch (propinfo->type) {
216 case PICL_PTYPE_CHARSTRING:
217 if (propinfo->size > 0)
218 (void) printf(" %s ", (char *)vbuf);
219 break;
220 case PICL_PTYPE_INT:
221 switch (propinfo->size) {
222 case sizeof (int8_t):
223 /* avoid using PRId8 until lint recognizes hh */
224 (void) printf(" %d ", *(int8_t *)vbuf);
225 break;
226 case sizeof (int16_t):
227 (void) printf(" %" PRId16 " ", *(int16_t *)vbuf);
228 break;
229 case sizeof (int32_t):
230 (void) printf(" %" PRId32 " ", *(int32_t *)vbuf);
231 break;
232 case sizeof (int64_t):
233 (void) printf(" %" PRId64 " ", *(int64_t *)vbuf);
234 break;
235 default:
236 print_errmsg(gettext(err_msg[EM_INT_INVSIZE]),
237 propinfo->size);
238 return (PICL_FAILURE);
239 }
240 break;
241 case PICL_PTYPE_UNSIGNED_INT:
242 switch (propinfo->size) {
243 case sizeof (uint8_t):
244 /* avoid using PRIx8 until lint recognizes hh */
245 (void) printf(" %#x ", *(uint8_t *)vbuf);
246 break;
247 case sizeof (uint16_t):
248 (void) printf(" %#" PRIx16 " ", *(uint16_t *)vbuf);
249 break;
250 case sizeof (uint32_t):
251 (void) printf(" %#" PRIx32 " ", *(uint32_t *)vbuf);
252 break;
253 case sizeof (uint64_t):
254 (void) printf(" %#" PRIx64 " ", *(uint64_t *)vbuf);
255 break;
256 default:
257 print_errmsg(gettext(err_msg[EM_UINT_INVSIZE]),
258 propinfo->size);
259 return (PICL_FAILURE);
260 }
261 break;
262 case PICL_PTYPE_FLOAT:
263 switch (propinfo->size) {
264 case sizeof (float):
265 (void) printf(" %f ", *(float *)vbuf);
266 break;
267 case sizeof (double):
268 (void) printf(" %f ", *(double *)vbuf);
269 break;
270 default:
271 print_errmsg(gettext(err_msg[EM_FLOAT_INVSIZE]),
272 propinfo->size);
273 return (PICL_FAILURE);
274 }
275 break;
276 case PICL_PTYPE_TIMESTAMP:
277 if (propinfo->size != sizeof (val64)) {
278 print_errmsg(gettext(err_msg[EM_TS_INVSIZE]));
279 return (PICL_FAILURE);
280 }
281 val64 = *(uint64_t *)vbuf;
282 tmp = (time_t)val64;
283 if ((uint64_t)tmp != val64) {
284 print_errmsg(gettext(err_msg[EM_TS_OVERFLOW]));
285 return (PICL_FAILURE);
286 }
287 str = ctime(&tmp);
288 if (str == NULL) {
289 print_errmsg(gettext(err_msg[EM_TS_INVALID]));
290 return (PICL_FAILURE);
291 }
292 str[strlen(str) - 1] = '\0';
293 (void) printf(" %s ", str);
294 break;
295 case PICL_PTYPE_TABLE:
296 if (propinfo->size != sizeof (picl_prophdl_t)) {
297 print_errmsg(gettext(err_msg[EM_TABLE_INVSIZE]),
298 propinfo->size);
299 return (PICL_FAILURE);
300 }
301 (void) printf("(%" PRIxPICLTBL "TBL) ",
302 *(picl_prophdl_t *)vbuf);
303 break;
304 case PICL_PTYPE_REFERENCE:
305 if (propinfo->size != sizeof (picl_nodehdl_t)) {
306 print_errmsg(gettext(err_msg[EM_REF_INVSIZE]),
307 propinfo->size);
308 return (PICL_FAILURE);
309 }
310 (void) printf(" (%" PRIxPICLHDL "H) ", *(picl_nodehdl_t *)vbuf);
311 break;
312 case PICL_PTYPE_BYTEARRAY:
313 if (propinfo->size > 0)
314 print_bytearray(lvl, vbuf, propinfo->size);
315 break;
316 default:
317 print_errmsg(gettext(err_msg[EM_TYPE_UNKNOWN]));
318 return (PICL_FAILURE);
319 }
320 return (PICL_SUCCESS);
321 }
322
323 /*
324 * print table property value
325 */
326 static int
print_table_prop(int lvl,picl_prophdl_t tblh)327 print_table_prop(int lvl, picl_prophdl_t tblh)
328 {
329 picl_prophdl_t rowproph;
330 picl_prophdl_t colproph;
331 int err;
332 picl_propinfo_t propinfo;
333
334 for (err = picl_get_next_by_col(tblh, &rowproph); err != PICL_ENDOFLIST;
335 err = picl_get_next_by_col(rowproph, &rowproph)) {
336 if (err != PICL_SUCCESS) {
337 print_errmsg(gettext(err_msg[EM_GETNXTBYCOL]),
338 picl_strerror(err));
339 return (err);
340 }
341
342 (void) printf("%*s %s", PROPINFO_LEFT_MARGIN(lvl), " ",
343 COL_DELIM);
344
345 for (colproph = rowproph; err != PICL_ENDOFLIST;
346 err = picl_get_next_by_row(colproph, &colproph)) {
347
348 if (err != PICL_SUCCESS) {
349 print_errmsg(gettext(err_msg[EM_GETNXTBYROW]),
350 picl_strerror(err));
351 return (err);
352 }
353
354 err = picl_get_propinfo(colproph, &propinfo);
355 if (err != PICL_SUCCESS) {
356 print_errmsg(gettext(err_msg[EM_GETPINFO]),
357 picl_strerror(err));
358 return (err);
359 }
360
361 err = print_propval(lvl, colproph, &propinfo);
362 if (err != PICL_SUCCESS)
363 return (err);
364 (void) printf(COL_DELIM);
365 }
366 (void) printf("\n");
367 }
368 return (PICL_SUCCESS);
369 }
370
371 /*
372 * Print the properties (name = value) of a node. If an error occurs
373 * when printing the property value, stop. print_propval() suppresses
374 * errors during getting property value except for stale/invalid handle
375 * and no response errors.
376 */
377 static int
print_proplist(int lvl,picl_nodehdl_t nodeh)378 print_proplist(int lvl, picl_nodehdl_t nodeh)
379 {
380 int err;
381 picl_prophdl_t proph;
382 picl_propinfo_t propinfo;
383 picl_prophdl_t tblh;
384
385 for (err = picl_get_first_prop(nodeh, &proph); err == PICL_SUCCESS;
386 err = picl_get_next_prop(proph, &proph)) {
387
388 err = picl_get_propinfo(proph, &propinfo);
389 if (err != PICL_SUCCESS) {
390 print_errmsg(gettext(err_msg[EM_GETPINFO]),
391 picl_strerror(err));
392 return (err);
393 }
394
395 if (propinfo.type == PICL_PTYPE_VOID)
396 (void) printf("%*s:%s\n", PROPINFO_LEFT_MARGIN(lvl),
397 " ", propinfo.name);
398 else {
399 (void) printf("%*s:%s\t", PROPINFO_LEFT_MARGIN(lvl),
400 " ", propinfo.name);
401 err = print_propval(lvl, proph, &propinfo);
402 (void) printf("\n");
403 if (err != PICL_SUCCESS)
404 return (err);
405 }
406
407 /*
408 * Expand the table property
409 */
410 if (propinfo.type == PICL_PTYPE_TABLE) {
411 err = picl_get_propval(proph, &tblh, propinfo.size);
412 if (err != PICL_SUCCESS) {
413 print_errmsg(gettext(err_msg[EM_GETPVAL]),
414 picl_strerror(err));
415 return (err);
416 }
417 err = print_table_prop(lvl, tblh);
418 if (err != PICL_SUCCESS)
419 return (err);
420 }
421 }
422 return (PICL_SUCCESS);
423 }
424
425 /*
426 * Recursively print the PICL tree
427 * When piclclass is specified, print only the nodes of that class.
428 */
429 static int
print_tree_by_class(int lvl,picl_nodehdl_t nodeh,char * piclclass)430 print_tree_by_class(int lvl, picl_nodehdl_t nodeh, char *piclclass)
431 {
432 picl_nodehdl_t chdh;
433 char *nameval;
434 char classval[PICL_PROPNAMELEN_MAX];
435 int err;
436 picl_prophdl_t proph;
437 picl_propinfo_t pinfo;
438
439 /*
440 * First get the class name of the node to compare with piclclass
441 */
442 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, classval,
443 sizeof (classval));
444 if (err != PICL_SUCCESS) {
445 print_errmsg(gettext(err_msg[EM_GETPVALBYNAME]),
446 picl_strerror(err));
447 return (err);
448 }
449
450 #define MATCHING_CLASSVAL(x, y) ((x == NULL) || (strcasecmp(x, y) == 0))
451
452 if (MATCHING_CLASSVAL(piclclass, classval)) {
453 err = picl_get_prop_by_name(nodeh, PICL_PROP_NAME, &proph);
454 if (err != PICL_SUCCESS) {
455 print_errmsg(gettext(err_msg[EM_GETPROPBYNAME]),
456 picl_strerror(err));
457 return (err);
458 }
459
460 err = picl_get_propinfo(proph, &pinfo);
461 if (err != PICL_SUCCESS) {
462 print_errmsg(gettext(err_msg[EM_GETPINFO]),
463 picl_strerror(err));
464 return (err);
465 }
466
467 nameval = alloca(pinfo.size);
468 err = picl_get_propval(proph, nameval, pinfo.size);
469 if (err != PICL_SUCCESS) {
470 print_errmsg(gettext(err_msg[EM_GETPVAL]),
471 picl_strerror(err));
472 return (err);
473 }
474
475 (void) printf("%*s %s (%s, %" PRIxPICLHDL ")\n",
476 NODEINFO_LEFT_MARGIN(lvl), " ", nameval, classval, nodeh);
477
478 if (verbose_mode) {
479 err = print_proplist(lvl, nodeh);
480 if (err != PICL_SUCCESS)
481 return (err);
482 }
483 ++lvl;
484 }
485
486 for (err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
487 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
488 err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
489 sizeof (picl_nodehdl_t))) {
490
491 if (err != PICL_SUCCESS) {
492 print_errmsg(gettext(err_msg[EM_GETPVALBYNAME]),
493 picl_strerror(err));
494 return (err);
495 }
496
497 err = print_tree_by_class(lvl, chdh, piclclass);
498 if (err != PICL_SUCCESS)
499 return (err);
500 }
501 return (PICL_SUCCESS);
502 }
503
504
505 /*
506 * This program prints the PICL tree.
507 * If an invalid handle or stale handle is encountered while printing
508 * the tree, it starts over from the root node.
509 */
510 int
main(int argc,char ** argv)511 main(int argc, char **argv)
512 {
513 int err;
514 picl_nodehdl_t rooth;
515 int c;
516 int done;
517 char piclclass[PICL_CLASSNAMELEN_MAX];
518 int cflg;
519
520 (void) setlocale(LC_ALL, "");
521 (void) textdomain(TEXT_DOMAIN);
522
523 if ((prog = strrchr(argv[0], '/')) == NULL)
524 prog = argv[0];
525 else
526 prog++;
527
528 cflg = 0;
529 while ((c = getopt(argc, argv, "vc:")) != EOF) {
530 switch (c) {
531 case 'v':
532 verbose_mode = 1;
533 break;
534 case 'c':
535 cflg = 1;
536 (void) strlcpy(piclclass, optarg,
537 PICL_CLASSNAMELEN_MAX);
538 break;
539 case '?':
540 /*FALLTHROUGH*/
541 default:
542 usage();
543 /*NOTREACHED*/
544 }
545 }
546 if (optind != argc)
547 usage();
548
549 err = picl_initialize();
550 if (err != PICL_SUCCESS) {
551 print_errmsg(gettext(err_msg[EM_INIT]), picl_strerror(err));
552 exit(1);
553 }
554
555
556 do {
557 done = 1;
558 err = picl_get_root(&rooth);
559 if (err != PICL_SUCCESS) {
560 print_errmsg(gettext(err_msg[EM_GETROOT]),
561 picl_strerror(err));
562 exit(1);
563 }
564
565 err = print_tree_by_class(ROOT_LEVEL, rooth,
566 (cflg ? piclclass : NULL));
567 if ((err == PICL_STALEHANDLE) || (err == PICL_INVALIDHANDLE))
568 done = 0;
569 } while (!done);
570
571 (void) picl_shutdown();
572
573 return (0);
574 }
575