OpenSolaris_b135/cmd/picl/prtpicl/prtpicl.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <alloca.h>
#include <libintl.h>
#include <locale.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
#include <sys/termios.h>
#include <picl.h>

/*
 * Constant definitions and macros
 */
#define	COL_DELIM		"|"
#define	ROOT_LEVEL		0
#define	LEVEL_INDENT		4
#define	PROP_INDENT		2
#define	NCOLS			80
#define	NODEINFO_LEFT_MARGIN(x)	(x * LEVEL_INDENT)
#define	PROPINFO_LEFT_MARGIN(x)	(x * LEVEL_INDENT + PROP_INDENT)

#define	PRIxPICLTBL		PRIx64
#define	PRIxPICLHDL		PRIx64

/*
 * Program variables
 */
static	char	*prog;
static	int	verbose_mode = 0;

/*
 * Error codes
 */
#define	EM_USAGE		0
#define	EM_INIT			1
#define	EM_GETROOT		2
#define	EM_GETPVAL		3
#define	EM_GETNXTBYCOL		4
#define	EM_GETNXTBYROW		5
#define	EM_GETPINFO		6
#define	EM_GETPVALBYNAME	7
#define	EM_GETPROPBYNAME	8
#define	EM_INT_INVSIZE		9
#define	EM_UINT_INVSIZE		10
#define	EM_FLOAT_INVSIZE	11
#define	EM_TS_INVALID		12
#define	EM_TABLE_INVSIZE	13
#define	EM_REF_INVSIZE		14
#define	EM_TYPE_UNKNOWN		15
#define	EM_TS_OVERFLOW		16

/*
 * Error mesage texts
 */
static	char	*err_msg[] = {
	/* program usage */
	"Usage: %s [-v] [-c <picl_class>]\n",			/*  0 */
	/* picl call failed messages */
	"picl_initialize failed: %s\n",				/*  1 */
	"picl_get_root failed: %s\n",				/*  2 */
	"picl_get_propval failed: %s\n",			/*  3 */
	"picl_get_next_by_col failed: %s\n",			/*  4 */
	"picl_get_next_by_row failed: %s\n",			/*  5 */
	"picl_get_propinfo failed: %s\n",			/*  6 */
	"picl_get_propval_by_name failed: %s\n",		/*  7 */
	"picl_get_prop_by_name failed: %s\n",			/*  8 */
	/* invalid data error messages */
	"picl_get_propval: invalid int size %d\n",		/*  9 */
	"picl_get_propval: invalid unsigned int size %d\n",	/* 10 */
	"picl_get_propval: invalid float size %d\n",		/* 11 */
	"picl_get_propval: invalid timestamp\n",		/* 12 */
	"picl_get_propval: invalid table handle size %d\n",	/* 13 */
	"picl_get_propval: invalid reference size %d\n",	/* 14 */
	"picl_get_propval: unknown type\n",			/* 15 */
	"picl_get_propval: timestamp value too large\n"		/* 16 */
};

/*PRINTFLIKE1*/
static void
print_errmsg(char *message, ...)
{
	va_list ap;

	va_start(ap, message);
	(void) fprintf(stderr, "%s: ", prog);
	(void) vfprintf(stderr, message, ap);
	va_end(ap);
}

/*
 * Print prtpicl usage
 */
static void
usage(void)
{
	print_errmsg(gettext(err_msg[EM_USAGE]), prog);
	exit(1);
}

/*
 * print a bytearray value and format it to fit in 80 columns
 */
static void
print_bytearray(int lvl, uint8_t *vbuf, size_t nbytes)
{
	int		cnum;
	int		columns;
	char		*s;
	struct winsize	winsize;
	size_t		i;

	/*
	 * The COLUMNS_PER_BYTE is set to 4 to match the printf
	 * format used below, i.e. " %02x ", to print a byte
	 */
#define	COLUMNS_PER_BYTE	4

	/*
	 * Kind of a hack to determine the width of the output...
	 */
	columns = NCOLS;
	if ((s = getenv("COLUMNS")) != NULL && (cnum = atoi(s)) > 0)
		columns = cnum;
	else if (isatty(fileno(stdout)) &&
	    ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0 &&
	    winsize.ws_col != 0)
		columns = winsize.ws_col;


	cnum = PROPINFO_LEFT_MARGIN(lvl);
	if ((nbytes * COLUMNS_PER_BYTE + cnum) > columns) {
		(void) printf("\n");
		cnum = 0;
	}
	for (i = 0; i < nbytes; ++i) {
		if (cnum > columns - COLUMNS_PER_BYTE) {
			(void) printf("\n");
			cnum = 0;
		}
		(void) printf(" %02x ", vbuf[i]);
		cnum += COLUMNS_PER_BYTE;
	}
}

