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