17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 594bc7577Sps154918 * Common Development and Distribution License (the "License"). 694bc7577Sps154918 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2294bc7577Sps154918 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <alloca.h> 297c478bd9Sstevel@tonic-gate #include <assert.h> 307c478bd9Sstevel@tonic-gate #include <errno.h> 317c478bd9Sstevel@tonic-gate #include <libintl.h> 327c478bd9Sstevel@tonic-gate #include <stdarg.h> 337c478bd9Sstevel@tonic-gate #include <stdio.h> 347c478bd9Sstevel@tonic-gate #include <stdlib.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include "fru_tag.h" 387c478bd9Sstevel@tonic-gate #include "libfrup.h" 397c478bd9Sstevel@tonic-gate #include "libfrureg.h" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #define NUM_ITER_BYTES 4 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #define HEAD_ITER 0 457c478bd9Sstevel@tonic-gate #define TAIL_ITER 1 /* not used */ 467c478bd9Sstevel@tonic-gate #define NUM_ITER 2 477c478bd9Sstevel@tonic-gate #define MAX_ITER 3 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define INDENT 3 507c478bd9Sstevel@tonic-gate #define TIMESTRINGLEN 128 5194bc7577Sps154918 #define TEMPERATURE_OFFSET 73 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static void (*print_node)(fru_node_t fru_type, const char *path, 547c478bd9Sstevel@tonic-gate const char *name, end_node_fp_t *end_node, 557c478bd9Sstevel@tonic-gate void **end_args); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static char tagname[sizeof ("?_0123456789_0123456789_0123456789")]; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate static int containers_only = 0, list_only = 0, saved_status = 0, xml = 0; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static FILE *errlog; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* 647c478bd9Sstevel@tonic-gate * Definition for data elements found in devices but not found in 657c478bd9Sstevel@tonic-gate * the system's version of libfrureg 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate static fru_regdef_t unknown = { 687c478bd9Sstevel@tonic-gate REGDEF_VERSION, 697c478bd9Sstevel@tonic-gate tagname, 707c478bd9Sstevel@tonic-gate -1, 717c478bd9Sstevel@tonic-gate -1, 727c478bd9Sstevel@tonic-gate -1, 737c478bd9Sstevel@tonic-gate -1, 747c478bd9Sstevel@tonic-gate FDTYPE_ByteArray, 757c478bd9Sstevel@tonic-gate FDISP_Hex, 767c478bd9Sstevel@tonic-gate FRU_WHICH_UNDEFINED, 777c478bd9Sstevel@tonic-gate FRU_WHICH_UNDEFINED, 787c478bd9Sstevel@tonic-gate 0, 797c478bd9Sstevel@tonic-gate NULL, 807c478bd9Sstevel@tonic-gate 0, 817c478bd9Sstevel@tonic-gate FRU_NOT_ITERATED, 827c478bd9Sstevel@tonic-gate NULL 837c478bd9Sstevel@tonic-gate }; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * Write message to standard error and possibly the error log buffer 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate static void 907c478bd9Sstevel@tonic-gate error(const char *format, ...) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate va_list args; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* make relevant output appear before error message */ 967c478bd9Sstevel@tonic-gate if (fflush(stdout) == EOF) { 977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Error flushing output: %s\n", 987c478bd9Sstevel@tonic-gate strerror(errno)); 997c478bd9Sstevel@tonic-gate exit(1); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate va_start(args, format); 1037c478bd9Sstevel@tonic-gate if (vfprintf(stderr, format, args) < 0) exit(1); 1047c478bd9Sstevel@tonic-gate if (errlog && (vfprintf(errlog, format, args) < 0)) exit(1); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Write message to standard output 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate static void 1117c478bd9Sstevel@tonic-gate output(const char *format, ...) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate va_list args; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate va_start(args, format); 1177c478bd9Sstevel@tonic-gate if (vfprintf(stdout, format, args) < 0) { 1187c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 1197c478bd9Sstevel@tonic-gate strerror(errno)); 1207c478bd9Sstevel@tonic-gate exit(1); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * Safe wrapper for putchar() 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate static void 1287c478bd9Sstevel@tonic-gate voidputchar(int c) 1297c478bd9Sstevel@tonic-gate { 1307c478bd9Sstevel@tonic-gate if (putchar(c) == EOF) { 1317c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 1327c478bd9Sstevel@tonic-gate strerror(errno)); 1337c478bd9Sstevel@tonic-gate exit(1); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static void (*safeputchar)(int c) = voidputchar; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Safe wrapper for puts() 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate static void 1437c478bd9Sstevel@tonic-gate voidputs(const char *s) 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate if (fputs(s, stdout) == EOF) { 1467c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 1477c478bd9Sstevel@tonic-gate strerror(errno)); 1487c478bd9Sstevel@tonic-gate exit(1); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate static void (*safeputs)(const char *s) = voidputs; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * XML-safe wrapper for putchar(): quotes XML-special characters 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate static void 1587c478bd9Sstevel@tonic-gate xputchar(int c) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate switch (c) { 1617c478bd9Sstevel@tonic-gate case '<': 1627c478bd9Sstevel@tonic-gate c = fputs("<", stdout); 1637c478bd9Sstevel@tonic-gate break; 1647c478bd9Sstevel@tonic-gate case '>': 1657c478bd9Sstevel@tonic-gate c = fputs(">", stdout); 1667c478bd9Sstevel@tonic-gate break; 1677c478bd9Sstevel@tonic-gate case '&': 1687c478bd9Sstevel@tonic-gate c = fputs("&", stdout); 1697c478bd9Sstevel@tonic-gate break; 1707c478bd9Sstevel@tonic-gate case '"': 1717c478bd9Sstevel@tonic-gate c = fputs(""", stdout); 1727c478bd9Sstevel@tonic-gate break; 1737c478bd9Sstevel@tonic-gate default: 1747c478bd9Sstevel@tonic-gate c = putchar(c); 1757c478bd9Sstevel@tonic-gate break; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (c == EOF) { 1797c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 1807c478bd9Sstevel@tonic-gate strerror(errno)); 1817c478bd9Sstevel@tonic-gate exit(1); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * XML-safe analog of puts(): quotes XML-special characters 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate static void 1897c478bd9Sstevel@tonic-gate xputs(const char *s) 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate char c; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate for (/* */; ((c = *s) != 0); s++) 1947c478bd9Sstevel@tonic-gate xputchar(c); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Output the XML DTD derived from the registry provided by libfrureg 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate int 2017c478bd9Sstevel@tonic-gate output_dtd(void) 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate char **element; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate unsigned int i, j, num_elements = 0; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate uint8_t *tagged; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate const fru_regdef_t *def; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if (((element = fru_reg_list_entries(&num_elements)) == NULL) || 2137c478bd9Sstevel@tonic-gate (num_elements == 0)) { 2147c478bd9Sstevel@tonic-gate error(gettext("No FRU ID Registry elements")); 2157c478bd9Sstevel@tonic-gate return (1); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if ((tagged = calloc(num_elements, sizeof (*tagged))) == NULL) { 2197c478bd9Sstevel@tonic-gate error(gettext("Unable to get memory for tagged element list"), 2207c478bd9Sstevel@tonic-gate strerror(errno)); 2217c478bd9Sstevel@tonic-gate return (1); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Output the DTD preamble 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate output("<!ELEMENT FRUID_XML_Tree (Parameter*, " 2287c478bd9Sstevel@tonic-gate "(Fru | Location | Container)*,\n" 2297c478bd9Sstevel@tonic-gate " Parameter*, ErrorLog?, Parameter*)>\n" 2307c478bd9Sstevel@tonic-gate "<!ATTLIST FRUID_XML_Tree>\n" 2317c478bd9Sstevel@tonic-gate "\n" 2327c478bd9Sstevel@tonic-gate "<!ELEMENT Parameter EMPTY>\n" 2337c478bd9Sstevel@tonic-gate "<!ATTLIST Parameter type CDATA #REQUIRED>\n" 2347c478bd9Sstevel@tonic-gate "<!ATTLIST Parameter name CDATA #REQUIRED>\n" 2357c478bd9Sstevel@tonic-gate "<!ATTLIST Parameter value CDATA #REQUIRED>\n" 2367c478bd9Sstevel@tonic-gate "\n" 2377c478bd9Sstevel@tonic-gate "<!ELEMENT Fru (Fru | Location | Container)*>\n" 2387c478bd9Sstevel@tonic-gate "<!ATTLIST Fru name CDATA #REQUIRED>\n" 2397c478bd9Sstevel@tonic-gate "\n" 2407c478bd9Sstevel@tonic-gate "<!ELEMENT Location (Fru | Location | Container)*>\n" 24194bc7577Sps154918 "<!ATTLIST Location\n" 24294bc7577Sps154918 " name CDATA #IMPLIED\n" 24394bc7577Sps154918 " value CDATA #IMPLIED\n" 24494bc7577Sps154918 ">\n" 2457c478bd9Sstevel@tonic-gate "\n" 2467c478bd9Sstevel@tonic-gate "<!ELEMENT Container (ContainerData?, " 2477c478bd9Sstevel@tonic-gate "(Fru | Location | Container)*)>\n" 2487c478bd9Sstevel@tonic-gate "<!ATTLIST Container name CDATA #REQUIRED>\n" 2497c478bd9Sstevel@tonic-gate "<!ATTLIST Container imagefile CDATA #IMPLIED>\n" 2507c478bd9Sstevel@tonic-gate "\n" 2517c478bd9Sstevel@tonic-gate "<!ELEMENT ContainerData (Segment*)>\n" 2527c478bd9Sstevel@tonic-gate "<!ATTLIST ContainerData>\n" 2537c478bd9Sstevel@tonic-gate "\n" 2547c478bd9Sstevel@tonic-gate "<!ATTLIST Segment name CDATA #REQUIRED>\n" 2557c478bd9Sstevel@tonic-gate "\n" 2567c478bd9Sstevel@tonic-gate "<!ELEMENT Index EMPTY>\n" 2577c478bd9Sstevel@tonic-gate "<!ATTLIST Index value CDATA #REQUIRED>\n" 2587c478bd9Sstevel@tonic-gate "\n" 2597c478bd9Sstevel@tonic-gate "<!ELEMENT ErrorLog (#PCDATA)>\n" 2607c478bd9Sstevel@tonic-gate "<!ATTLIST ErrorLog>\n" 2617c478bd9Sstevel@tonic-gate "\n"); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * Output the definition for each element 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate for (i = 0; i < num_elements; i++) { 2677c478bd9Sstevel@tonic-gate assert(element[i] != NULL); 26894bc7577Sps154918 /* Prevent incompatible duplicate defn. from FRUID Registry. */ 26994bc7577Sps154918 if ((strcmp("Location", element[i])) == 0) continue; 2707c478bd9Sstevel@tonic-gate if ((def = fru_reg_lookup_def_by_name(element[i])) == NULL) { 2717c478bd9Sstevel@tonic-gate error(gettext("Error looking up registry " 2727c478bd9Sstevel@tonic-gate "definition for \"%s\"\n"), 2737c478bd9Sstevel@tonic-gate element[i]); 2747c478bd9Sstevel@tonic-gate return (1); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (def->tagType != FRU_X) tagged[i] = 1; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (def->dataType == FDTYPE_Record) { 2807c478bd9Sstevel@tonic-gate if (def->iterationType == FRU_NOT_ITERATED) 2817c478bd9Sstevel@tonic-gate output("<!ELEMENT %s (%s", element[i], 2827c478bd9Sstevel@tonic-gate def->enumTable[0].text); 2837c478bd9Sstevel@tonic-gate else 2847c478bd9Sstevel@tonic-gate output("<!ELEMENT %s (Index_%s*)>\n" 2857c478bd9Sstevel@tonic-gate "<!ATTLIST Index_%s>\n" 2867c478bd9Sstevel@tonic-gate "<!ELEMENT Index_%s (%s", 2877c478bd9Sstevel@tonic-gate element[i], element[i], element[i], 2887c478bd9Sstevel@tonic-gate element[i], def->enumTable[0].text); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate for (j = 1; j < def->enumCount; j++) 2917c478bd9Sstevel@tonic-gate output(",\n\t%s", def->enumTable[j].text); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate output(")>\n"); 2947c478bd9Sstevel@tonic-gate } else if (def->iterationType == FRU_NOT_ITERATED) { 2957c478bd9Sstevel@tonic-gate output("<!ELEMENT %s EMPTY>\n" 2967c478bd9Sstevel@tonic-gate "<!ATTLIST %s value CDATA #REQUIRED>\n", 2977c478bd9Sstevel@tonic-gate element[i], element[i]); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (def->dataType == FDTYPE_Enumeration) { 3007c478bd9Sstevel@tonic-gate output("<!-- %s valid enumeration values\n"); 3017c478bd9Sstevel@tonic-gate for (j = 0; j < def->enumCount; j++) { 3027c478bd9Sstevel@tonic-gate output("\t\""); 3037c478bd9Sstevel@tonic-gate xputs(def->enumTable[j].text); 3047c478bd9Sstevel@tonic-gate output("\"\n"); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate output("-->\n"); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate else 3107c478bd9Sstevel@tonic-gate output("<!ELEMENT %s (Index*)>\n", element[i]); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate output("\n"); 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* Provide for returning the tag for an "unknown" element */ 3167c478bd9Sstevel@tonic-gate output("<!ATTLIST UNKNOWN tag CDATA \"UNKNOWN\">\n\n"); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * List all data elements as possible members of "Segment" 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate output("<!ELEMENT Segment ((UNKNOWN"); 3237c478bd9Sstevel@tonic-gate for (i = 0; i < num_elements; i++) { 3247c478bd9Sstevel@tonic-gate if (tagged[i]) output("\n\t| %s", element[i]); 3257c478bd9Sstevel@tonic-gate free(element[i]); 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate output(")*)>\n"); 3287c478bd9Sstevel@tonic-gate free(element); 3297c478bd9Sstevel@tonic-gate free(tagged); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate return (0); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Safely pretty-print the value of a field 3367c478bd9Sstevel@tonic-gate */ 3377c478bd9Sstevel@tonic-gate static void 3387c478bd9Sstevel@tonic-gate print_field(const uint8_t *field, const fru_regdef_t *def) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate char *errmsg = NULL, timestring[TIMESTRINGLEN]; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate int i; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate uint64_t value; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate time_t timefield; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate switch (def->dataType) { 3507c478bd9Sstevel@tonic-gate case FDTYPE_Binary: 3517c478bd9Sstevel@tonic-gate assert(def->payloadLen <= sizeof (value)); 3527c478bd9Sstevel@tonic-gate switch (def->dispType) { 3537c478bd9Sstevel@tonic-gate case FDISP_Binary: 3547c478bd9Sstevel@tonic-gate for (i = 0; i < def->payloadLen; i++) 3557c478bd9Sstevel@tonic-gate output("%c%c%c%c%c%c%c%c", 3567c478bd9Sstevel@tonic-gate ((field[i] & 0x80) ? '1' : '0'), 3577c478bd9Sstevel@tonic-gate ((field[i] & 0x40) ? '1' : '0'), 3587c478bd9Sstevel@tonic-gate ((field[i] & 0x20) ? '1' : '0'), 3597c478bd9Sstevel@tonic-gate ((field[i] & 0x10) ? '1' : '0'), 3607c478bd9Sstevel@tonic-gate ((field[i] & 0x08) ? '1' : '0'), 3617c478bd9Sstevel@tonic-gate ((field[i] & 0x04) ? '1' : '0'), 3627c478bd9Sstevel@tonic-gate ((field[i] & 0x02) ? '1' : '0'), 3637c478bd9Sstevel@tonic-gate ((field[i] & 0x01) ? '1' : '0')); 3647c478bd9Sstevel@tonic-gate return; 3657c478bd9Sstevel@tonic-gate case FDISP_Octal: 3667c478bd9Sstevel@tonic-gate case FDISP_Decimal: 3677c478bd9Sstevel@tonic-gate value = 0; 3687c478bd9Sstevel@tonic-gate (void) memcpy((((uint8_t *)&value) + 3697c478bd9Sstevel@tonic-gate sizeof (value) - def->payloadLen), 3707c478bd9Sstevel@tonic-gate field, def->payloadLen); 37194bc7577Sps154918 if ((value != 0) && 37294bc7577Sps154918 ((strcmp(def->name, "Lowest") == 0) || 37394bc7577Sps154918 (strcmp(def->name, "Highest") == 0) || 37494bc7577Sps154918 (strcmp(def->name, "Latest") == 0))) 375*1e3549a6Sps154918 output((def->dispType == FDISP_Octal) ? 376*1e3549a6Sps154918 "%llo" : "%lld (%lld degrees C)", 377*1e3549a6Sps154918 value, (value - TEMPERATURE_OFFSET)); 378*1e3549a6Sps154918 else 3797c478bd9Sstevel@tonic-gate output((def->dispType == FDISP_Octal) ? 3807c478bd9Sstevel@tonic-gate "%llo" : "%lld", value); 3817c478bd9Sstevel@tonic-gate return; 3827c478bd9Sstevel@tonic-gate case FDISP_Time: 3837c478bd9Sstevel@tonic-gate if (def->payloadLen > sizeof (timefield)) { 3847c478bd9Sstevel@tonic-gate errmsg = "time value too large for formatting"; 3857c478bd9Sstevel@tonic-gate break; 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate (void) memcpy(&timefield, field, sizeof (timefield)); 3887c478bd9Sstevel@tonic-gate if (strftime(timestring, sizeof (timestring), "%C", 3897c478bd9Sstevel@tonic-gate localtime(&timefield)) == 0) { 3907c478bd9Sstevel@tonic-gate errmsg = "formatted time would overflow buffer"; 3917c478bd9Sstevel@tonic-gate break; 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate safeputs(timestring); 3947c478bd9Sstevel@tonic-gate return; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate break; 3977c478bd9Sstevel@tonic-gate case FDTYPE_ASCII: 3987c478bd9Sstevel@tonic-gate for (i = 0; i < def->payloadLen && field[i]; i++) 3997c478bd9Sstevel@tonic-gate safeputchar(field[i]); 4007c478bd9Sstevel@tonic-gate return; 4017c478bd9Sstevel@tonic-gate case FDTYPE_Enumeration: 4027c478bd9Sstevel@tonic-gate value = 0; 4037c478bd9Sstevel@tonic-gate (void) memcpy((((uint8_t *)&value) + sizeof (value) 4047c478bd9Sstevel@tonic-gate - def->payloadLen), 4057c478bd9Sstevel@tonic-gate field, def->payloadLen); 4067c478bd9Sstevel@tonic-gate for (i = 0; i < def->enumCount; i++) 4077c478bd9Sstevel@tonic-gate if (def->enumTable[i].value == value) { 4087c478bd9Sstevel@tonic-gate safeputs(def->enumTable[i].text); 4097c478bd9Sstevel@tonic-gate return; 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate errmsg = "unrecognized value"; 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* If nothing matched above, print the field in hex */ 4177c478bd9Sstevel@tonic-gate for (i = 0; i < def->payloadLen; i++) 4187c478bd9Sstevel@tonic-gate output("%2.2X", field[i]); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* Safely print any error message associated with the field */ 4217c478bd9Sstevel@tonic-gate if (errmsg) { 4227c478bd9Sstevel@tonic-gate output(" ("); 4237c478bd9Sstevel@tonic-gate safeputs(errmsg); 4247c478bd9Sstevel@tonic-gate output(")\n"); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * Recursively print the contents of a data element 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate static void 4327c478bd9Sstevel@tonic-gate print_element(const uint8_t *data, const fru_regdef_t *def, 4337c478bd9Sstevel@tonic-gate const char *parent_path, int indent) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate char *path; 4367c478bd9Sstevel@tonic-gate size_t len; 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate int bytes = 0, i; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate indent = (xml) ? (indent + INDENT) : (2*INDENT); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate /* 4447c478bd9Sstevel@tonic-gate * Construct the path, or, for XML, the name, for the current 4457c478bd9Sstevel@tonic-gate * data element 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate if ((def->iterationCount == 0) && 4487c478bd9Sstevel@tonic-gate (def->iterationType != FRU_NOT_ITERATED)) { 4497c478bd9Sstevel@tonic-gate if (xml) { 4507c478bd9Sstevel@tonic-gate if (def->dataType == FDTYPE_Record) { 4517c478bd9Sstevel@tonic-gate len = strlen("Index_") + strlen(def->name) + 1; 4527c478bd9Sstevel@tonic-gate path = alloca(len); 4537c478bd9Sstevel@tonic-gate (void) snprintf(path, len, 4547c478bd9Sstevel@tonic-gate "Index_%s", def->name); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate else 4577c478bd9Sstevel@tonic-gate path = "Index"; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate else 4607c478bd9Sstevel@tonic-gate path = (char *)parent_path; 4617c478bd9Sstevel@tonic-gate } else { 4627c478bd9Sstevel@tonic-gate if (xml) 4637c478bd9Sstevel@tonic-gate path = (char *)def->name; 4647c478bd9Sstevel@tonic-gate else { 4657c478bd9Sstevel@tonic-gate len = strlen(parent_path) + sizeof ("/") + 4667c478bd9Sstevel@tonic-gate strlen(def->name) + 4677c478bd9Sstevel@tonic-gate (def->iterationCount ? sizeof ("[255]") : 0); 4687c478bd9Sstevel@tonic-gate path = alloca(len); 4697c478bd9Sstevel@tonic-gate bytes = snprintf(path, len, 4707c478bd9Sstevel@tonic-gate "%s/%s", parent_path, def->name); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * Handle the various categories of data elements: iteration, 4767c478bd9Sstevel@tonic-gate * record, and field 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate if (def->iterationCount) { 4797c478bd9Sstevel@tonic-gate int iterlen = (def->payloadLen - NUM_ITER_BYTES)/ 4807c478bd9Sstevel@tonic-gate def->iterationCount, 4817c478bd9Sstevel@tonic-gate n, valid = 1; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate uint8_t head, num; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate fru_regdef_t newdef; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate /* 4897c478bd9Sstevel@tonic-gate * Make a new element definition to describe the components 4907c478bd9Sstevel@tonic-gate * of the iteration 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate (void) memcpy(&newdef, def, sizeof (newdef)); 4937c478bd9Sstevel@tonic-gate newdef.iterationCount = 0; 4947c478bd9Sstevel@tonic-gate newdef.payloadLen = iterlen; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * Validate the contents of the iteration control bytes 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate if (data[HEAD_ITER] >= def->iterationCount) { 5007c478bd9Sstevel@tonic-gate valid = 0; 5017c478bd9Sstevel@tonic-gate error(gettext("%s: Invalid iteration head: %d " 5027c478bd9Sstevel@tonic-gate "(should be less than %d)\n"), 5037c478bd9Sstevel@tonic-gate path, data[HEAD_ITER], def->iterationCount); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (data[NUM_ITER] > def->iterationCount) { 5077c478bd9Sstevel@tonic-gate valid = 0; 5087c478bd9Sstevel@tonic-gate error(gettext("%s: Invalid iteration count: %d " 5097c478bd9Sstevel@tonic-gate "(should not be greater than %d)\n"), 5107c478bd9Sstevel@tonic-gate path, data[NUM_ITER], def->iterationCount); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if (data[MAX_ITER] != def->iterationCount) { 5147c478bd9Sstevel@tonic-gate valid = 0; 5157c478bd9Sstevel@tonic-gate error(gettext("%s: Invalid iteration maximum: %d " 5167c478bd9Sstevel@tonic-gate "(should equal %d)\n"), 5177c478bd9Sstevel@tonic-gate path, data[MAX_ITER], def->iterationCount); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if (valid) { 5217c478bd9Sstevel@tonic-gate head = data[HEAD_ITER]; 5227c478bd9Sstevel@tonic-gate num = data[NUM_ITER]; 5237c478bd9Sstevel@tonic-gate } else { 5247c478bd9Sstevel@tonic-gate head = 0; 5257c478bd9Sstevel@tonic-gate num = def->iterationCount; 5267c478bd9Sstevel@tonic-gate error(gettext("%s: Showing all iterations\n"), path); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate if (xml) 5307c478bd9Sstevel@tonic-gate output("%*s<%s>\n", indent, "", path); 5317c478bd9Sstevel@tonic-gate else 5327c478bd9Sstevel@tonic-gate output("%*s%s (%d iterations)\n", indent, "", path, 5337c478bd9Sstevel@tonic-gate num); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * Print each component of the iteration 5377c478bd9Sstevel@tonic-gate */ 5387c478bd9Sstevel@tonic-gate for (i = head, n = 0, data += 4; 5397c478bd9Sstevel@tonic-gate n < num; 5407c478bd9Sstevel@tonic-gate i = ((i + 1) % def->iterationCount), n++) { 5417c478bd9Sstevel@tonic-gate if (!xml) (void) sprintf((path + bytes), "[%d]", n); 5427c478bd9Sstevel@tonic-gate print_element((data + i*iterlen), &newdef, path, 5437c478bd9Sstevel@tonic-gate indent); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if (xml) output("%*s</%s>\n", indent, "", path); 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate } else if (def->dataType == FDTYPE_Record) { 5497c478bd9Sstevel@tonic-gate const fru_regdef_t *component; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (xml) 5527c478bd9Sstevel@tonic-gate output("%*s<%s>\n", indent, "", path); 5537c478bd9Sstevel@tonic-gate else 5547c478bd9Sstevel@tonic-gate output("%*s%s\n", indent, "", path); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* 5577c478bd9Sstevel@tonic-gate * Print each component of the record 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate for (i = 0; i < def->enumCount; 5607c478bd9Sstevel@tonic-gate i++, data += component->payloadLen) { 5617c478bd9Sstevel@tonic-gate component = fru_reg_lookup_def_by_name( 5627c478bd9Sstevel@tonic-gate def->enumTable[i].text); 5637c478bd9Sstevel@tonic-gate assert(component != NULL); 5647c478bd9Sstevel@tonic-gate print_element(data, component, path, indent); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate if (xml) output("%*s</%s>\n", indent, "", path); 5687c478bd9Sstevel@tonic-gate } else if (xml) { 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * Base case: print the field formatted for XML 5717c478bd9Sstevel@tonic-gate */ 5727c478bd9Sstevel@tonic-gate char *format = ((def == &unknown) 5737c478bd9Sstevel@tonic-gate ? "%*s<UNKNOWN tag=\"%s\" value=\"" 5747c478bd9Sstevel@tonic-gate : "%*s<%s value=\""); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate output(format, indent, "", path); 5777c478bd9Sstevel@tonic-gate print_field(data, def); 5787c478bd9Sstevel@tonic-gate /*CSTYLED*/ 5797c478bd9Sstevel@tonic-gate output("\"/>\n"); /* \" confuses cstyle */ 5807c478bd9Sstevel@tonic-gate } else { 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * Base case: print the field 5837c478bd9Sstevel@tonic-gate */ 5847c478bd9Sstevel@tonic-gate output("%*s%s: ", indent, "", path); 5857c478bd9Sstevel@tonic-gate print_field(data, def); 5867c478bd9Sstevel@tonic-gate output("\n"); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * Print the contents of a packet (i.e., a tagged data element) 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5947c478bd9Sstevel@tonic-gate static int 5957c478bd9Sstevel@tonic-gate print_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate int tag_type = get_tag_type(tag); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate size_t payload_length = 0; 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate const fru_regdef_t *def; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Build a definition for unrecognized tags (e.g., not in libfrureg) 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate if ((tag_type == -1) || 6087c478bd9Sstevel@tonic-gate ((payload_length = get_payload_length(tag)) != length)) { 6097c478bd9Sstevel@tonic-gate def = &unknown; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate unknown.tagType = -1; 6127c478bd9Sstevel@tonic-gate unknown.tagDense = -1; 6137c478bd9Sstevel@tonic-gate unknown.payloadLen = length; 6147c478bd9Sstevel@tonic-gate unknown.dataLength = unknown.payloadLen; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate if (tag_type == -1) 6177c478bd9Sstevel@tonic-gate (void) snprintf(tagname, sizeof (tagname), "INVALID"); 6187c478bd9Sstevel@tonic-gate else 6197c478bd9Sstevel@tonic-gate (void) snprintf(tagname, sizeof (tagname), 6207c478bd9Sstevel@tonic-gate "%s_%u_%u_%u", get_tagtype_str(tag_type), 6217c478bd9Sstevel@tonic-gate get_tag_dense(tag), payload_length, length); 6227c478bd9Sstevel@tonic-gate } else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) { 6237c478bd9Sstevel@tonic-gate def = &unknown; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate unknown.tagType = tag_type; 6267c478bd9Sstevel@tonic-gate unknown.tagDense = get_tag_dense(tag); 6277c478bd9Sstevel@tonic-gate unknown.payloadLen = payload_length; 6287c478bd9Sstevel@tonic-gate unknown.dataLength = unknown.payloadLen; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate (void) snprintf(tagname, sizeof (tagname), "%s_%u_%u", 6317c478bd9Sstevel@tonic-gate get_tagtype_str(unknown.tagType), 6327c478bd9Sstevel@tonic-gate unknown.tagDense, payload_length); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate /* 6377c478bd9Sstevel@tonic-gate * Print the defined element 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate print_element(payload, def, "", INDENT); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * Print a segment's name and the contents of each data element in the segment 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate static int 6487c478bd9Sstevel@tonic-gate print_packets_in_segment(fru_seghdl_t segment, void *args) 6497c478bd9Sstevel@tonic-gate { 6507c478bd9Sstevel@tonic-gate char *name; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate int status; 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if ((status = fru_get_segment_name(segment, &name)) != FRU_SUCCESS) { 6567c478bd9Sstevel@tonic-gate saved_status = status; 6577c478bd9Sstevel@tonic-gate name = ""; 6587c478bd9Sstevel@tonic-gate error(gettext("Error getting segment name: %s\n"), 6597c478bd9Sstevel@tonic-gate fru_strerror(status)); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if (xml) 6647c478bd9Sstevel@tonic-gate output("%*s<Segment name=\"%s\">\n", INDENT, "", name); 6657c478bd9Sstevel@tonic-gate else 6667c478bd9Sstevel@tonic-gate output("%*sSEGMENT: %s\n", INDENT, "", name); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Iterate over the packets in the segment, printing the contents */ 6697c478bd9Sstevel@tonic-gate if ((status = fru_for_each_packet(segment, print_packet, args)) 6707c478bd9Sstevel@tonic-gate != FRU_SUCCESS) { 6717c478bd9Sstevel@tonic-gate saved_status = status; 6727c478bd9Sstevel@tonic-gate error(gettext("Error processing data in segment \"%s\": %s\n"), 6737c478bd9Sstevel@tonic-gate name, fru_strerror(status)); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if (xml) output("%*s</Segment>\n", INDENT, ""); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate free(name); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6847c478bd9Sstevel@tonic-gate static void 6857c478bd9Sstevel@tonic-gate print_node_path(fru_node_t fru_type, const char *path, const char *name, 6867c478bd9Sstevel@tonic-gate end_node_fp_t *end_node, void **end_args) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate output("%s%s\n", path, 6897c478bd9Sstevel@tonic-gate ((fru_type == FRU_NODE_CONTAINER) ? " (container)" 6907c478bd9Sstevel@tonic-gate : ((fru_type == FRU_NODE_FRU) ? " (fru)" : ""))); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * Close the XML element for a "location" node 6957c478bd9Sstevel@tonic-gate */ 6967c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6977c478bd9Sstevel@tonic-gate static void 6987c478bd9Sstevel@tonic-gate end_location_xml(fru_nodehdl_t node, const char *path, const char *name, 6997c478bd9Sstevel@tonic-gate void *args) 7007c478bd9Sstevel@tonic-gate { 7017c478bd9Sstevel@tonic-gate assert(args != NULL); 7027c478bd9Sstevel@tonic-gate output("</Location> <!-- %s -->\n", args); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * Close the XML element for a "fru" node 7077c478bd9Sstevel@tonic-gate */ 7087c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7097c478bd9Sstevel@tonic-gate static void 7107c478bd9Sstevel@tonic-gate end_fru_xml(fru_nodehdl_t node, const char *path, const char *name, void *args) 7117c478bd9Sstevel@tonic-gate { 7127c478bd9Sstevel@tonic-gate assert(args != NULL); 7137c478bd9Sstevel@tonic-gate output("</Fru> <!-- %s -->\n", args); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate /* 7177c478bd9Sstevel@tonic-gate * Close the XML element for a "container" node 7187c478bd9Sstevel@tonic-gate */ 7197c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7207c478bd9Sstevel@tonic-gate static void 7217c478bd9Sstevel@tonic-gate end_container_xml(fru_nodehdl_t node, const char *path, const char *name, 7227c478bd9Sstevel@tonic-gate void *args) 7237c478bd9Sstevel@tonic-gate { 7247c478bd9Sstevel@tonic-gate assert(args != NULL); 7257c478bd9Sstevel@tonic-gate output("</Container> <!-- %s -->\n", args); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate * Introduce a node in XML and set the appropriate node-closing function 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7327c478bd9Sstevel@tonic-gate static void 7337c478bd9Sstevel@tonic-gate print_node_xml(fru_node_t fru_type, const char *path, const char *name, 7347c478bd9Sstevel@tonic-gate end_node_fp_t *end_node, void **end_args) 7357c478bd9Sstevel@tonic-gate { 7367c478bd9Sstevel@tonic-gate switch (fru_type) { 7377c478bd9Sstevel@tonic-gate case FRU_NODE_FRU: 7387c478bd9Sstevel@tonic-gate output("<Fru name=\"%s\">\n", name); 7397c478bd9Sstevel@tonic-gate *end_node = end_fru_xml; 7407c478bd9Sstevel@tonic-gate break; 7417c478bd9Sstevel@tonic-gate case FRU_NODE_CONTAINER: 7427c478bd9Sstevel@tonic-gate output("<Container name=\"%s\">\n", name); 7437c478bd9Sstevel@tonic-gate *end_node = end_container_xml; 7447c478bd9Sstevel@tonic-gate break; 7457c478bd9Sstevel@tonic-gate default: 7467c478bd9Sstevel@tonic-gate output("<Location name=\"%s\">\n", name); 7477c478bd9Sstevel@tonic-gate *end_node = end_location_xml; 7487c478bd9Sstevel@tonic-gate break; 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate *end_args = (void *) name; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * Print node info and, where appropriate, node contents 7567c478bd9Sstevel@tonic-gate */ 7577c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7587c478bd9Sstevel@tonic-gate static fru_errno_t 7597c478bd9Sstevel@tonic-gate process_node(fru_nodehdl_t node, const char *path, const char *name, 7607c478bd9Sstevel@tonic-gate void *args, end_node_fp_t *end_node, void **end_args) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate int status; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate fru_node_t fru_type = FRU_NODE_UNKNOWN; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate if ((status = fru_get_node_type(node, &fru_type)) != FRU_SUCCESS) { 7687c478bd9Sstevel@tonic-gate saved_status = status; 7697c478bd9Sstevel@tonic-gate error(gettext("Error getting node type: %s\n"), 7707c478bd9Sstevel@tonic-gate fru_strerror(status)); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if (containers_only) { 7747c478bd9Sstevel@tonic-gate if (fru_type != FRU_NODE_CONTAINER) 7757c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 7767c478bd9Sstevel@tonic-gate name = path; 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* Introduce the node */ 7807c478bd9Sstevel@tonic-gate assert(print_node != NULL); 7817c478bd9Sstevel@tonic-gate print_node(fru_type, path, name, end_node, end_args); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if (list_only) 7847c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate /* Print the contents of each packet in each segment of a container */ 7877c478bd9Sstevel@tonic-gate if (fru_type == FRU_NODE_CONTAINER) { 7887c478bd9Sstevel@tonic-gate if (xml) output("<ContainerData>\n"); 7897c478bd9Sstevel@tonic-gate if ((status = 7907c478bd9Sstevel@tonic-gate fru_for_each_segment(node, print_packets_in_segment, 7917c478bd9Sstevel@tonic-gate NULL)) 7927c478bd9Sstevel@tonic-gate != FRU_SUCCESS) { 7937c478bd9Sstevel@tonic-gate saved_status = status; 7947c478bd9Sstevel@tonic-gate error(gettext("Error processing node \"%s\": %s\n"), 7957c478bd9Sstevel@tonic-gate name, fru_strerror(status)); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate if (xml) output("</ContainerData>\n"); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate /* 8047c478bd9Sstevel@tonic-gate * Process the node if its path matches the search path in "args" 8057c478bd9Sstevel@tonic-gate */ 8067c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8077c478bd9Sstevel@tonic-gate static fru_errno_t 8087c478bd9Sstevel@tonic-gate process_matching_node(fru_nodehdl_t node, const char *path, const char *name, 8097c478bd9Sstevel@tonic-gate void *args, end_node_fp_t *end_node, void **end_args) 8107c478bd9Sstevel@tonic-gate { 8117c478bd9Sstevel@tonic-gate int status; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate if (!fru_pathmatch(path, args)) 8157c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate status = process_node(node, path, path, args, end_node, end_args); 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate return ((status == FRU_SUCCESS) ? FRU_WALK_TERMINATE : status); 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * Write the trailer required for well-formed DTD-compliant XML 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate static void 8267c478bd9Sstevel@tonic-gate terminate_xml() 8277c478bd9Sstevel@tonic-gate { 8287c478bd9Sstevel@tonic-gate errno = 0; 8297c478bd9Sstevel@tonic-gate if (ftell(errlog) > 0) { 8307c478bd9Sstevel@tonic-gate char c; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate output("<ErrorLog>\n"); 8337c478bd9Sstevel@tonic-gate rewind(errlog); 8347c478bd9Sstevel@tonic-gate if (!errno) 8357c478bd9Sstevel@tonic-gate while ((c = getc(errlog)) != EOF) 8367c478bd9Sstevel@tonic-gate xputchar(c); 8377c478bd9Sstevel@tonic-gate output("</ErrorLog>\n"); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (errno) { 8417c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 8427c478bd9Sstevel@tonic-gate errlog = NULL; 8437c478bd9Sstevel@tonic-gate error(gettext("Error copying error messages to \"ErrorLog\""), 8447c478bd9Sstevel@tonic-gate strerror(errno)); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate output("</FRUID_XML_Tree>\n"); 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate /* 8517c478bd9Sstevel@tonic-gate * Print available FRU ID information 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate int 8547c478bd9Sstevel@tonic-gate prtfru(const char *searchpath, int containers_only_flag, int list_only_flag, 8557c478bd9Sstevel@tonic-gate int xml_flag) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate fru_errno_t status; 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate fru_nodehdl_t frutree = 0; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate /* Copy parameter flags to global flags */ 8637c478bd9Sstevel@tonic-gate containers_only = containers_only_flag; 8647c478bd9Sstevel@tonic-gate list_only = list_only_flag; 8657c478bd9Sstevel@tonic-gate xml = xml_flag; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* Help arrange for correct, efficient interleaving of output */ 8697c478bd9Sstevel@tonic-gate (void) setvbuf(stderr, NULL, _IOLBF, 0); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* Initialize for XML--or not */ 8737c478bd9Sstevel@tonic-gate if (xml) { 8747c478bd9Sstevel@tonic-gate safeputchar = xputchar; 8757c478bd9Sstevel@tonic-gate safeputs = xputs; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate print_node = print_node_xml; 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate if ((errlog = tmpfile()) == NULL) { 8807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8817c478bd9Sstevel@tonic-gate "Error creating error log file: %s\n", 8827c478bd9Sstevel@tonic-gate strerror(errno)); 8837c478bd9Sstevel@tonic-gate return (1); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* Output the XML preamble */ 8877c478bd9Sstevel@tonic-gate output("<?xml version=\"1.0\" ?>\n" 8887c478bd9Sstevel@tonic-gate "<!--\n" 8897c478bd9Sstevel@tonic-gate " Copyright 2000-2002 Sun Microsystems, Inc. " 8907c478bd9Sstevel@tonic-gate "All rights reserved.\n" 8917c478bd9Sstevel@tonic-gate " Use is subject to license terms.\n" 8927c478bd9Sstevel@tonic-gate "-->\n\n" 8937c478bd9Sstevel@tonic-gate "<!DOCTYPE FRUID_XML_Tree SYSTEM \"prtfrureg.dtd\">\n\n" 8947c478bd9Sstevel@tonic-gate "<FRUID_XML_Tree>\n"); 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate /* Arrange to always properly terminate XML */ 8977c478bd9Sstevel@tonic-gate if (atexit(terminate_xml)) 8987c478bd9Sstevel@tonic-gate error(gettext("Warning: XML will not be terminated: " 8997c478bd9Sstevel@tonic-gate "%s\n"), strerror(errno)); 9007c478bd9Sstevel@tonic-gate } else 9017c478bd9Sstevel@tonic-gate print_node = print_node_path; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* Get the root node */ 9057c478bd9Sstevel@tonic-gate if ((status = fru_get_root(&frutree)) == FRU_NODENOTFOUND) { 9067c478bd9Sstevel@tonic-gate error(gettext("This system does not provide FRU ID data\n")); 9077c478bd9Sstevel@tonic-gate return (1); 9087c478bd9Sstevel@tonic-gate } else if (status != FRU_SUCCESS) { 9097c478bd9Sstevel@tonic-gate error(gettext("Unable to access FRU ID data: %s\n"), 9107c478bd9Sstevel@tonic-gate fru_strerror(status)); 9117c478bd9Sstevel@tonic-gate return (1); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* Process the tree */ 9157c478bd9Sstevel@tonic-gate if (searchpath == NULL) { 9167c478bd9Sstevel@tonic-gate status = fru_walk_tree(frutree, "", process_node, NULL); 9177c478bd9Sstevel@tonic-gate } else { 9187c478bd9Sstevel@tonic-gate status = fru_walk_tree(frutree, "", process_matching_node, 9197c478bd9Sstevel@tonic-gate (void *)searchpath); 9207c478bd9Sstevel@tonic-gate if (status == FRU_WALK_TERMINATE) { 9217c478bd9Sstevel@tonic-gate status = FRU_SUCCESS; 9227c478bd9Sstevel@tonic-gate } else if (status == FRU_SUCCESS) { 9237c478bd9Sstevel@tonic-gate error(gettext("\"%s\" not found\n"), searchpath); 9247c478bd9Sstevel@tonic-gate return (1); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate if (status != FRU_SUCCESS) 9297c478bd9Sstevel@tonic-gate error(gettext("Error processing FRU tree: %s\n"), 9307c478bd9Sstevel@tonic-gate fru_strerror(status)); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate return (((status == FRU_SUCCESS) && (saved_status == 0)) ? 0 : 1); 9337c478bd9Sstevel@tonic-gate } 934