/*
 * Print a property's value
 * If the property is read protected, return success.
 * If an invalid/stale handle error is encountered, return the error. For
 * other errors, print a message and return success.
 */
static int
print_propval(int lvl, picl_prophdl_t proph, const picl_propinfo_t *propinfo)
{
	int		err;
	void		*vbuf;
	char		*str;
	uint64_t	val64;
	time_t		tmp;

	/*
	 * If property is read protected, print a message and continue
	 */
	if (!(propinfo->accessmode & PICL_READ)) {
		(void) printf("<%s>", gettext("WRITE-ONLY"));
		return (PICL_SUCCESS);
	}

	vbuf = alloca(propinfo->size);
	if (propinfo->type == PICL_PTYPE_VOID)
		return (PICL_SUCCESS);

	err = picl_get_propval(proph, vbuf, propinfo->size);
	/*
	 * If the error is not a stale/invalid handle or noresponse, continue
	 * by ignoring the error/skipping the property.
	 */
	if ((err == PICL_INVALIDHANDLE) || (err == PICL_STALEHANDLE) ||
	    (err == PICL_NORESPONSE))
		return (err);
	else if (err != PICL_SUCCESS) {
		(void) printf("<%s: %s>", gettext("ERROR"), picl_strerror(err));
		return (PICL_SUCCESS);
	}

	assert(vbuf != NULL);
	assert(propinfo->size > 0);

	switch (propinfo->type) {
	case PICL_PTYPE_CHARSTRING:
		(void) printf(" %s ", (char *)vbuf);
		break;
	case PICL_PTYPE_INT:
		switch (propinfo->size) {
		case sizeof (int8_t):
			/* avoid using PRId8 until lint recognizes hh */
			(void) printf(" %d ", *(int8_t *)vbuf);
			break;
		case sizeof (int16_t):
			(void) printf(" %" PRId16 " ", *(int16_t *)vbuf);
			break;
		case sizeof (int32_t):
			(void) printf(" %" PRId32 " ", *(int32_t *)vbuf);
			break;
		case sizeof (int64_t):
			(void) printf(" %" PRId64 " ", *(int64_t *)vbuf);
			break;
		default:
			print_errmsg(gettext(err_msg[EM_INT_INVSIZE]),
			    propinfo->size);
			return (PICL_FAILURE);
		}
		break;
	case PICL_PTYPE_UNSIGNED_INT:
		switch (propinfo->size) {
		case sizeof (uint8_t):
			/* avoid using PRIx8 until lint recognizes hh */
			(void) printf(" %#x ", *(uint8_t *)vbuf);
			break;
		case sizeof (uint16_t):
			(void) printf(" %#" PRIx16 " ", *(uint16_t *)vbuf);
			break;
		case sizeof (uint32_t):
			(void) printf(" %#" PRIx32 " ", *(uint32_t *)vbuf);
			break;
		case sizeof (uint64_t):
			(void) printf(" %#" PRIx64 " ", *(uint64_t *)vbuf);
			break;
		default:
			print_errmsg(gettext(err_msg[EM_UINT_INVSIZE]),
			    propinfo->size);
			return (PICL_FAILURE);
		}
		break;
	case PICL_PTYPE_FLOAT:
		switch (propinfo->size) {
		case sizeof (float):
			(void) printf(" %f ", *(float *)vbuf);
			break;
		case sizeof (double):
			(void) printf(" %f ", *(double *)vbuf);
			break;
		default:
			print_errmsg(gettext(err_msg[EM_FLOAT_INVSIZE]),
			    propinfo->size);
			return (PICL_FAILURE);
		}
		break;
	case PICL_PTYPE_TIMESTAMP:
		val64 = *(uint64_t *)vbuf;
		tmp = (time_t)val64;
		if ((uint64_t)tmp != val64) {
			print_errmsg(gettext(err_msg[EM_TS_OVERFLOW]));
			return (PICL_FAILURE);
		}
		str = ctime(&tmp);
		if (str == NULL) {
			print_errmsg(gettext(err_msg[EM_TS_INVALID]));
			return (PICL_FAILURE);
		}
		str[strlen(str) - 1] = '\0';
		(void) printf(" %s ", str);
		break;
	case PICL_PTYPE_TABLE:
		if (propinfo->size != sizeof (picl_prophdl_t)) {
			print_errmsg(gettext(err_msg[EM_TABLE_INVSIZE]),
			    propinfo->size);
			return (PICL_FAILURE);
		}
		(void) printf("(%" PRIxPICLTBL "TBL) ",
		    *(picl_prophdl_t *)vbuf);
		break;
	case PICL_PTYPE_REFERENCE:
		if (propinfo->size != sizeof (picl_nodehdl_t)) {
			print_errmsg(gettext(err_msg[EM_REF_INVSIZE]),
			    propinfo->size);
			return (PICL_FAILURE);
		}
		(void) printf(" (%" PRIxPICLHDL "H) ", *(picl_nodehdl_t *)vbuf);
		break;
	case PICL_PTYPE_BYTEARRAY:
		print_bytearray(lvl, vbuf, propinfo->size);
		break;
	default:
		print_errmsg(gettext(err_msg[EM_TYPE_UNKNOWN]));
		return (PICL_FAILURE);
	}
	return (PICL_SUCCESS);
}

