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