1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1699 ps154918 * Common Development and Distribution License (the "License"). 6 1699 ps154918 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 6201 dt207653 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <alloca.h> 27 0 stevel #include <assert.h> 28 0 stevel #include <errno.h> 29 0 stevel #include <libintl.h> 30 0 stevel #include <stdarg.h> 31 0 stevel #include <stdio.h> 32 0 stevel #include <stdlib.h> 33 0 stevel #include <string.h> 34 4392 dt207653 #include <ctype.h> 35 8244 Dipti #include <wchar.h> 36 8244 Dipti #include <wctype.h> 37 0 stevel 38 0 stevel #include "fru_tag.h" 39 0 stevel #include "libfrup.h" 40 0 stevel #include "libfrureg.h" 41 0 stevel 42 0 stevel 43 0 stevel #define NUM_ITER_BYTES 4 44 0 stevel 45 0 stevel #define HEAD_ITER 0 46 0 stevel #define TAIL_ITER 1 /* not used */ 47 0 stevel #define NUM_ITER 2 48 0 stevel #define MAX_ITER 3 49 0 stevel 50 0 stevel #define INDENT 3 51 0 stevel #define TIMESTRINGLEN 128 52 1699 ps154918 #define TEMPERATURE_OFFSET 73 53 5270 dt207653 #define MIN_VERSION 17 54 7247 aa222140 #define GMT "%a, %b %d %Y %H:%M:%S GMT" 55 8244 Dipti 56 8244 Dipti typedef struct 57 8244 Dipti { 58 8244 Dipti uint8_t value; 59 8244 Dipti char *data; 60 8244 Dipti } Status_CurrentR; 61 8244 Dipti 62 8244 Dipti Status_CurrentR Status_CurrentR_status[] = { 63 8244 Dipti { 0x00, "OK"}, 64 8244 Dipti { 0x04, "DEEMED FAULTY"}, 65 8244 Dipti { 0x08, "FRU DETECTED"}, 66 8244 Dipti { 0x0c, "FRU DETECTED, DEEMED FAULTY"}, 67 8244 Dipti { 0x10, "PROXIED FAULT"}, 68 8244 Dipti { 0x14, "DEEMED FAULTY. Also PROXIED FAULT"}, 69 8244 Dipti { 0x18, "FRU DETECTED. Also PROXIED FAULT"}, 70 8244 Dipti { 0x1c, "FRU DETECTED, DEEMED FAULTY. Also PROXIED FAULT"}, 71 8244 Dipti { 0x20, "SUSPECT"}, 72 8244 Dipti { 0x24, "SUSPECT, DEEMED FAULTY"}, 73 8244 Dipti { 0x28, "SUSPECT, FRU DETECTED"}, 74 8244 Dipti { 0x2c, "SUSPECT, FRU DETECTED, DEEMED FAULTY"}, 75 8244 Dipti { 0x30, "SUSPECT. Also PROXIED FAULT"}, 76 8244 Dipti { 0x34, "SUSPECT, DEEMED FAULTY. Also PROXIED FAULT"}, 77 8244 Dipti { 0x38, "SUSPECT, FRU DETECTED. Also PROXIED FAULT"}, 78 8244 Dipti { 0x3c, "SUSPECT, FRU DETECTED, DEEMED FAULTY. Also PROXIED FAULT"}, 79 8244 Dipti { 0x40, "MAINTENANCE REQUIRED"}, 80 8244 Dipti { 0x44, "MAINTENANCE REQUIRED, DEEMED FAULTY"}, 81 8244 Dipti { 0x48, "MAINTENANCE REQUIRED, FRU DETECTED"}, 82 8244 Dipti { 0x4c, "MAINTENANCE REQUIRED, FRU DETECTED, DEEMED FAULTY"}, 83 8244 Dipti { 0x50, "MAINTENANCE REQUIRED. Also PROXIED FAULT"}, 84 8244 Dipti { 0x54, "MAINTENANCE REQUIRED, DEEMED FAULTY. Also PROXIED FAULT"}, 85 8244 Dipti { 0x58, "MAINTENANCE REQUIRED, FRU DETECTED. Also PROXIED FAULT"}, 86 8244 Dipti { 0x5c, "MAINTENANCE REQUIRED, FRU DETECTED, DEEMED FAULTY. \ 87 8244 Dipti Also PROXIED FAULT"}, 88 8244 Dipti { 0x60, "MAINTENANCE REQUIRED, SUSPECT"}, 89 8244 Dipti { 0x64, "MAINTENANCE REQUIRED, SUSPECT, DEEMED FAULTY"}, 90 8244 Dipti { 0x68, "MAINTENANCE REQUIRED, SUSPECT, FRU DETECTED"}, 91 8244 Dipti { 0x6c, "MAINTENANCE REQUIRED, SUSPECT, FRU DETECTED, DEEMED FAULTY"}, 92 8244 Dipti { 0x70, "MAINTENANCE REQUIRED, SUSPECT. Also PROXIED FAULT"}, 93 8244 Dipti { 0x74, "MAINTENANCE REQUIRED, SUSPECT, DEEMED FAULTY.\ 94 8244 Dipti Also PROXIED FAULT"}, 95 8244 Dipti { 0x78, "MAINTENANCE REQUIRED, SUSPECT, FRU DETECTED. \ 96 8244 Dipti Also PROXIED FAULT"}, 97 8244 Dipti { 0x7c, "MAINTENANCE REQUIRED, SUSPECT, FRU DETECTED, \ 98 8244 Dipti DEEMED FAULTY. Also PROXIED FAULT"}, 99 8244 Dipti { 0x80, "DISABLED"}, 100 8244 Dipti { 0x84, "DISABLED, DEEMED FAULTY"}, 101 8244 Dipti { 0x88, "DISABLED, FRU DETECTED"}, 102 8244 Dipti { 0x8c, "DISABLED, FRU DETECTED, DEEMED FAULTY"}, 103 8244 Dipti { 0x90, "DISABLED. Also PROXIED FAULT"}, 104 8244 Dipti { 0x94, "DISABLED, DEEMED FAULTY. Also PROXIED FAULT"}, 105 8244 Dipti { 0x98, "DISABLED, FRU DETECTED. Also PROXIED FAULT"}, 106 8244 Dipti { 0x9c, "DISABLED, FRU DETECTED, DEEMED FAULTY. Also PROXIED FAULT"}, 107 8244 Dipti { 0xa0, "DISABLED, SUSPECT"}, 108 8244 Dipti { 0xa4, "DISABLED, SUSPECT, DEEMED FAULTY"}, 109 8244 Dipti { 0xa8, "DISABLED, SUSPECT, FRU DETECTED"}, 110 8244 Dipti { 0xac, "DISABLED, SUSPECT, FRU DETECTED, DEEMED FAULTY"}, 111 8244 Dipti { 0xb0, "DISABLED, SUSPECT. Also PROXIED FAULT"}, 112 8244 Dipti { 0xb4, "DISABLED, SUSPECT, DEEMED FAULTY. Also PROXIED FAULT"}, 113 8244 Dipti { 0xb8, "DISABLED, SUSPECT, FRU DETECTED. Also PROXIED FAULT"}, 114 8244 Dipti { 0xbc, "DISABLED, SUSPECT, FRU DETECTED, \ 115 8244 Dipti DEEMED FAULTY. Also PROXIED FAULT"}, 116 8244 Dipti { 0xc0, "DISABLED, MAINTENANCE REQUIRED"}, 117 8244 Dipti { 0xc4, "DISABLED, MAINTENANCE REQUIRED, DEEMED FAULTY"}, 118 8244 Dipti { 0xc8, "DISABLED, MAINTENANCE REQUIRED, FRU DETECTED"}, 119 8244 Dipti { 0xcc, "DISABLED, MAINTENANCE REQUIRED, FRU DETECTED, DEEMED FAULTY"}, 120 8244 Dipti { 0xd0, "DISABLED, MAINTENANCE REQUIRED. Also PROXIED FAULT"}, 121 8244 Dipti { 0xd4, "DISABLED, MAINTENANCE REQUIRED, \ 122 8244 Dipti DEEMED FAULTY. Also PROXIED FAULT"}, 123 8244 Dipti { 0xd8, "DISABLED, MAINTENANCE REQUIRED, \ 124 8244 Dipti FRU DETECTED. Also PROXIED FAULT"}, 125 8244 Dipti { 0xdc, "DISABLED, MAINTENANCE REQUIRED, FRU DETECTED, \ 126 8244 Dipti DEEMED FAULTY. Also PROXIED FAULT"}, 127 8244 Dipti { 0xe0, "DISABLED, MAINTENANCE REQUIRED, SUSPECT"}, 128 8244 Dipti { 0xe4, "DISABLED, MAINTENANCE REQUIRED, SUSPECT, DEEMED FAULTY"}, 129 8244 Dipti { 0xe8, "DISABLED, MAINTENANCE REQUIRED, SUSPECT, FRU DETECTED"}, 130 8244 Dipti { 0xec, "DISABLED, MAINTENANCE REQUIRED, SUSPECT, \ 131 8244 Dipti FRU DETECTED, DEEMED FAULTY"}, 132 8244 Dipti { 0xf0, "DISABLED, MAINTENANCE REQUIRED, SUSPECT. Also PROXIED FAULT"}, 133 8244 Dipti { 0xf4, "DISABLED, MAINTENANCE REQUIRED, SUSPECT, \ 134 8244 Dipti DEEMED FAULTY. Also PROXIED FAULT"}, 135 8244 Dipti { 0xf8, "DISABLED, MAINTENANCE REQUIRED, SUSPECT, \ 136 8244 Dipti FRU DETECTED. Also PROXIED FAULT"}, 137 8244 Dipti { 0xfc, "DISABLED, MAINTENANCE REQUIRED, SUSPECT, \ 138 8244 Dipti FRU DETECTED, DEEMED FAULTY. Also PROXIED FAULT"}, 139 8244 Dipti { 0xff, "RETIRED"} 140 8244 Dipti }; 141 0 stevel 142 0 stevel static void (*print_node)(fru_node_t fru_type, const char *path, 143 0 stevel const char *name, end_node_fp_t *end_node, 144 0 stevel void **end_args); 145 0 stevel 146 4392 dt207653 static void print_element(const uint8_t *data, const fru_regdef_t *def, 147 4392 dt207653 const char *parent_path, int indent); 148 4392 dt207653 149 0 stevel static char tagname[sizeof ("?_0123456789_0123456789_0123456789")]; 150 0 stevel 151 0 stevel static int containers_only = 0, list_only = 0, saved_status = 0, xml = 0; 152 0 stevel 153 0 stevel static FILE *errlog; 154 0 stevel 155 4392 dt207653 int iterglobal = 0; 156 4392 dt207653 int FMAmessageR = -1; 157 5015 dt207653 int Fault_Install_DataR_flag = 0; 158 5015 dt207653 int Power_On_DataR_flag = 0; 159 5270 dt207653 int spd_memtype = 0; 160 5270 dt207653 int spd_revision = 0; 161 0 stevel /* 162 0 stevel * Definition for data elements found in devices but not found in 163 0 stevel * the system's version of libfrureg 164 0 stevel */ 165 0 stevel static fru_regdef_t unknown = { 166 0 stevel REGDEF_VERSION, 167 0 stevel tagname, 168 0 stevel -1, 169 0 stevel -1, 170 0 stevel -1, 171 0 stevel -1, 172 0 stevel FDTYPE_ByteArray, 173 0 stevel FDISP_Hex, 174 0 stevel FRU_WHICH_UNDEFINED, 175 0 stevel FRU_WHICH_UNDEFINED, 176 0 stevel 0, 177 0 stevel NULL, 178 0 stevel 0, 179 0 stevel FRU_NOT_ITERATED, 180 0 stevel NULL 181 0 stevel }; 182 0 stevel 183 0 stevel 184 0 stevel /* 185 0 stevel * Write message to standard error and possibly the error log buffer 186 0 stevel */ 187 0 stevel static void 188 0 stevel error(const char *format, ...) 189 0 stevel { 190 0 stevel va_list args; 191 0 stevel 192 0 stevel 193 0 stevel /* make relevant output appear before error message */ 194 0 stevel if (fflush(stdout) == EOF) { 195 0 stevel (void) fprintf(stderr, "Error flushing output: %s\n", 196 5015 dt207653 strerror(errno)); 197 0 stevel exit(1); 198 0 stevel } 199 0 stevel 200 0 stevel va_start(args, format); 201 0 stevel if (vfprintf(stderr, format, args) < 0) exit(1); 202 0 stevel if (errlog && (vfprintf(errlog, format, args) < 0)) exit(1); 203 0 stevel } 204 0 stevel 205 0 stevel /* 206 0 stevel * Write message to standard output 207 0 stevel */ 208 0 stevel static void 209 0 stevel output(const char *format, ...) 210 0 stevel { 211 0 stevel va_list args; 212 0 stevel 213 0 stevel 214 0 stevel va_start(args, format); 215 0 stevel if (vfprintf(stdout, format, args) < 0) { 216 0 stevel error(gettext("Error writing output: %s\n"), 217 5015 dt207653 strerror(errno)); 218 0 stevel exit(1); 219 0 stevel } 220 0 stevel } 221 0 stevel 222 0 stevel /* 223 0 stevel * Safe wrapper for putchar() 224 0 stevel */ 225 0 stevel static void 226 0 stevel voidputchar(int c) 227 0 stevel { 228 0 stevel if (putchar(c) == EOF) { 229 0 stevel error(gettext("Error writing output: %s\n"), 230 5015 dt207653 strerror(errno)); 231 0 stevel exit(1); 232 0 stevel } 233 0 stevel } 234 0 stevel 235 0 stevel static void (*safeputchar)(int c) = voidputchar; 236 0 stevel 237 0 stevel /* 238 0 stevel * Safe wrapper for puts() 239 0 stevel */ 240 0 stevel static void 241 0 stevel voidputs(const char *s) 242 0 stevel { 243 0 stevel if (fputs(s, stdout) == EOF) { 244 0 stevel error(gettext("Error writing output: %s\n"), 245 5015 dt207653 strerror(errno)); 246 0 stevel exit(1); 247 0 stevel } 248 0 stevel } 249 0 stevel 250 0 stevel static void (*safeputs)(const char *s) = voidputs; 251 0 stevel 252 0 stevel /* 253 0 stevel * XML-safe wrapper for putchar(): quotes XML-special characters 254 0 stevel */ 255 0 stevel static void 256 0 stevel xputchar(int c) 257 0 stevel { 258 0 stevel switch (c) { 259 0 stevel case '<': 260 0 stevel c = fputs("<", stdout); 261 0 stevel break; 262 0 stevel case '>': 263 0 stevel c = fputs(">", stdout); 264 0 stevel break; 265 0 stevel case '&': 266 0 stevel c = fputs("&", stdout); 267 0 stevel break; 268 0 stevel case '"': 269 0 stevel c = fputs(""", stdout); 270 0 stevel break; 271 0 stevel default: 272 0 stevel c = putchar(c); 273 0 stevel break; 274 0 stevel } 275 0 stevel 276 0 stevel if (c == EOF) { 277 0 stevel error(gettext("Error writing output: %s\n"), 278 5015 dt207653 strerror(errno)); 279 0 stevel exit(1); 280 0 stevel } 281 0 stevel } 282 0 stevel 283 0 stevel /* 284 0 stevel * XML-safe analog of puts(): quotes XML-special characters 285 0 stevel */ 286 0 stevel static void 287 0 stevel xputs(const char *s) 288 0 stevel { 289 0 stevel char c; 290 0 stevel 291 0 stevel for (/* */; ((c = *s) != 0); s++) 292 0 stevel xputchar(c); 293 0 stevel } 294 0 stevel 295 0 stevel /* 296 0 stevel * Output the XML DTD derived from the registry provided by libfrureg 297 0 stevel */ 298 0 stevel int 299 0 stevel output_dtd(void) 300 0 stevel { 301 0 stevel char **element; 302 0 stevel 303 0 stevel unsigned int i, j, num_elements = 0; 304 0 stevel 305 0 stevel uint8_t *tagged; 306 0 stevel 307 0 stevel const fru_regdef_t *def; 308 0 stevel 309 0 stevel 310 0 stevel if (((element = fru_reg_list_entries(&num_elements)) == NULL) || 311 0 stevel (num_elements == 0)) { 312 0 stevel error(gettext("No FRU ID Registry elements")); 313 0 stevel return (1); 314 0 stevel } 315 0 stevel 316 0 stevel if ((tagged = calloc(num_elements, sizeof (*tagged))) == NULL) { 317 0 stevel error(gettext("Unable to get memory for tagged element list"), 318 5015 dt207653 strerror(errno)); 319 0 stevel return (1); 320 0 stevel } 321 0 stevel 322 0 stevel /* 323 0 stevel * Output the DTD preamble 324 0 stevel */ 325 0 stevel output("<!ELEMENT FRUID_XML_Tree (Parameter*, " 326 0 stevel "(Fru | Location | Container)*,\n" 327 0 stevel " Parameter*, ErrorLog?, Parameter*)>\n" 328 0 stevel "<!ATTLIST FRUID_XML_Tree>\n" 329 0 stevel "\n" 330 0 stevel "<!ELEMENT Parameter EMPTY>\n" 331 0 stevel "<!ATTLIST Parameter type CDATA #REQUIRED>\n" 332 0 stevel "<!ATTLIST Parameter name CDATA #REQUIRED>\n" 333 0 stevel "<!ATTLIST Parameter value CDATA #REQUIRED>\n" 334 0 stevel "\n" 335 0 stevel "<!ELEMENT Fru (Fru | Location | Container)*>\n" 336 0 stevel "<!ATTLIST Fru name CDATA #REQUIRED>\n" 337 0 stevel "\n" 338 0 stevel "<!ELEMENT Location (Fru | Location | Container)*>\n" 339 1699 ps154918 "<!ATTLIST Location\n" 340 1699 ps154918 " name CDATA #IMPLIED\n" 341 1699 ps154918 " value CDATA #IMPLIED\n" 342 1699 ps154918 ">\n" 343 0 stevel "\n" 344 0 stevel "<!ELEMENT Container (ContainerData?, " 345 0 stevel "(Fru | Location | Container)*)>\n" 346 0 stevel "<!ATTLIST Container name CDATA #REQUIRED>\n" 347 0 stevel "<!ATTLIST Container imagefile CDATA #IMPLIED>\n" 348 0 stevel "\n" 349 0 stevel "<!ELEMENT ContainerData (Segment*)>\n" 350 0 stevel "<!ATTLIST ContainerData>\n" 351 0 stevel "\n" 352 0 stevel "<!ATTLIST Segment name CDATA #REQUIRED>\n" 353 0 stevel "\n" 354 0 stevel "<!ELEMENT Index EMPTY>\n" 355 0 stevel "<!ATTLIST Index value CDATA #REQUIRED>\n" 356 0 stevel "\n" 357 0 stevel "<!ELEMENT ErrorLog (#PCDATA)>\n" 358 0 stevel "<!ATTLIST ErrorLog>\n" 359 0 stevel "\n"); 360 0 stevel 361 0 stevel /* 362 0 stevel * Output the definition for each element 363 0 stevel */ 364 0 stevel for (i = 0; i < num_elements; i++) { 365 0 stevel assert(element[i] != NULL); 366 1699 ps154918 /* Prevent incompatible duplicate defn. from FRUID Registry. */ 367 1699 ps154918 if ((strcmp("Location", element[i])) == 0) continue; 368 0 stevel if ((def = fru_reg_lookup_def_by_name(element[i])) == NULL) { 369 0 stevel error(gettext("Error looking up registry " 370 5015 dt207653 "definition for \"%s\"\n"), 371 5015 dt207653 element[i]); 372 0 stevel return (1); 373 0 stevel } 374 0 stevel 375 0 stevel if (def->tagType != FRU_X) tagged[i] = 1; 376 0 stevel 377 0 stevel if (def->dataType == FDTYPE_Record) { 378 0 stevel if (def->iterationType == FRU_NOT_ITERATED) 379 0 stevel output("<!ELEMENT %s (%s", element[i], 380 0 stevel def->enumTable[0].text); 381 0 stevel else 382 0 stevel output("<!ELEMENT %s (Index_%s*)>\n" 383 0 stevel "<!ATTLIST Index_%s>\n" 384 0 stevel "<!ELEMENT Index_%s (%s", 385 0 stevel element[i], element[i], element[i], 386 0 stevel element[i], def->enumTable[0].text); 387 0 stevel 388 0 stevel for (j = 1; j < def->enumCount; j++) 389 0 stevel output(",\n\t%s", def->enumTable[j].text); 390 0 stevel 391 0 stevel output(")>\n"); 392 0 stevel } else if (def->iterationType == FRU_NOT_ITERATED) { 393 0 stevel output("<!ELEMENT %s EMPTY>\n" 394 0 stevel "<!ATTLIST %s value CDATA #REQUIRED>\n", 395 0 stevel element[i], element[i]); 396 0 stevel 397 0 stevel if (def->dataType == FDTYPE_Enumeration) { 398 0 stevel output("<!-- %s valid enumeration values\n"); 399 0 stevel for (j = 0; j < def->enumCount; j++) { 400 0 stevel output("\t\""); 401 0 stevel xputs(def->enumTable[j].text); 402 0 stevel output("\"\n"); 403 0 stevel } 404 0 stevel output("-->\n"); 405 0 stevel } 406 0 stevel } 407 0 stevel else 408 0 stevel output("<!ELEMENT %s (Index*)>\n", element[i]); 409 0 stevel 410 0 stevel output("\n"); 411 0 stevel } 412 0 stevel 413 0 stevel /* Provide for returning the tag for an "unknown" element */ 414 0 stevel output("<!ATTLIST UNKNOWN tag CDATA \"UNKNOWN\">\n\n"); 415 0 stevel 416 0 stevel 417 0 stevel /* 418 0 stevel * List all data elements as possible members of "Segment" 419 0 stevel */ 420 0 stevel output("<!ELEMENT Segment ((UNKNOWN"); 421 0 stevel for (i = 0; i < num_elements; i++) { 422 0 stevel if (tagged[i]) output("\n\t| %s", element[i]); 423 0 stevel free(element[i]); 424 0 stevel } 425 0 stevel output(")*)>\n"); 426 0 stevel free(element); 427 0 stevel free(tagged); 428 0 stevel 429 0 stevel return (0); 430 0 stevel } 431 4392 dt207653 /* 432 4392 dt207653 * Function to convert bcd to binary to correct the SPD_Manufacturer_Week 433 4392 dt207653 * 434 4392 dt207653 */ 435 4392 dt207653 static void convertbcdtobinary(int *val) 436 4392 dt207653 { 437 5270 dt207653 unsigned int newval = (unsigned int)*val, tmpval = 0; 438 5270 dt207653 while (newval > 0) { 439 5270 dt207653 tmpval = (tmpval << 4) | (newval & 0xF); 440 5270 dt207653 newval >>= 4; 441 5270 dt207653 } 442 5270 dt207653 while (tmpval > 0) { 443 5270 dt207653 newval = (newval * 10) + (tmpval & 0xF); 444 5270 dt207653 tmpval >>= 4; 445 4392 dt207653 } 446 4392 dt207653 *val = newval; 447 4392 dt207653 } 448 4392 dt207653 449 8244 Dipti /* 450 8244 Dipti * Checking UTF-8 printable charecter 451 8244 Dipti */ 452 8244 Dipti static int check_utf_char(const uint8_t *field, int len) 453 8244 Dipti { 454 8244 Dipti int i, status = 0; 455 8244 Dipti char tmp[128], tmp1[128], tmp2[128]; 456 8244 Dipti (void) sprintf(tmp, " (Invalid Data"); 457 8244 Dipti (void) sprintf(tmp2, "0x"); 458 8244 Dipti for (i = 0; i < len && field[i]; i++) { 459 8244 Dipti (void) sprintf(tmp1, "%2.2X", field[i]); 460 8244 Dipti (void) strcat(tmp2, tmp1); 461 8244 Dipti if (iswprint(field[i]) == 0) { 462 8244 Dipti status = 1; 463 8244 Dipti (void) sprintf(tmp1, " : 0x%2.2X", field[i]); 464 8244 Dipti (void) strcat(tmp, tmp1); 465 8244 Dipti } 466 8244 Dipti } 467 8244 Dipti if (status) { 468 8244 Dipti (void) sprintf(tmp1, ")"); 469 8244 Dipti (void) strcat(tmp, tmp1); 470 8244 Dipti (void) strcat(tmp2, tmp); 471 8244 Dipti output("%s", tmp2); 472 8244 Dipti } 473 8244 Dipti return (status); 474 8244 Dipti } 475 0 stevel 476 0 stevel /* 477 0 stevel * Safely pretty-print the value of a field 478 0 stevel */ 479 0 stevel static void 480 0 stevel print_field(const uint8_t *field, const fru_regdef_t *def) 481 0 stevel { 482 4392 dt207653 char *errmsg = NULL, timestring[TIMESTRINGLEN], path[16384]; 483 0 stevel 484 4392 dt207653 int i, valueint; 485 0 stevel 486 0 stevel uint64_t value; 487 0 stevel 488 0 stevel time_t timefield; 489 0 stevel 490 4392 dt207653 struct tm *tm; 491 0 stevel 492 4392 dt207653 uchar_t first_byte, data[128]; 493 4392 dt207653 494 4392 dt207653 const fru_regdef_t *new_def; 495 4392 dt207653 496 4392 dt207653 const char *elem_name = NULL; 497 4392 dt207653 const char *parent_path; 498 0 stevel switch (def->dataType) { 499 0 stevel case FDTYPE_Binary: 500 0 stevel assert(def->payloadLen <= sizeof (value)); 501 0 stevel switch (def->dispType) { 502 0 stevel case FDISP_Binary: 503 0 stevel for (i = 0; i < def->payloadLen; i++) 504 0 stevel output("%c%c%c%c%c%c%c%c", 505 0 stevel ((field[i] & 0x80) ? '1' : '0'), 506 0 stevel ((field[i] & 0x40) ? '1' : '0'), 507 0 stevel ((field[i] & 0x20) ? '1' : '0'), 508 0 stevel ((field[i] & 0x10) ? '1' : '0'), 509 0 stevel ((field[i] & 0x08) ? '1' : '0'), 510 0 stevel ((field[i] & 0x04) ? '1' : '0'), 511 0 stevel ((field[i] & 0x02) ? '1' : '0'), 512 0 stevel ((field[i] & 0x01) ? '1' : '0')); 513 0 stevel return; 514 0 stevel case FDISP_Octal: 515 0 stevel case FDISP_Decimal: 516 0 stevel value = 0; 517 4392 dt207653 valueint = 0; 518 0 stevel (void) memcpy((((uint8_t *)&value) + 519 5015 dt207653 sizeof (value) - def->payloadLen), 520 5015 dt207653 field, def->payloadLen); 521 4392 dt207653 if ((value != 0) && 522 5015 dt207653 (strcmp(def->name, "SPD_Manufacture_Week") == 0)) { 523 4392 dt207653 valueint = (int)value; 524 5270 dt207653 if (spd_memtype && spd_revision) { 525 5270 dt207653 convertbcdtobinary(&valueint); 526 5270 dt207653 spd_memtype = 0; 527 5270 dt207653 spd_revision = 0; 528 5270 dt207653 } 529 4392 dt207653 output("%d", valueint); 530 4392 dt207653 return; 531 4392 dt207653 } 532 1699 ps154918 if ((value != 0) && 533 5015 dt207653 ((strcmp(def->name, "Lowest") == 0) || 534 5015 dt207653 (strcmp(def->name, "Highest") == 0) || 535 5015 dt207653 (strcmp(def->name, "Latest") == 0))) 536 1944 ps154918 output((def->dispType == FDISP_Octal) ? 537 1944 ps154918 "%llo" : "%lld (%lld degrees C)", 538 5015 dt207653 value, (value - TEMPERATURE_OFFSET)); 539 1944 ps154918 else 540 1944 ps154918 output((def->dispType == FDISP_Octal) ? 541 0 stevel "%llo" : "%lld", value); 542 0 stevel return; 543 0 stevel case FDISP_Time: 544 0 stevel if (def->payloadLen > sizeof (timefield)) { 545 0 stevel errmsg = "time value too large for formatting"; 546 0 stevel break; 547 0 stevel } 548 4392 dt207653 timefield = 0; 549 4392 dt207653 (void) memcpy((((uint8_t *)&timefield) + 550 5015 dt207653 sizeof (timefield) - def->payloadLen), 551 5015 dt207653 field, def->payloadLen); 552 4392 dt207653 if (timefield == 0) { 553 4392 dt207653 errmsg = "No Value Recorded"; 554 4392 dt207653 break; 555 4392 dt207653 } 556 7247 aa222140 if ((tm = gmtime(&timefield)) == NULL) { 557 4392 dt207653 errmsg = "cannot convert time value"; 558 4392 dt207653 break; 559 4392 dt207653 } 560 7247 aa222140 if (strftime(timestring, sizeof (timestring), GMT, tm) 561 4392 dt207653 == 0) { 562 0 stevel errmsg = "formatted time would overflow buffer"; 563 0 stevel break; 564 0 stevel } 565 0 stevel safeputs(timestring); 566 0 stevel return; 567 0 stevel } 568 0 stevel break; 569 0 stevel case FDTYPE_ASCII: 570 4392 dt207653 if (!xml) { 571 4392 dt207653 if (strcmp(def->name, "Message") == 0) { 572 4392 dt207653 if (FMAmessageR == 0) 573 4392 dt207653 elem_name = "FMA_Event_DataR"; 574 4392 dt207653 else if (FMAmessageR == 1) 575 4392 dt207653 elem_name = "FMA_MessageR"; 576 4392 dt207653 if (elem_name != NULL) { 577 4392 dt207653 (void) memcpy(data, field, 578 5015 dt207653 def->payloadLen); 579 4392 dt207653 new_def = 580 5015 dt207653 fru_reg_lookup_def_by_name 581 5015 dt207653 (elem_name); 582 4402 dt207653 (void) snprintf(path, sizeof (path), 583 4392 dt207653 "/Status_EventsR[%d]/Message(FMA)", 584 5015 dt207653 iterglobal); 585 4392 dt207653 parent_path = path; 586 4392 dt207653 output("\n"); 587 4392 dt207653 print_element(data, new_def, 588 5015 dt207653 parent_path, 2*INDENT); 589 4392 dt207653 return; 590 4392 dt207653 } 591 4392 dt207653 } 592 4392 dt207653 } 593 8244 Dipti if (strcmp(def->name, "Fru_Path") == 0) { 594 8244 Dipti if (check_utf_char(field, def->payloadLen) == 1) 595 8244 Dipti return; 596 8244 Dipti } 597 0 stevel for (i = 0; i < def->payloadLen && field[i]; i++) 598 0 stevel safeputchar(field[i]); 599 0 stevel return; 600 0 stevel case FDTYPE_Enumeration: 601 0 stevel value = 0; 602 0 stevel (void) memcpy((((uint8_t *)&value) + sizeof (value) 603 5015 dt207653 - def->payloadLen), 604 5015 dt207653 field, def->payloadLen); 605 0 stevel for (i = 0; i < def->enumCount; i++) 606 0 stevel if (def->enumTable[i].value == value) { 607 4392 dt207653 if (strcmp(def->name, "Event_Code") == 0) { 608 4392 dt207653 if (strcmp(def->enumTable[i].text, 609 4392 dt207653 "FMA Message R") == 0) 610 4392 dt207653 FMAmessageR = 1; 611 4392 dt207653 else 612 4392 dt207653 if (strcmp(def->enumTable[i].text, 613 4392 dt207653 "FMA Event Data R") == 0) 614 4392 dt207653 FMAmessageR = 0; 615 4392 dt207653 } 616 5270 dt207653 if (strcmp(def->name, 617 5270 dt207653 "SPD_Fundamental_Memory_Type") == 0) { 618 5270 dt207653 if (strcmp(def->enumTable[i].text, 619 5270 dt207653 "DDR II SDRAM") == 0) 620 5270 dt207653 spd_memtype = 1; 621 5270 dt207653 } 622 0 stevel safeputs(def->enumTable[i].text); 623 0 stevel return; 624 0 stevel } 625 0 stevel 626 0 stevel errmsg = "unrecognized value"; 627 0 stevel break; 628 0 stevel } 629 0 stevel 630 0 stevel /* If nothing matched above, print the field in hex */ 631 4392 dt207653 switch (def->dispType) { 632 4392 dt207653 case FDISP_MSGID: 633 4392 dt207653 (void) memcpy((uchar_t *)&first_byte, field, 1); 634 4392 dt207653 if (isprint(first_byte)) { 635 4392 dt207653 for (i = 0; i < def->payloadLen && field[i]; 636 5015 dt207653 i++) 637 4392 dt207653 safeputchar(field[i]); 638 4392 dt207653 } 639 4392 dt207653 break; 640 4392 dt207653 case FDISP_UUID: 641 4392 dt207653 for (i = 0; i < def->payloadLen; i++) { 642 4392 dt207653 if ((i == 4) || (i == 6) || 643 5015 dt207653 (i == 8) || (i == 10)) 644 4392 dt207653 output("-"); 645 4392 dt207653 output("%2.2x", field[i]); 646 4392 dt207653 } 647 4392 dt207653 break; 648 4392 dt207653 default: 649 8244 Dipti if ((strcmp(def->name, "Status") == 0) || 650 8244 Dipti (strcmp(def->name, "Old_Status") == 0) || 651 8244 Dipti (strcmp(def->name, "New_Status") == 0)) { 652 8244 Dipti int status_length = \ 653 8244 Dipti sizeof (Status_CurrentR_status) / \ 654 8244 Dipti sizeof (*(Status_CurrentR_status)); 655 8244 Dipti i = 0; 656 8244 Dipti do { 657 8244 Dipti if (Status_CurrentR_status[i].value == \ 658 8244 Dipti *(field)) 659 8244 Dipti break; 660 8244 Dipti i++; 661 8244 Dipti } while (i < status_length); 662 8244 Dipti if (i < status_length) 663 8244 Dipti output("0x%2.2X (%s)", *(field), 664 8244 Dipti Status_CurrentR_status[i].data); 665 8244 Dipti else 666 8244 Dipti output("0x%2.2X (UNKNOWN)", *(field)); 667 8244 Dipti break; 668 8244 Dipti } 669 5270 dt207653 if (strcmp(def->name, 670 5270 dt207653 "SPD_Data_Revision_Code") == 0) { 671 5270 dt207653 value = 0; 672 5270 dt207653 valueint = 0; 673 5270 dt207653 (void) memcpy((((uint8_t *)&value) 674 5270 dt207653 + sizeof (value) - def->payloadLen), 675 5270 dt207653 field, def->payloadLen); 676 5270 dt207653 valueint = (int)value; 677 5270 dt207653 if ((valueint >= MIN_VERSION) && (spd_memtype)) 678 5270 dt207653 spd_revision = 1; 679 5270 dt207653 } 680 4392 dt207653 for (i = 0; i < def->payloadLen; i++) 681 4392 dt207653 output("%2.2X", field[i]); 682 4392 dt207653 break; 683 4392 dt207653 } 684 0 stevel 685 0 stevel /* Safely print any error message associated with the field */ 686 0 stevel if (errmsg) { 687 4392 dt207653 if (strcmp(def->name, "Fault_Diag_Secs") != 0) { 688 4392 dt207653 output(" ("); 689 4392 dt207653 safeputs(errmsg); 690 4392 dt207653 output(")"); 691 4392 dt207653 } 692 0 stevel } 693 0 stevel } 694 0 stevel 695 0 stevel /* 696 0 stevel * Recursively print the contents of a data element 697 0 stevel */ 698 0 stevel static void 699 0 stevel print_element(const uint8_t *data, const fru_regdef_t *def, 700 0 stevel const char *parent_path, int indent) 701 0 stevel { 702 0 stevel char *path; 703 0 stevel size_t len; 704 0 stevel 705 0 stevel int bytes = 0, i; 706 0 stevel 707 0 stevel 708 0 stevel indent = (xml) ? (indent + INDENT) : (2*INDENT); 709 5015 dt207653 if (strcmp(def->name, "Sun_SPD_DataR") == 0) { 710 5015 dt207653 Fault_Install_DataR_flag = indent; 711 5015 dt207653 Power_On_DataR_flag = indent; 712 5015 dt207653 } 713 0 stevel /* 714 0 stevel * Construct the path, or, for XML, the name, for the current 715 0 stevel * data element 716 0 stevel */ 717 0 stevel if ((def->iterationCount == 0) && 718 0 stevel (def->iterationType != FRU_NOT_ITERATED)) { 719 0 stevel if (xml) { 720 0 stevel if (def->dataType == FDTYPE_Record) { 721 0 stevel len = strlen("Index_") + strlen(def->name) + 1; 722 0 stevel path = alloca(len); 723 0 stevel (void) snprintf(path, len, 724 0 stevel "Index_%s", def->name); 725 0 stevel } 726 0 stevel else 727 0 stevel path = "Index"; 728 0 stevel } 729 0 stevel else 730 0 stevel path = (char *)parent_path; 731 0 stevel } else { 732 0 stevel if (xml) 733 0 stevel path = (char *)def->name; 734 0 stevel else { 735 0 stevel len = strlen(parent_path) + sizeof ("/") + 736 0 stevel strlen(def->name) + 737 0 stevel (def->iterationCount ? sizeof ("[255]") : 0); 738 0 stevel path = alloca(len); 739 0 stevel bytes = snprintf(path, len, 740 0 stevel "%s/%s", parent_path, def->name); 741 0 stevel } 742 0 stevel } 743 0 stevel 744 5015 dt207653 if ((Fault_Install_DataR_flag) && 745 5015 dt207653 (strcmp(path, "E_1_46") == 0) || (strcmp(path, "/E_1_46") == 0)) { 746 5015 dt207653 int cnt; 747 5015 dt207653 char timestring[128]; 748 5015 dt207653 time_t timefield = 0; 749 5015 dt207653 struct tm *tm; 750 5015 dt207653 indent = Fault_Install_DataR_flag; 751 5015 dt207653 (void) memcpy((uint8_t *)&timefield, data, 4); 752 5015 dt207653 if (timefield == 0) { 753 5015 dt207653 (void) sprintf(timestring, 754 5015 dt207653 "00000000 (No Value Recorded)\""); 755 5015 dt207653 } else { 756 7247 aa222140 if ((tm = gmtime(&timefield)) == NULL) 757 5015 dt207653 (void) sprintf(timestring, 758 5015 dt207653 "cannot convert time value"); 759 5015 dt207653 if (strftime(timestring, 760 7247 aa222140 sizeof (timestring), GMT, tm) == 0) 761 5015 dt207653 (void) sprintf(timestring, 762 5015 dt207653 "formatted time would overflow buffer"); 763 5015 dt207653 } 764 5015 dt207653 if (xml) { 765 5015 dt207653 (void) sprintf(path, "Fault_Install_DataR"); 766 5015 dt207653 output("%*s<%s>\n", indent, "", path); 767 5015 dt207653 indent = Fault_Install_DataR_flag + INDENT; 768 5015 dt207653 (void) sprintf(path, "UNIX_Timestamp32"); 769 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 770 5015 dt207653 /*CSTYLED*/ 771 5015 dt207653 output("%s\"/>\n", timestring); 772 5015 dt207653 (void) sprintf(path, "MACADDR"); 773 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 774 5015 dt207653 for (cnt = 4; cnt < 4 + 6; cnt++) { 775 5015 dt207653 output("%2.2x", data[cnt]); 776 5015 dt207653 if (cnt < 4 + 6 - 1) 777 5015 dt207653 output(":"); 778 5015 dt207653 } 779 5015 dt207653 /*CSTYLED*/ 780 5015 dt207653 output("\"/>\n"); 781 5015 dt207653 (void) sprintf(path, "Status"); 782 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 783 5015 dt207653 /*CSTYLED*/ 784 5015 dt207653 output("%2.2x\"/>\n", data[10]); 785 5015 dt207653 (void) sprintf(path, "Initiator"); 786 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 787 5015 dt207653 /*CSTYLED*/ 788 5015 dt207653 output("%2.2x\"/>\n", data[11]); 789 5015 dt207653 (void) sprintf(path, "Message_Type"); 790 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 791 5015 dt207653 /*CSTYLED*/ 792 5015 dt207653 output("%2.2x\"/>\n", data[12]); 793 5015 dt207653 (void) sprintf(path, "Message_32"); 794 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 795 5015 dt207653 for (cnt = 13; cnt < 13 + 32; cnt++) 796 5015 dt207653 output("%2.2x", data[cnt]); 797 5015 dt207653 /*CSTYLED*/ 798 5015 dt207653 output("\"/>\n"); 799 5015 dt207653 indent = Fault_Install_DataR_flag; 800 5015 dt207653 (void) sprintf(path, "Fault_Install_DataR"); 801 5015 dt207653 output("%*s</%s>\n", indent, "", path); 802 5015 dt207653 } else { 803 5015 dt207653 (void) sprintf(path, "/Fault_Install_DataR"); 804 5015 dt207653 output("%*s%s\n", indent, "", path); 805 5015 dt207653 (void) sprintf(path, 806 5015 dt207653 "/Fault_Install_DataR/UNIX_Timestamp32"); 807 5015 dt207653 output("%*s%s: ", indent, "", path); 808 5015 dt207653 output("%s\n", timestring); 809 5015 dt207653 (void) sprintf(path, "/Fault_Install_DataR/MACADDR"); 810 5015 dt207653 output("%*s%s: ", indent, "", path); 811 5015 dt207653 for (cnt = 4; cnt < 4 + 6; cnt++) { 812 5015 dt207653 output("%2.2x", data[cnt]); 813 5015 dt207653 if (cnt < 4 + 6 - 1) 814 5015 dt207653 output(":"); 815 5015 dt207653 } 816 5015 dt207653 output("\n"); 817 5015 dt207653 (void) sprintf(path, "/Fault_Install_DataR/Status"); 818 5015 dt207653 output("%*s%s: ", indent, "", path); 819 5015 dt207653 output("%2.2x\n", data[10]); 820 5015 dt207653 (void) sprintf(path, "/Fault_Install_DataR/Initiator"); 821 5015 dt207653 output("%*s%s: ", indent, "", path); 822 5015 dt207653 output("%2.2x\n", data[11]); 823 5015 dt207653 (void) sprintf(path, 824 5015 dt207653 "/Fault_Install_DataR/Message_Type"); 825 5015 dt207653 output("%*s%s: ", indent, "", path); 826 5015 dt207653 output("%2.2x\n", data[12]); 827 5015 dt207653 (void) sprintf(path, "/Fault_Install_DataR/Message_32"); 828 5015 dt207653 output("%*s%s: ", indent, "", path); 829 5015 dt207653 for (cnt = 13; cnt < 13 + 32; cnt++) 830 5015 dt207653 output("%2.2x", data[cnt]); 831 5015 dt207653 output("\n"); 832 5015 dt207653 } 833 5015 dt207653 Fault_Install_DataR_flag = 0; 834 5015 dt207653 return; 835 5015 dt207653 } else if ((Power_On_DataR_flag) && ( 836 5015 dt207653 strcmp(path, "C_10_8") == 0 || 837 5015 dt207653 (strcmp(path, "/C_10_8") == 0))) { 838 5015 dt207653 int cnt; 839 5015 dt207653 char timestring[128]; 840 5015 dt207653 time_t timefield = 0; 841 5015 dt207653 struct tm *tm; 842 5015 dt207653 indent = Power_On_DataR_flag; 843 5015 dt207653 (void) memcpy((uint8_t *)&timefield, data, 4); 844 5015 dt207653 if (timefield == 0) { 845 5015 dt207653 (void) sprintf(timestring, 846 5015 dt207653 "00000000 (No Value Recorded)"); 847 5015 dt207653 } else { 848 7247 aa222140 if ((tm = gmtime(&timefield)) == NULL) 849 5015 dt207653 (void) sprintf(timestring, 850 5015 dt207653 "cannot convert time value"); 851 5015 dt207653 if (strftime(timestring, 852 7247 aa222140 sizeof (timestring), GMT, tm) == 0) 853 5015 dt207653 (void) sprintf(timestring, 854 5015 dt207653 "formatted time would overflow buffer"); 855 5015 dt207653 } 856 5015 dt207653 if (xml) { 857 5015 dt207653 (void) sprintf(path, "Power_On_DataR"); 858 5015 dt207653 output("%*s<%s>\n", indent, "", path); 859 5015 dt207653 indent = Power_On_DataR_flag + INDENT; 860 5015 dt207653 (void) sprintf(path, "UNIX_Timestamp32"); 861 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 862 5015 dt207653 /*CSTYLED*/ 863 5015 dt207653 output("%s\"/>\n", timestring); 864 5015 dt207653 (void) sprintf(path, "Power_On_Minutes"); 865 5015 dt207653 output("%*s<%s value=\"", indent, "", path); 866 5015 dt207653 for (cnt = 4; cnt < 4 + 4; cnt++) 867 5015 dt207653 output("%2.2x", data[cnt]); 868 5015 dt207653 /*CSTYLED*/ 869 5015 dt207653 output("\"/>\n"); 870 5015 dt207653 indent = Power_On_DataR_flag; 871 5015 dt207653 (void) sprintf(path, "Power_On_DataR"); 872 5015 dt207653 output("%*s</%s>\n", indent, "", path); 873 5015 dt207653 } else { 874 5015 dt207653 (void) sprintf(path, "/Power_On_DataR"); 875 5015 dt207653 output("%*s%s\n", indent, "", path); 876 5015 dt207653 (void) sprintf(path, 877 5015 dt207653 "/Power_On_DataR/UNIX_Timestamp32"); 878 5015 dt207653 output("%*s%s: ", indent, "", path); 879 5015 dt207653 output("%s\n", timestring); 880 5015 dt207653 (void) sprintf(path, 881 5015 dt207653 "/Power_On_DataR/Power_On_Minutes"); 882 5015 dt207653 output("%*s%s: ", indent, "", path); 883 5015 dt207653 for (cnt = 4; cnt < 4 + 4; cnt++) 884 5015 dt207653 output("%2.2x", data[cnt]); 885 5015 dt207653 output("\n"); 886 5015 dt207653 } 887 5015 dt207653 Power_On_DataR_flag = 0; 888 5015 dt207653 return; 889 5015 dt207653 } 890 0 stevel /* 891 0 stevel * Handle the various categories of data elements: iteration, 892 0 stevel * record, and field 893 0 stevel */ 894 0 stevel if (def->iterationCount) { 895 0 stevel int iterlen = (def->payloadLen - NUM_ITER_BYTES)/ 896 5015 dt207653 def->iterationCount, 897 5015 dt207653 n, valid = 1; 898 0 stevel 899 0 stevel uint8_t head, num; 900 0 stevel 901 0 stevel fru_regdef_t newdef; 902 0 stevel 903 0 stevel 904 0 stevel /* 905 0 stevel * Make a new element definition to describe the components 906 0 stevel * of the iteration 907 0 stevel */ 908 0 stevel (void) memcpy(&newdef, def, sizeof (newdef)); 909 0 stevel newdef.iterationCount = 0; 910 0 stevel newdef.payloadLen = iterlen; 911 0 stevel 912 0 stevel /* 913 0 stevel * Validate the contents of the iteration control bytes 914 0 stevel */ 915 0 stevel if (data[HEAD_ITER] >= def->iterationCount) { 916 0 stevel valid = 0; 917 0 stevel error(gettext("%s: Invalid iteration head: %d " 918 0 stevel "(should be less than %d)\n"), 919 0 stevel path, data[HEAD_ITER], def->iterationCount); 920 0 stevel } 921 0 stevel 922 0 stevel if (data[NUM_ITER] > def->iterationCount) { 923 0 stevel valid = 0; 924 0 stevel error(gettext("%s: Invalid iteration count: %d " 925 0 stevel "(should not be greater than %d)\n"), 926 0 stevel path, data[NUM_ITER], def->iterationCount); 927 0 stevel } 928 0 stevel 929 0 stevel if (data[MAX_ITER] != def->iterationCount) { 930 0 stevel valid = 0; 931 0 stevel error(gettext("%s: Invalid iteration maximum: %d " 932 0 stevel "(should equal %d)\n"), 933 0 stevel path, data[MAX_ITER], def->iterationCount); 934 0 stevel } 935 0 stevel 936 0 stevel if (valid) { 937 0 stevel head = data[HEAD_ITER]; 938 0 stevel num = data[NUM_ITER]; 939 0 stevel } else { 940 0 stevel head = 0; 941 0 stevel num = def->iterationCount; 942 0 stevel error(gettext("%s: Showing all iterations\n"), path); 943 0 stevel } 944 0 stevel 945 0 stevel if (xml) 946 0 stevel output("%*s<%s>\n", indent, "", path); 947 0 stevel else 948 0 stevel output("%*s%s (%d iterations)\n", indent, "", path, 949 5015 dt207653 num); 950 0 stevel 951 0 stevel /* 952 0 stevel * Print each component of the iteration 953 0 stevel */ 954 0 stevel for (i = head, n = 0, data += 4; 955 5015 dt207653 n < num; 956 5015 dt207653 i = ((i + 1) % def->iterationCount), n++) { 957 0 stevel if (!xml) (void) sprintf((path + bytes), "[%d]", n); 958 4392 dt207653 iterglobal = n; 959 0 stevel print_element((data + i*iterlen), &newdef, path, 960 5015 dt207653 indent); 961 0 stevel } 962 0 stevel 963 0 stevel if (xml) output("%*s</%s>\n", indent, "", path); 964 0 stevel 965 0 stevel } else if (def->dataType == FDTYPE_Record) { 966 0 stevel const fru_regdef_t *component; 967 0 stevel 968 0 stevel if (xml) 969 0 stevel output("%*s<%s>\n", indent, "", path); 970 0 stevel else 971 0 stevel output("%*s%s\n", indent, "", path); 972 0 stevel 973 0 stevel /* 974 0 stevel * Print each component of the record 975 0 stevel */ 976 0 stevel for (i = 0; i < def->enumCount; 977 5015 dt207653 i++, data += component->payloadLen) { 978 0 stevel component = fru_reg_lookup_def_by_name( 979 5015 dt207653 def->enumTable[i].text); 980 0 stevel assert(component != NULL); 981 0 stevel print_element(data, component, path, indent); 982 0 stevel } 983 0 stevel 984 0 stevel if (xml) output("%*s</%s>\n", indent, "", path); 985 0 stevel } else if (xml) { 986 0 stevel /* 987 0 stevel * Base case: print the field formatted for XML 988 0 stevel */ 989 0 stevel char *format = ((def == &unknown) 990 0 stevel ? "%*s<UNKNOWN tag=\"%s\" value=\"" 991 0 stevel : "%*s<%s value=\""); 992 0 stevel 993 0 stevel output(format, indent, "", path); 994 0 stevel print_field(data, def); 995 0 stevel /*CSTYLED*/ 996 0 stevel output("\"/>\n"); /* \" confuses cstyle */ 997 4392 dt207653 998 4392 dt207653 if ((strcmp(def->name, "Message") == 0) && 999 5015 dt207653 ((FMAmessageR == 0) || (FMAmessageR == 1))) { 1000 4392 dt207653 const char *elem_name = NULL; 1001 4392 dt207653 const char *parent_path; 1002 4392 dt207653 uchar_t tmpdata[128]; 1003 4392 dt207653 char path[16384]; 1004 4392 dt207653 const fru_regdef_t *new_def; 1005 4392 dt207653 1006 4392 dt207653 if (FMAmessageR == 0) 1007 4392 dt207653 elem_name = "FMA_Event_DataR"; 1008 4392 dt207653 else if (FMAmessageR == 1) 1009 4392 dt207653 elem_name = "FMA_MessageR"; 1010 4392 dt207653 if (elem_name != NULL) { 1011 4392 dt207653 (void) memcpy(tmpdata, data, def->payloadLen); 1012 4392 dt207653 new_def = fru_reg_lookup_def_by_name(elem_name); 1013 4430 dt207653 (void) snprintf(path, sizeof (path), 1014 4392 dt207653 "/Status_EventsR[%d]/Message(FMA)", iterglobal); 1015 4392 dt207653 parent_path = path; 1016 4392 dt207653 print_element(tmpdata, new_def, 1017 5015 dt207653 parent_path, 2*INDENT); 1018 4392 dt207653 FMAmessageR = -1; 1019 4392 dt207653 } 1020 4392 dt207653 } 1021 4392 dt207653 1022 0 stevel } else { 1023 0 stevel /* 1024 0 stevel * Base case: print the field 1025 0 stevel */ 1026 0 stevel output("%*s%s: ", indent, "", path); 1027 0 stevel print_field(data, def); 1028 0 stevel output("\n"); 1029 0 stevel } 1030 0 stevel } 1031 0 stevel 1032 0 stevel /* 1033 0 stevel * Print the contents of a packet (i.e., a tagged data element) 1034 0 stevel */ 1035 0 stevel /* ARGSUSED */ 1036 0 stevel static int 1037 0 stevel print_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args) 1038 0 stevel { 1039 0 stevel int tag_type = get_tag_type(tag); 1040 0 stevel 1041 0 stevel size_t payload_length = 0; 1042 0 stevel 1043 0 stevel const fru_regdef_t *def; 1044 0 stevel 1045 0 stevel /* 1046 0 stevel * Build a definition for unrecognized tags (e.g., not in libfrureg) 1047 0 stevel */ 1048 0 stevel if ((tag_type == -1) || 1049 0 stevel ((payload_length = get_payload_length(tag)) != length)) { 1050 0 stevel def = &unknown; 1051 0 stevel 1052 0 stevel unknown.tagType = -1; 1053 0 stevel unknown.tagDense = -1; 1054 0 stevel unknown.payloadLen = length; 1055 0 stevel unknown.dataLength = unknown.payloadLen; 1056 0 stevel 1057 0 stevel if (tag_type == -1) 1058 0 stevel (void) snprintf(tagname, sizeof (tagname), "INVALID"); 1059 0 stevel else 1060 0 stevel (void) snprintf(tagname, sizeof (tagname), 1061 0 stevel "%s_%u_%u_%u", get_tagtype_str(tag_type), 1062 0 stevel get_tag_dense(tag), payload_length, length); 1063 0 stevel } else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) { 1064 0 stevel def = &unknown; 1065 0 stevel 1066 0 stevel unknown.tagType = tag_type; 1067 0 stevel unknown.tagDense = get_tag_dense(tag); 1068 0 stevel unknown.payloadLen = payload_length; 1069 0 stevel unknown.dataLength = unknown.payloadLen; 1070 0 stevel 1071 0 stevel (void) snprintf(tagname, sizeof (tagname), "%s_%u_%u", 1072 0 stevel get_tagtype_str(unknown.tagType), 1073 0 stevel unknown.tagDense, payload_length); 1074 0 stevel } 1075 0 stevel 1076 0 stevel 1077 0 stevel /* 1078 0 stevel * Print the defined element 1079 0 stevel */ 1080 0 stevel print_element(payload, def, "", INDENT); 1081 0 stevel 1082 0 stevel return (FRU_SUCCESS); 1083 0 stevel } 1084 0 stevel 1085 0 stevel /* 1086 0 stevel * Print a segment's name and the contents of each data element in the segment 1087 0 stevel */ 1088 0 stevel static int 1089 0 stevel print_packets_in_segment(fru_seghdl_t segment, void *args) 1090 0 stevel { 1091 0 stevel char *name; 1092 0 stevel 1093 0 stevel int status; 1094 0 stevel 1095 0 stevel 1096 0 stevel if ((status = fru_get_segment_name(segment, &name)) != FRU_SUCCESS) { 1097 0 stevel saved_status = status; 1098 0 stevel name = ""; 1099 0 stevel error(gettext("Error getting segment name: %s\n"), 1100 0 stevel fru_strerror(status)); 1101 0 stevel } 1102 0 stevel 1103 0 stevel 1104 0 stevel if (xml) 1105 0 stevel output("%*s<Segment name=\"%s\">\n", INDENT, "", name); 1106 0 stevel else 1107 0 stevel output("%*sSEGMENT: %s\n", INDENT, "", name); 1108 0 stevel 1109 8244 Dipti if (strcmp(name, "ED") == 0) { 1110 8244 Dipti if (xml) output("%*s</Segment>\n", INDENT, ""); 1111 8244 Dipti free(name); 1112 8244 Dipti return (FRU_SUCCESS); 1113 8244 Dipti } 1114 0 stevel /* Iterate over the packets in the segment, printing the contents */ 1115 0 stevel if ((status = fru_for_each_packet(segment, print_packet, args)) 1116 0 stevel != FRU_SUCCESS) { 1117 0 stevel saved_status = status; 1118 0 stevel error(gettext("Error processing data in segment \"%s\": %s\n"), 1119 5015 dt207653 name, fru_strerror(status)); 1120 0 stevel } 1121 0 stevel 1122 0 stevel if (xml) output("%*s</Segment>\n", INDENT, ""); 1123 0 stevel 1124 0 stevel free(name); 1125 0 stevel 1126 0 stevel return (FRU_SUCCESS); 1127 0 stevel } 1128 0 stevel 1129 0 stevel /* ARGSUSED */ 1130 0 stevel static void 1131 0 stevel print_node_path(fru_node_t fru_type, const char *path, const char *name, 1132 0 stevel end_node_fp_t *end_node, void **end_args) 1133 0 stevel { 1134 0 stevel output("%s%s\n", path, 1135 0 stevel ((fru_type == FRU_NODE_CONTAINER) ? " (container)" 1136 5015 dt207653 : ((fru_type == FRU_NODE_FRU) ? " (fru)" : ""))); 1137 0 stevel } 1138 0 stevel 1139 0 stevel /* 1140 0 stevel * Close the XML element for a "location" node 1141 0 stevel */ 1142 0 stevel /* ARGSUSED */ 1143 0 stevel static void 1144 0 stevel end_location_xml(fru_nodehdl_t node, const char *path, const char *name, 1145 0 stevel void *args) 1146 0 stevel { 1147 0 stevel assert(args != NULL); 1148 0 stevel output("</Location> <!-- %s -->\n", args); 1149 0 stevel } 1150 0 stevel 1151 0 stevel /* 1152 0 stevel * Close the XML element for a "fru" node 1153 0 stevel */ 1154 0 stevel /* ARGSUSED */ 1155 0 stevel static void 1156 0 stevel end_fru_xml(fru_nodehdl_t node, const char *path, const char *name, void *args) 1157 0 stevel { 1158 0 stevel assert(args != NULL); 1159 0 stevel output("</Fru> <!-- %s -->\n", args); 1160 0 stevel } 1161 0 stevel 1162 0 stevel /* 1163 0 stevel * Close the XML element for a "container" node 1164 0 stevel */ 1165 0 stevel /* ARGSUSED */ 1166 0 stevel static void 1167 0 stevel end_container_xml(fru_nodehdl_t node, const char *path, const char *name, 1168 0 stevel void *args) 1169 0 stevel { 1170 0 stevel assert(args != NULL); 1171 0 stevel output("</Container> <!-- %s -->\n", args); 1172 0 stevel } 1173 0 stevel 1174 0 stevel /* 1175 0 stevel * Introduce a node in XML and set the appropriate node-closing function 1176 0 stevel */ 1177 0 stevel /* ARGSUSED */ 1178 0 stevel static void 1179 0 stevel print_node_xml(fru_node_t fru_type, const char *path, const char *name, 1180 0 stevel end_node_fp_t *end_node, void **end_args) 1181 0 stevel { 1182 0 stevel switch (fru_type) { 1183 0 stevel case FRU_NODE_FRU: 1184 0 stevel output("<Fru name=\"%s\">\n", name); 1185 0 stevel *end_node = end_fru_xml; 1186 0 stevel break; 1187 0 stevel case FRU_NODE_CONTAINER: 1188 0 stevel output("<Container name=\"%s\">\n", name); 1189 0 stevel *end_node = end_container_xml; 1190 0 stevel break; 1191 0 stevel default: 1192 0 stevel output("<Location name=\"%s\">\n", name); 1193 0 stevel *end_node = end_location_xml; 1194 0 stevel break; 1195 0 stevel } 1196 0 stevel 1197 0 stevel *end_args = (void *) name; 1198 0 stevel } 1199 0 stevel 1200 0 stevel /* 1201 0 stevel * Print node info and, where appropriate, node contents 1202 0 stevel */ 1203 0 stevel /* ARGSUSED */ 1204 0 stevel static fru_errno_t 1205 0 stevel process_node(fru_nodehdl_t node, const char *path, const char *name, 1206 0 stevel void *args, end_node_fp_t *end_node, void **end_args) 1207 0 stevel { 1208 0 stevel int status; 1209 0 stevel 1210 0 stevel fru_node_t fru_type = FRU_NODE_UNKNOWN; 1211 0 stevel 1212 0 stevel 1213 0 stevel if ((status = fru_get_node_type(node, &fru_type)) != FRU_SUCCESS) { 1214 0 stevel saved_status = status; 1215 0 stevel error(gettext("Error getting node type: %s\n"), 1216 5015 dt207653 fru_strerror(status)); 1217 0 stevel } 1218 0 stevel 1219 0 stevel if (containers_only) { 1220 0 stevel if (fru_type != FRU_NODE_CONTAINER) 1221 0 stevel return (FRU_SUCCESS); 1222 0 stevel name = path; 1223 0 stevel } 1224 0 stevel 1225 0 stevel /* Introduce the node */ 1226 0 stevel assert(print_node != NULL); 1227 0 stevel print_node(fru_type, path, name, end_node, end_args); 1228 0 stevel 1229 0 stevel if (list_only) 1230 0 stevel return (FRU_SUCCESS); 1231 0 stevel 1232 0 stevel /* Print the contents of each packet in each segment of a container */ 1233 0 stevel if (fru_type == FRU_NODE_CONTAINER) { 1234 0 stevel if (xml) output("<ContainerData>\n"); 1235 0 stevel if ((status = 1236 5015 dt207653 fru_for_each_segment(node, print_packets_in_segment, 1237 5015 dt207653 NULL)) 1238 0 stevel != FRU_SUCCESS) { 1239 0 stevel saved_status = status; 1240 0 stevel error(gettext("Error processing node \"%s\": %s\n"), 1241 5015 dt207653 name, fru_strerror(status)); 1242 0 stevel } 1243 0 stevel if (xml) output("</ContainerData>\n"); 1244 0 stevel } 1245 0 stevel 1246 0 stevel return (FRU_SUCCESS); 1247 0 stevel } 1248 0 stevel 1249 0 stevel /* 1250 0 stevel * Process the node if its path matches the search path in "args" 1251 0 stevel */ 1252 0 stevel /* ARGSUSED */ 1253 0 stevel static fru_errno_t 1254 0 stevel process_matching_node(fru_nodehdl_t node, const char *path, const char *name, 1255 0 stevel void *args, end_node_fp_t *end_node, void **end_args) 1256 5015 dt207653 { 1257 0 stevel int status; 1258 0 stevel 1259 0 stevel 1260 0 stevel if (!fru_pathmatch(path, args)) 1261 0 stevel return (FRU_SUCCESS); 1262 0 stevel 1263 0 stevel status = process_node(node, path, path, args, end_node, end_args); 1264 0 stevel 1265 0 stevel return ((status == FRU_SUCCESS) ? FRU_WALK_TERMINATE : status); 1266 0 stevel } 1267 0 stevel 1268 0 stevel /* 1269 0 stevel * Write the trailer required for well-formed DTD-compliant XML 1270 0 stevel */ 1271 0 stevel static void 1272 0 stevel terminate_xml() 1273 0 stevel { 1274 0 stevel errno = 0; 1275 0 stevel if (ftell(errlog) > 0) { 1276 0 stevel char c; 1277 0 stevel 1278 0 stevel output("<ErrorLog>\n"); 1279 0 stevel rewind(errlog); 1280 0 stevel if (!errno) 1281 0 stevel while ((c = getc(errlog)) != EOF) 1282 0 stevel xputchar(c); 1283 0 stevel output("</ErrorLog>\n"); 1284 0 stevel } 1285 0 stevel 1286 0 stevel if (errno) { 1287 0 stevel /*NOTREACHED*/ 1288 0 stevel errlog = NULL; 1289 0 stevel error(gettext("Error copying error messages to \"ErrorLog\""), 1290 0 stevel strerror(errno)); 1291 0 stevel } 1292 0 stevel 1293 0 stevel output("</FRUID_XML_Tree>\n"); 1294 0 stevel } 1295 0 stevel 1296 0 stevel /* 1297 0 stevel * Print available FRU ID information 1298 0 stevel */ 1299 0 stevel int 1300 0 stevel prtfru(const char *searchpath, int containers_only_flag, int list_only_flag, 1301 0 stevel int xml_flag) 1302 0 stevel { 1303 0 stevel fru_errno_t status; 1304 0 stevel 1305 0 stevel fru_nodehdl_t frutree = 0; 1306 0 stevel 1307 0 stevel 1308 0 stevel /* Copy parameter flags to global flags */ 1309 0 stevel containers_only = containers_only_flag; 1310 0 stevel list_only = list_only_flag; 1311 0 stevel xml = xml_flag; 1312 0 stevel 1313 0 stevel 1314 0 stevel /* Help arrange for correct, efficient interleaving of output */ 1315 0 stevel (void) setvbuf(stderr, NULL, _IOLBF, 0); 1316 0 stevel 1317 0 stevel 1318 0 stevel /* Initialize for XML--or not */ 1319 0 stevel if (xml) { 1320 0 stevel safeputchar = xputchar; 1321 0 stevel safeputs = xputs; 1322 0 stevel 1323 0 stevel print_node = print_node_xml; 1324 0 stevel 1325 0 stevel if ((errlog = tmpfile()) == NULL) { 1326 0 stevel (void) fprintf(stderr, 1327 0 stevel "Error creating error log file: %s\n", 1328 0 stevel strerror(errno)); 1329 0 stevel return (1); 1330 0 stevel } 1331 0 stevel 1332 0 stevel /* Output the XML preamble */ 1333 0 stevel output("<?xml version=\"1.0\" ?>\n" 1334 0 stevel "<!--\n" 1335 0 stevel " Copyright 2000-2002 Sun Microsystems, Inc. " 1336 0 stevel "All rights reserved.\n" 1337 0 stevel " Use is subject to license terms.\n" 1338 0 stevel "-->\n\n" 1339 0 stevel "<!DOCTYPE FRUID_XML_Tree SYSTEM \"prtfrureg.dtd\">\n\n" 1340 0 stevel "<FRUID_XML_Tree>\n"); 1341 0 stevel 1342 0 stevel /* Arrange to always properly terminate XML */ 1343 0 stevel if (atexit(terminate_xml)) 1344 0 stevel error(gettext("Warning: XML will not be terminated: " 1345 5015 dt207653 "%s\n"), strerror(errno)); 1346 0 stevel } else 1347 0 stevel print_node = print_node_path; 1348 0 stevel 1349 0 stevel 1350 0 stevel /* Get the root node */ 1351 0 stevel if ((status = fru_get_root(&frutree)) == FRU_NODENOTFOUND) { 1352 6201 dt207653 error(gettext("This system does not support PICL " 1353 6201 dt207653 "infrastructure to provide FRUID data\n" 1354 6201 dt207653 "Please use the platform SP to access the FRUID " 1355 6201 dt207653 "information\n")); 1356 0 stevel return (1); 1357 0 stevel } else if (status != FRU_SUCCESS) { 1358 0 stevel error(gettext("Unable to access FRU ID data: %s\n"), 1359 5015 dt207653 fru_strerror(status)); 1360 0 stevel return (1); 1361 0 stevel } 1362 0 stevel 1363 0 stevel /* Process the tree */ 1364 0 stevel if (searchpath == NULL) { 1365 0 stevel status = fru_walk_tree(frutree, "", process_node, NULL); 1366 0 stevel } else { 1367 0 stevel status = fru_walk_tree(frutree, "", process_matching_node, 1368 5015 dt207653 (void *)searchpath); 1369 0 stevel if (status == FRU_WALK_TERMINATE) { 1370 0 stevel status = FRU_SUCCESS; 1371 0 stevel } else if (status == FRU_SUCCESS) { 1372 0 stevel error(gettext("\"%s\" not found\n"), searchpath); 1373 0 stevel return (1); 1374 0 stevel } 1375 0 stevel } 1376 0 stevel 1377 0 stevel if (status != FRU_SUCCESS) 1378 0 stevel error(gettext("Error processing FRU tree: %s\n"), 1379 5015 dt207653 fru_strerror(status)); 1380 0 stevel 1381 0 stevel return (((status == FRU_SUCCESS) && (saved_status == 0)) ? 0 : 1); 1382 0 stevel } 1383