/*
 * print table property value
 */
static int
print_table_prop(int lvl, picl_prophdl_t tblh)
{
	picl_prophdl_t	rowproph;
	picl_prophdl_t	colproph;
	int		err;
	picl_propinfo_t	propinfo;

	for (err = picl_get_next_by_col(tblh, &rowproph); err != PICL_ENDOFLIST;
	    err = picl_get_next_by_col(rowproph, &rowproph)) {
		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETNXTBYCOL]),
			    picl_strerror(err));
			return (err);
		}

		(void) printf("%*s %s", PROPINFO_LEFT_MARGIN(lvl), " ",
		    COL_DELIM);

		for (colproph = rowproph; err != PICL_ENDOFLIST;
		    err = picl_get_next_by_row(colproph, &colproph)) {

			if (err != PICL_SUCCESS) {
				print_errmsg(gettext(err_msg[EM_GETNXTBYROW]),
				    picl_strerror(err));
				return (err);
			}

			err = picl_get_propinfo(colproph, &propinfo);
			if (err != PICL_SUCCESS) {
				print_errmsg(gettext(err_msg[EM_GETPINFO]),
				    picl_strerror(err));
				return (err);
			}

			err = print_propval(lvl, colproph, &propinfo);
			if (err != PICL_SUCCESS)
				return (err);
			(void) printf(COL_DELIM);
		}
		(void) printf("\n");
	}
	return (PICL_SUCCESS);
}

/*
 * Print the properties (name = value) of a node. If an error occurs
 * when printing the property value, stop. print_propval() suppresses
 * errors during getting property value except for stale/invalid handle
 * and no response errors.
 */
static int
print_proplist(int lvl, picl_nodehdl_t nodeh)
{
	int		err;
	picl_prophdl_t	proph;
	picl_propinfo_t	propinfo;
	picl_prophdl_t	tblh;

	for (err = picl_get_first_prop(nodeh, &proph); err == PICL_SUCCESS;
	    err = picl_get_next_prop(proph, &proph)) {

		err = picl_get_propinfo(proph, &propinfo);
		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETPINFO]),
			    picl_strerror(err));
			return (err);
		}

		if (propinfo.type == PICL_PTYPE_VOID)
			(void) printf("%*s:%s\n", PROPINFO_LEFT_MARGIN(lvl),
			    " ", propinfo.name);
		else {
			(void) printf("%*s:%s\t", PROPINFO_LEFT_MARGIN(lvl),
			    " ", propinfo.name);
			err = print_propval(lvl, proph, &propinfo);
			(void) printf("\n");
			if (err != PICL_SUCCESS)
				return (err);
		}

		/*
		 * Expand the table property
		 */
		if (propinfo.type == PICL_PTYPE_TABLE) {
			err = picl_get_propval(proph, &tblh, propinfo.size);
			if (err != PICL_SUCCESS) {
				print_errmsg(gettext(err_msg[EM_GETPVAL]),
				    picl_strerror(err));
				return (err);
			}
			err = print_table_prop(lvl, tblh);
			if (err != PICL_SUCCESS)
				return (err);
		}
	}
	return (PICL_SUCCESS);
}

