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