xref: /illumos-gate/usr/src/cmd/picl/prtpicl/prtpicl.c (revision 4f364e7c95ee7fd9d5bbeddc1940e92405bb0e72)
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
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
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
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
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
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
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
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
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