/*
 * Recursively print the PICL tree
 * When piclclass is specified, print only the nodes of that class.
 */
static int
print_tree_by_class(int lvl, picl_nodehdl_t nodeh, char *piclclass)
{
	picl_nodehdl_t	chdh;
	char		*nameval;
	char		classval[PICL_PROPNAMELEN_MAX];
	int		err;
	picl_prophdl_t	proph;
	picl_propinfo_t	pinfo;

	/*
	 * First get the class name of the node to compare with piclclass
	 */
	err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, classval,
	    sizeof (classval));
	if (err != PICL_SUCCESS) {
		print_errmsg(gettext(err_msg[EM_GETPVALBYNAME]),
		    picl_strerror(err));
		return (err);
	}

#define	MATCHING_CLASSVAL(x, y)	((x == NULL) || (strcasecmp(x, y) == 0))

	if (MATCHING_CLASSVAL(piclclass, classval)) {
		err = picl_get_prop_by_name(nodeh, PICL_PROP_NAME, &proph);
		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETPROPBYNAME]),
			    picl_strerror(err));
			return (err);
		}

		err = picl_get_propinfo(proph, &pinfo);
		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETPINFO]),
			    picl_strerror(err));
			return (err);
		}

		nameval = alloca(pinfo.size);
		err = picl_get_propval(proph, nameval, pinfo.size);
		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETPVAL]),
			    picl_strerror(err));
			return (err);
		}

		(void) printf("%*s %s (%s, %" PRIxPICLHDL ")\n",
		    NODEINFO_LEFT_MARGIN(lvl), " ", nameval, classval, nodeh);

		if (verbose_mode) {
			err = print_proplist(lvl, nodeh);
			if (err != PICL_SUCCESS)
				return (err);
		}
		++lvl;
	}

	for (err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
		    sizeof (picl_nodehdl_t))) {

		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETPVALBYNAME]),
			    picl_strerror(err));
			return (err);
		}

		err = print_tree_by_class(lvl, chdh, piclclass);
		if (err != PICL_SUCCESS)
			return (err);
	}
	return (PICL_SUCCESS);
}


/*
 * This program prints the PICL tree.
 * If an invalid handle or stale handle is encountered while printing
 * the tree, it starts over from the root node.
 */
int
main(int argc, char **argv)
{
	int		err;
	picl_nodehdl_t	rooth;
	int		c;
	int		done;
	char		piclclass[PICL_CLASSNAMELEN_MAX];
	int		cflg;

	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	if ((prog = strrchr(argv[0], '/')) == NULL)
		prog = argv[0];
	else
		prog++;

	cflg = 0;
	while ((c = getopt(argc, argv, "vc:")) != EOF) {
		switch (c) {
		case 'v':
			verbose_mode = 1;
			break;
		case 'c':
			cflg = 1;
			(void) strlcpy(piclclass, optarg,
			    PICL_CLASSNAMELEN_MAX);
			break;
		case '?':
			/*FALLTHROUGH*/
		default:
			usage();
			/*NOTREACHED*/
		}
	}
	if (optind != argc)
		usage();

	err = picl_initialize();
	if (err != PICL_SUCCESS) {
		print_errmsg(gettext(err_msg[EM_INIT]), picl_strerror(err));
		exit(1);
	}


	do {
		done = 1;
		err = picl_get_root(&rooth);
		if (err != PICL_SUCCESS) {
			print_errmsg(gettext(err_msg[EM_GETROOT]),
			    picl_strerror(err));
			exit(1);
		}

		err = print_tree_by_class(ROOT_LEVEL, rooth,
		    (cflg ? piclclass : NULL));
		if ((err == PICL_STALEHANDLE) || (err == PICL_INVALIDHANDLE))
			done = 0;
	} while (!done);

	(void) picl_shutdown();

	return (0);
}