prtpicl.c revision da6837b3e07c5c71f29c61ce60821868f9fc3102
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#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
#define EM_TS_INVSIZE 17
/*
* 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 */
"picl_get_propval: invalid timestamp size\n" /* 17 */
};
/*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);
}
switch (propinfo->type) {
case PICL_PTYPE_CHARSTRING:
if (propinfo->size > 0)
(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:
if (propinfo->size != sizeof (val64)) {
print_errmsg(gettext(err_msg[EM_TS_INVSIZE]));
return (PICL_FAILURE);
}
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:
if (propinfo->size > 0)
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);
}