1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <alloca.h> 30*7c478bd9Sstevel@tonic-gate #include <assert.h> 31*7c478bd9Sstevel@tonic-gate #include <errno.h> 32*7c478bd9Sstevel@tonic-gate #include <libintl.h> 33*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 34*7c478bd9Sstevel@tonic-gate #include <stdio.h> 35*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 36*7c478bd9Sstevel@tonic-gate #include <string.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "fru_tag.h" 39*7c478bd9Sstevel@tonic-gate #include "libfrup.h" 40*7c478bd9Sstevel@tonic-gate #include "libfrureg.h" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #define NUM_ITER_BYTES 4 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate #define HEAD_ITER 0 46*7c478bd9Sstevel@tonic-gate #define TAIL_ITER 1 /* not used */ 47*7c478bd9Sstevel@tonic-gate #define NUM_ITER 2 48*7c478bd9Sstevel@tonic-gate #define MAX_ITER 3 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #define INDENT 3 51*7c478bd9Sstevel@tonic-gate #define TIMESTRINGLEN 128 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate static void (*print_node)(fru_node_t fru_type, const char *path, 55*7c478bd9Sstevel@tonic-gate const char *name, end_node_fp_t *end_node, 56*7c478bd9Sstevel@tonic-gate void **end_args); 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate static char tagname[sizeof ("?_0123456789_0123456789_0123456789")]; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate static int containers_only = 0, list_only = 0, saved_status = 0, xml = 0; 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate static FILE *errlog; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Definition for data elements found in devices but not found in 66*7c478bd9Sstevel@tonic-gate * the system's version of libfrureg 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate static fru_regdef_t unknown = { 69*7c478bd9Sstevel@tonic-gate REGDEF_VERSION, 70*7c478bd9Sstevel@tonic-gate tagname, 71*7c478bd9Sstevel@tonic-gate -1, 72*7c478bd9Sstevel@tonic-gate -1, 73*7c478bd9Sstevel@tonic-gate -1, 74*7c478bd9Sstevel@tonic-gate -1, 75*7c478bd9Sstevel@tonic-gate FDTYPE_ByteArray, 76*7c478bd9Sstevel@tonic-gate FDISP_Hex, 77*7c478bd9Sstevel@tonic-gate FRU_WHICH_UNDEFINED, 78*7c478bd9Sstevel@tonic-gate FRU_WHICH_UNDEFINED, 79*7c478bd9Sstevel@tonic-gate 0, 80*7c478bd9Sstevel@tonic-gate NULL, 81*7c478bd9Sstevel@tonic-gate 0, 82*7c478bd9Sstevel@tonic-gate FRU_NOT_ITERATED, 83*7c478bd9Sstevel@tonic-gate NULL 84*7c478bd9Sstevel@tonic-gate }; 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 88*7c478bd9Sstevel@tonic-gate * Write message to standard error and possibly the error log buffer 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate static void 91*7c478bd9Sstevel@tonic-gate error(const char *format, ...) 92*7c478bd9Sstevel@tonic-gate { 93*7c478bd9Sstevel@tonic-gate va_list args; 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* make relevant output appear before error message */ 97*7c478bd9Sstevel@tonic-gate if (fflush(stdout) == EOF) { 98*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Error flushing output: %s\n", 99*7c478bd9Sstevel@tonic-gate strerror(errno)); 100*7c478bd9Sstevel@tonic-gate exit(1); 101*7c478bd9Sstevel@tonic-gate } 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate va_start(args, format); 104*7c478bd9Sstevel@tonic-gate if (vfprintf(stderr, format, args) < 0) exit(1); 105*7c478bd9Sstevel@tonic-gate if (errlog && (vfprintf(errlog, format, args) < 0)) exit(1); 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate /* 109*7c478bd9Sstevel@tonic-gate * Write message to standard output 110*7c478bd9Sstevel@tonic-gate */ 111*7c478bd9Sstevel@tonic-gate static void 112*7c478bd9Sstevel@tonic-gate output(const char *format, ...) 113*7c478bd9Sstevel@tonic-gate { 114*7c478bd9Sstevel@tonic-gate va_list args; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate va_start(args, format); 118*7c478bd9Sstevel@tonic-gate if (vfprintf(stdout, format, args) < 0) { 119*7c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 120*7c478bd9Sstevel@tonic-gate strerror(errno)); 121*7c478bd9Sstevel@tonic-gate exit(1); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate * Safe wrapper for putchar() 127*7c478bd9Sstevel@tonic-gate */ 128*7c478bd9Sstevel@tonic-gate static void 129*7c478bd9Sstevel@tonic-gate voidputchar(int c) 130*7c478bd9Sstevel@tonic-gate { 131*7c478bd9Sstevel@tonic-gate if (putchar(c) == EOF) { 132*7c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 133*7c478bd9Sstevel@tonic-gate strerror(errno)); 134*7c478bd9Sstevel@tonic-gate exit(1); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate static void (*safeputchar)(int c) = voidputchar; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate * Safe wrapper for puts() 142*7c478bd9Sstevel@tonic-gate */ 143*7c478bd9Sstevel@tonic-gate static void 144*7c478bd9Sstevel@tonic-gate voidputs(const char *s) 145*7c478bd9Sstevel@tonic-gate { 146*7c478bd9Sstevel@tonic-gate if (fputs(s, stdout) == EOF) { 147*7c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 148*7c478bd9Sstevel@tonic-gate strerror(errno)); 149*7c478bd9Sstevel@tonic-gate exit(1); 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate static void (*safeputs)(const char *s) = voidputs; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* 156*7c478bd9Sstevel@tonic-gate * XML-safe wrapper for putchar(): quotes XML-special characters 157*7c478bd9Sstevel@tonic-gate */ 158*7c478bd9Sstevel@tonic-gate static void 159*7c478bd9Sstevel@tonic-gate xputchar(int c) 160*7c478bd9Sstevel@tonic-gate { 161*7c478bd9Sstevel@tonic-gate switch (c) { 162*7c478bd9Sstevel@tonic-gate case '<': 163*7c478bd9Sstevel@tonic-gate c = fputs("<", stdout); 164*7c478bd9Sstevel@tonic-gate break; 165*7c478bd9Sstevel@tonic-gate case '>': 166*7c478bd9Sstevel@tonic-gate c = fputs(">", stdout); 167*7c478bd9Sstevel@tonic-gate break; 168*7c478bd9Sstevel@tonic-gate case '&': 169*7c478bd9Sstevel@tonic-gate c = fputs("&", stdout); 170*7c478bd9Sstevel@tonic-gate break; 171*7c478bd9Sstevel@tonic-gate case '"': 172*7c478bd9Sstevel@tonic-gate c = fputs(""", stdout); 173*7c478bd9Sstevel@tonic-gate break; 174*7c478bd9Sstevel@tonic-gate default: 175*7c478bd9Sstevel@tonic-gate c = putchar(c); 176*7c478bd9Sstevel@tonic-gate break; 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate if (c == EOF) { 180*7c478bd9Sstevel@tonic-gate error(gettext("Error writing output: %s\n"), 181*7c478bd9Sstevel@tonic-gate strerror(errno)); 182*7c478bd9Sstevel@tonic-gate exit(1); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * XML-safe analog of puts(): quotes XML-special characters 188*7c478bd9Sstevel@tonic-gate */ 189*7c478bd9Sstevel@tonic-gate static void 190*7c478bd9Sstevel@tonic-gate xputs(const char *s) 191*7c478bd9Sstevel@tonic-gate { 192*7c478bd9Sstevel@tonic-gate char c; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate for (/* */; ((c = *s) != 0); s++) 195*7c478bd9Sstevel@tonic-gate xputchar(c); 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* 199*7c478bd9Sstevel@tonic-gate * Output the XML DTD derived from the registry provided by libfrureg 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate int 202*7c478bd9Sstevel@tonic-gate output_dtd(void) 203*7c478bd9Sstevel@tonic-gate { 204*7c478bd9Sstevel@tonic-gate char **element; 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate unsigned int i, j, num_elements = 0; 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate uint8_t *tagged; 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate const fru_regdef_t *def; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate if (((element = fru_reg_list_entries(&num_elements)) == NULL) || 214*7c478bd9Sstevel@tonic-gate (num_elements == 0)) { 215*7c478bd9Sstevel@tonic-gate error(gettext("No FRU ID Registry elements")); 216*7c478bd9Sstevel@tonic-gate return (1); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate if ((tagged = calloc(num_elements, sizeof (*tagged))) == NULL) { 220*7c478bd9Sstevel@tonic-gate error(gettext("Unable to get memory for tagged element list"), 221*7c478bd9Sstevel@tonic-gate strerror(errno)); 222*7c478bd9Sstevel@tonic-gate return (1); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * Output the DTD preamble 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate output("<!ELEMENT FRUID_XML_Tree (Parameter*, " 229*7c478bd9Sstevel@tonic-gate "(Fru | Location | Container)*,\n" 230*7c478bd9Sstevel@tonic-gate " Parameter*, ErrorLog?, Parameter*)>\n" 231*7c478bd9Sstevel@tonic-gate "<!ATTLIST FRUID_XML_Tree>\n" 232*7c478bd9Sstevel@tonic-gate "\n" 233*7c478bd9Sstevel@tonic-gate "<!ELEMENT Parameter EMPTY>\n" 234*7c478bd9Sstevel@tonic-gate "<!ATTLIST Parameter type CDATA #REQUIRED>\n" 235*7c478bd9Sstevel@tonic-gate "<!ATTLIST Parameter name CDATA #REQUIRED>\n" 236*7c478bd9Sstevel@tonic-gate "<!ATTLIST Parameter value CDATA #REQUIRED>\n" 237*7c478bd9Sstevel@tonic-gate "\n" 238*7c478bd9Sstevel@tonic-gate "<!ELEMENT Fru (Fru | Location | Container)*>\n" 239*7c478bd9Sstevel@tonic-gate "<!ATTLIST Fru name CDATA #REQUIRED>\n" 240*7c478bd9Sstevel@tonic-gate "\n" 241*7c478bd9Sstevel@tonic-gate "<!ELEMENT Location (Fru | Location | Container)*>\n" 242*7c478bd9Sstevel@tonic-gate "<!ATTLIST Location name CDATA #REQUIRED>\n" 243*7c478bd9Sstevel@tonic-gate "\n" 244*7c478bd9Sstevel@tonic-gate "<!ELEMENT Container (ContainerData?, " 245*7c478bd9Sstevel@tonic-gate "(Fru | Location | Container)*)>\n" 246*7c478bd9Sstevel@tonic-gate "<!ATTLIST Container name CDATA #REQUIRED>\n" 247*7c478bd9Sstevel@tonic-gate "<!ATTLIST Container imagefile CDATA #IMPLIED>\n" 248*7c478bd9Sstevel@tonic-gate "\n" 249*7c478bd9Sstevel@tonic-gate "<!ELEMENT ContainerData (Segment*)>\n" 250*7c478bd9Sstevel@tonic-gate "<!ATTLIST ContainerData>\n" 251*7c478bd9Sstevel@tonic-gate "\n" 252*7c478bd9Sstevel@tonic-gate "<!ATTLIST Segment name CDATA #REQUIRED>\n" 253*7c478bd9Sstevel@tonic-gate "\n" 254*7c478bd9Sstevel@tonic-gate "<!ELEMENT Index EMPTY>\n" 255*7c478bd9Sstevel@tonic-gate "<!ATTLIST Index value CDATA #REQUIRED>\n" 256*7c478bd9Sstevel@tonic-gate "\n" 257*7c478bd9Sstevel@tonic-gate "<!ELEMENT ErrorLog (#PCDATA)>\n" 258*7c478bd9Sstevel@tonic-gate "<!ATTLIST ErrorLog>\n" 259*7c478bd9Sstevel@tonic-gate "\n"); 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate /* 262*7c478bd9Sstevel@tonic-gate * Output the definition for each element 263*7c478bd9Sstevel@tonic-gate */ 264*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_elements; i++) { 265*7c478bd9Sstevel@tonic-gate assert(element[i] != NULL); 266*7c478bd9Sstevel@tonic-gate if ((def = fru_reg_lookup_def_by_name(element[i])) == NULL) { 267*7c478bd9Sstevel@tonic-gate error(gettext("Error looking up registry " 268*7c478bd9Sstevel@tonic-gate "definition for \"%s\"\n"), 269*7c478bd9Sstevel@tonic-gate element[i]); 270*7c478bd9Sstevel@tonic-gate return (1); 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate if (def->tagType != FRU_X) tagged[i] = 1; 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate if (def->dataType == FDTYPE_Record) { 276*7c478bd9Sstevel@tonic-gate if (def->iterationType == FRU_NOT_ITERATED) 277*7c478bd9Sstevel@tonic-gate output("<!ELEMENT %s (%s", element[i], 278*7c478bd9Sstevel@tonic-gate def->enumTable[0].text); 279*7c478bd9Sstevel@tonic-gate else 280*7c478bd9Sstevel@tonic-gate output("<!ELEMENT %s (Index_%s*)>\n" 281*7c478bd9Sstevel@tonic-gate "<!ATTLIST Index_%s>\n" 282*7c478bd9Sstevel@tonic-gate "<!ELEMENT Index_%s (%s", 283*7c478bd9Sstevel@tonic-gate element[i], element[i], element[i], 284*7c478bd9Sstevel@tonic-gate element[i], def->enumTable[0].text); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate for (j = 1; j < def->enumCount; j++) 287*7c478bd9Sstevel@tonic-gate output(",\n\t%s", def->enumTable[j].text); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate output(")>\n"); 290*7c478bd9Sstevel@tonic-gate } else if (def->iterationType == FRU_NOT_ITERATED) { 291*7c478bd9Sstevel@tonic-gate output("<!ELEMENT %s EMPTY>\n" 292*7c478bd9Sstevel@tonic-gate "<!ATTLIST %s value CDATA #REQUIRED>\n", 293*7c478bd9Sstevel@tonic-gate element[i], element[i]); 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate if (def->dataType == FDTYPE_Enumeration) { 296*7c478bd9Sstevel@tonic-gate output("<!-- %s valid enumeration values\n"); 297*7c478bd9Sstevel@tonic-gate for (j = 0; j < def->enumCount; j++) { 298*7c478bd9Sstevel@tonic-gate output("\t\""); 299*7c478bd9Sstevel@tonic-gate xputs(def->enumTable[j].text); 300*7c478bd9Sstevel@tonic-gate output("\"\n"); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate output("-->\n"); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate else 306*7c478bd9Sstevel@tonic-gate output("<!ELEMENT %s (Index*)>\n", element[i]); 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate output("\n"); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate /* Provide for returning the tag for an "unknown" element */ 312*7c478bd9Sstevel@tonic-gate output("<!ATTLIST UNKNOWN tag CDATA \"UNKNOWN\">\n\n"); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * List all data elements as possible members of "Segment" 317*7c478bd9Sstevel@tonic-gate */ 318*7c478bd9Sstevel@tonic-gate output("<!ELEMENT Segment ((UNKNOWN"); 319*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_elements; i++) { 320*7c478bd9Sstevel@tonic-gate if (tagged[i]) output("\n\t| %s", element[i]); 321*7c478bd9Sstevel@tonic-gate free(element[i]); 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate output(")*)>\n"); 324*7c478bd9Sstevel@tonic-gate free(element); 325*7c478bd9Sstevel@tonic-gate free(tagged); 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate return (0); 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /* 331*7c478bd9Sstevel@tonic-gate * Safely pretty-print the value of a field 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate static void 334*7c478bd9Sstevel@tonic-gate print_field(const uint8_t *field, const fru_regdef_t *def) 335*7c478bd9Sstevel@tonic-gate { 336*7c478bd9Sstevel@tonic-gate char *errmsg = NULL, timestring[TIMESTRINGLEN]; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate int i; 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate uint64_t value; 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate time_t timefield; 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate switch (def->dataType) { 346*7c478bd9Sstevel@tonic-gate case FDTYPE_Binary: 347*7c478bd9Sstevel@tonic-gate assert(def->payloadLen <= sizeof (value)); 348*7c478bd9Sstevel@tonic-gate switch (def->dispType) { 349*7c478bd9Sstevel@tonic-gate case FDISP_Binary: 350*7c478bd9Sstevel@tonic-gate for (i = 0; i < def->payloadLen; i++) 351*7c478bd9Sstevel@tonic-gate output("%c%c%c%c%c%c%c%c", 352*7c478bd9Sstevel@tonic-gate ((field[i] & 0x80) ? '1' : '0'), 353*7c478bd9Sstevel@tonic-gate ((field[i] & 0x40) ? '1' : '0'), 354*7c478bd9Sstevel@tonic-gate ((field[i] & 0x20) ? '1' : '0'), 355*7c478bd9Sstevel@tonic-gate ((field[i] & 0x10) ? '1' : '0'), 356*7c478bd9Sstevel@tonic-gate ((field[i] & 0x08) ? '1' : '0'), 357*7c478bd9Sstevel@tonic-gate ((field[i] & 0x04) ? '1' : '0'), 358*7c478bd9Sstevel@tonic-gate ((field[i] & 0x02) ? '1' : '0'), 359*7c478bd9Sstevel@tonic-gate ((field[i] & 0x01) ? '1' : '0')); 360*7c478bd9Sstevel@tonic-gate return; 361*7c478bd9Sstevel@tonic-gate case FDISP_Octal: 362*7c478bd9Sstevel@tonic-gate case FDISP_Decimal: 363*7c478bd9Sstevel@tonic-gate value = 0; 364*7c478bd9Sstevel@tonic-gate (void) memcpy((((uint8_t *)&value) + 365*7c478bd9Sstevel@tonic-gate sizeof (value) - def->payloadLen), 366*7c478bd9Sstevel@tonic-gate field, def->payloadLen); 367*7c478bd9Sstevel@tonic-gate output((def->dispType == FDISP_Octal) ? 368*7c478bd9Sstevel@tonic-gate "%llo" : "%lld", value); 369*7c478bd9Sstevel@tonic-gate return; 370*7c478bd9Sstevel@tonic-gate case FDISP_Time: 371*7c478bd9Sstevel@tonic-gate if (def->payloadLen > sizeof (timefield)) { 372*7c478bd9Sstevel@tonic-gate errmsg = "time value too large for formatting"; 373*7c478bd9Sstevel@tonic-gate break; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate (void) memcpy(&timefield, field, sizeof (timefield)); 376*7c478bd9Sstevel@tonic-gate if (strftime(timestring, sizeof (timestring), "%C", 377*7c478bd9Sstevel@tonic-gate localtime(&timefield)) == 0) { 378*7c478bd9Sstevel@tonic-gate errmsg = "formatted time would overflow buffer"; 379*7c478bd9Sstevel@tonic-gate break; 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate safeputs(timestring); 382*7c478bd9Sstevel@tonic-gate return; 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate break; 385*7c478bd9Sstevel@tonic-gate case FDTYPE_ASCII: 386*7c478bd9Sstevel@tonic-gate for (i = 0; i < def->payloadLen && field[i]; i++) 387*7c478bd9Sstevel@tonic-gate safeputchar(field[i]); 388*7c478bd9Sstevel@tonic-gate return; 389*7c478bd9Sstevel@tonic-gate case FDTYPE_Enumeration: 390*7c478bd9Sstevel@tonic-gate value = 0; 391*7c478bd9Sstevel@tonic-gate (void) memcpy((((uint8_t *)&value) + sizeof (value) 392*7c478bd9Sstevel@tonic-gate - def->payloadLen), 393*7c478bd9Sstevel@tonic-gate field, def->payloadLen); 394*7c478bd9Sstevel@tonic-gate for (i = 0; i < def->enumCount; i++) 395*7c478bd9Sstevel@tonic-gate if (def->enumTable[i].value == value) { 396*7c478bd9Sstevel@tonic-gate safeputs(def->enumTable[i].text); 397*7c478bd9Sstevel@tonic-gate return; 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate errmsg = "unrecognized value"; 401*7c478bd9Sstevel@tonic-gate break; 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate /* If nothing matched above, print the field in hex */ 405*7c478bd9Sstevel@tonic-gate for (i = 0; i < def->payloadLen; i++) 406*7c478bd9Sstevel@tonic-gate output("%2.2X", field[i]); 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* Safely print any error message associated with the field */ 409*7c478bd9Sstevel@tonic-gate if (errmsg) { 410*7c478bd9Sstevel@tonic-gate output(" ("); 411*7c478bd9Sstevel@tonic-gate safeputs(errmsg); 412*7c478bd9Sstevel@tonic-gate output(")\n"); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * Recursively print the contents of a data element 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate static void 420*7c478bd9Sstevel@tonic-gate print_element(const uint8_t *data, const fru_regdef_t *def, 421*7c478bd9Sstevel@tonic-gate const char *parent_path, int indent) 422*7c478bd9Sstevel@tonic-gate { 423*7c478bd9Sstevel@tonic-gate char *path; 424*7c478bd9Sstevel@tonic-gate size_t len; 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate int bytes = 0, i; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate indent = (xml) ? (indent + INDENT) : (2*INDENT); 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate /* 432*7c478bd9Sstevel@tonic-gate * Construct the path, or, for XML, the name, for the current 433*7c478bd9Sstevel@tonic-gate * data element 434*7c478bd9Sstevel@tonic-gate */ 435*7c478bd9Sstevel@tonic-gate if ((def->iterationCount == 0) && 436*7c478bd9Sstevel@tonic-gate (def->iterationType != FRU_NOT_ITERATED)) { 437*7c478bd9Sstevel@tonic-gate if (xml) { 438*7c478bd9Sstevel@tonic-gate if (def->dataType == FDTYPE_Record) { 439*7c478bd9Sstevel@tonic-gate len = strlen("Index_") + strlen(def->name) + 1; 440*7c478bd9Sstevel@tonic-gate path = alloca(len); 441*7c478bd9Sstevel@tonic-gate (void) snprintf(path, len, 442*7c478bd9Sstevel@tonic-gate "Index_%s", def->name); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate else 445*7c478bd9Sstevel@tonic-gate path = "Index"; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate else 448*7c478bd9Sstevel@tonic-gate path = (char *)parent_path; 449*7c478bd9Sstevel@tonic-gate } else { 450*7c478bd9Sstevel@tonic-gate if (xml) 451*7c478bd9Sstevel@tonic-gate path = (char *)def->name; 452*7c478bd9Sstevel@tonic-gate else { 453*7c478bd9Sstevel@tonic-gate len = strlen(parent_path) + sizeof ("/") + 454*7c478bd9Sstevel@tonic-gate strlen(def->name) + 455*7c478bd9Sstevel@tonic-gate (def->iterationCount ? sizeof ("[255]") : 0); 456*7c478bd9Sstevel@tonic-gate path = alloca(len); 457*7c478bd9Sstevel@tonic-gate bytes = snprintf(path, len, 458*7c478bd9Sstevel@tonic-gate "%s/%s", parent_path, def->name); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* 463*7c478bd9Sstevel@tonic-gate * Handle the various categories of data elements: iteration, 464*7c478bd9Sstevel@tonic-gate * record, and field 465*7c478bd9Sstevel@tonic-gate */ 466*7c478bd9Sstevel@tonic-gate if (def->iterationCount) { 467*7c478bd9Sstevel@tonic-gate int iterlen = (def->payloadLen - NUM_ITER_BYTES)/ 468*7c478bd9Sstevel@tonic-gate def->iterationCount, 469*7c478bd9Sstevel@tonic-gate n, valid = 1; 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate uint8_t head, num; 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate fru_regdef_t newdef; 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate /* 477*7c478bd9Sstevel@tonic-gate * Make a new element definition to describe the components 478*7c478bd9Sstevel@tonic-gate * of the iteration 479*7c478bd9Sstevel@tonic-gate */ 480*7c478bd9Sstevel@tonic-gate (void) memcpy(&newdef, def, sizeof (newdef)); 481*7c478bd9Sstevel@tonic-gate newdef.iterationCount = 0; 482*7c478bd9Sstevel@tonic-gate newdef.payloadLen = iterlen; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate /* 485*7c478bd9Sstevel@tonic-gate * Validate the contents of the iteration control bytes 486*7c478bd9Sstevel@tonic-gate */ 487*7c478bd9Sstevel@tonic-gate if (data[HEAD_ITER] >= def->iterationCount) { 488*7c478bd9Sstevel@tonic-gate valid = 0; 489*7c478bd9Sstevel@tonic-gate error(gettext("%s: Invalid iteration head: %d " 490*7c478bd9Sstevel@tonic-gate "(should be less than %d)\n"), 491*7c478bd9Sstevel@tonic-gate path, data[HEAD_ITER], def->iterationCount); 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate if (data[NUM_ITER] > def->iterationCount) { 495*7c478bd9Sstevel@tonic-gate valid = 0; 496*7c478bd9Sstevel@tonic-gate error(gettext("%s: Invalid iteration count: %d " 497*7c478bd9Sstevel@tonic-gate "(should not be greater than %d)\n"), 498*7c478bd9Sstevel@tonic-gate path, data[NUM_ITER], def->iterationCount); 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate if (data[MAX_ITER] != def->iterationCount) { 502*7c478bd9Sstevel@tonic-gate valid = 0; 503*7c478bd9Sstevel@tonic-gate error(gettext("%s: Invalid iteration maximum: %d " 504*7c478bd9Sstevel@tonic-gate "(should equal %d)\n"), 505*7c478bd9Sstevel@tonic-gate path, data[MAX_ITER], def->iterationCount); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate if (valid) { 509*7c478bd9Sstevel@tonic-gate head = data[HEAD_ITER]; 510*7c478bd9Sstevel@tonic-gate num = data[NUM_ITER]; 511*7c478bd9Sstevel@tonic-gate } else { 512*7c478bd9Sstevel@tonic-gate head = 0; 513*7c478bd9Sstevel@tonic-gate num = def->iterationCount; 514*7c478bd9Sstevel@tonic-gate error(gettext("%s: Showing all iterations\n"), path); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate if (xml) 518*7c478bd9Sstevel@tonic-gate output("%*s<%s>\n", indent, "", path); 519*7c478bd9Sstevel@tonic-gate else 520*7c478bd9Sstevel@tonic-gate output("%*s%s (%d iterations)\n", indent, "", path, 521*7c478bd9Sstevel@tonic-gate num); 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * Print each component of the iteration 525*7c478bd9Sstevel@tonic-gate */ 526*7c478bd9Sstevel@tonic-gate for (i = head, n = 0, data += 4; 527*7c478bd9Sstevel@tonic-gate n < num; 528*7c478bd9Sstevel@tonic-gate i = ((i + 1) % def->iterationCount), n++) { 529*7c478bd9Sstevel@tonic-gate if (!xml) (void) sprintf((path + bytes), "[%d]", n); 530*7c478bd9Sstevel@tonic-gate print_element((data + i*iterlen), &newdef, path, 531*7c478bd9Sstevel@tonic-gate indent); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate if (xml) output("%*s</%s>\n", indent, "", path); 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate } else if (def->dataType == FDTYPE_Record) { 537*7c478bd9Sstevel@tonic-gate const fru_regdef_t *component; 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate if (xml) 540*7c478bd9Sstevel@tonic-gate output("%*s<%s>\n", indent, "", path); 541*7c478bd9Sstevel@tonic-gate else 542*7c478bd9Sstevel@tonic-gate output("%*s%s\n", indent, "", path); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* 545*7c478bd9Sstevel@tonic-gate * Print each component of the record 546*7c478bd9Sstevel@tonic-gate */ 547*7c478bd9Sstevel@tonic-gate for (i = 0; i < def->enumCount; 548*7c478bd9Sstevel@tonic-gate i++, data += component->payloadLen) { 549*7c478bd9Sstevel@tonic-gate component = fru_reg_lookup_def_by_name( 550*7c478bd9Sstevel@tonic-gate def->enumTable[i].text); 551*7c478bd9Sstevel@tonic-gate assert(component != NULL); 552*7c478bd9Sstevel@tonic-gate print_element(data, component, path, indent); 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate if (xml) output("%*s</%s>\n", indent, "", path); 556*7c478bd9Sstevel@tonic-gate } else if (xml) { 557*7c478bd9Sstevel@tonic-gate /* 558*7c478bd9Sstevel@tonic-gate * Base case: print the field formatted for XML 559*7c478bd9Sstevel@tonic-gate */ 560*7c478bd9Sstevel@tonic-gate char *format = ((def == &unknown) 561*7c478bd9Sstevel@tonic-gate ? "%*s<UNKNOWN tag=\"%s\" value=\"" 562*7c478bd9Sstevel@tonic-gate : "%*s<%s value=\""); 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate output(format, indent, "", path); 565*7c478bd9Sstevel@tonic-gate print_field(data, def); 566*7c478bd9Sstevel@tonic-gate /*CSTYLED*/ 567*7c478bd9Sstevel@tonic-gate output("\"/>\n"); /* \" confuses cstyle */ 568*7c478bd9Sstevel@tonic-gate } else { 569*7c478bd9Sstevel@tonic-gate /* 570*7c478bd9Sstevel@tonic-gate * Base case: print the field 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate output("%*s%s: ", indent, "", path); 573*7c478bd9Sstevel@tonic-gate print_field(data, def); 574*7c478bd9Sstevel@tonic-gate output("\n"); 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * Print the contents of a packet (i.e., a tagged data element) 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 582*7c478bd9Sstevel@tonic-gate static int 583*7c478bd9Sstevel@tonic-gate print_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args) 584*7c478bd9Sstevel@tonic-gate { 585*7c478bd9Sstevel@tonic-gate int tag_type = get_tag_type(tag); 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate size_t payload_length = 0; 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate const fru_regdef_t *def; 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate /* 593*7c478bd9Sstevel@tonic-gate * Build a definition for unrecognized tags (e.g., not in libfrureg) 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate if ((tag_type == -1) || 596*7c478bd9Sstevel@tonic-gate ((payload_length = get_payload_length(tag)) != length)) { 597*7c478bd9Sstevel@tonic-gate def = &unknown; 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate unknown.tagType = -1; 600*7c478bd9Sstevel@tonic-gate unknown.tagDense = -1; 601*7c478bd9Sstevel@tonic-gate unknown.payloadLen = length; 602*7c478bd9Sstevel@tonic-gate unknown.dataLength = unknown.payloadLen; 603*7c478bd9Sstevel@tonic-gate 604*7c478bd9Sstevel@tonic-gate if (tag_type == -1) 605*7c478bd9Sstevel@tonic-gate (void) snprintf(tagname, sizeof (tagname), "INVALID"); 606*7c478bd9Sstevel@tonic-gate else 607*7c478bd9Sstevel@tonic-gate (void) snprintf(tagname, sizeof (tagname), 608*7c478bd9Sstevel@tonic-gate "%s_%u_%u_%u", get_tagtype_str(tag_type), 609*7c478bd9Sstevel@tonic-gate get_tag_dense(tag), payload_length, length); 610*7c478bd9Sstevel@tonic-gate } else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) { 611*7c478bd9Sstevel@tonic-gate def = &unknown; 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate unknown.tagType = tag_type; 614*7c478bd9Sstevel@tonic-gate unknown.tagDense = get_tag_dense(tag); 615*7c478bd9Sstevel@tonic-gate unknown.payloadLen = payload_length; 616*7c478bd9Sstevel@tonic-gate unknown.dataLength = unknown.payloadLen; 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate (void) snprintf(tagname, sizeof (tagname), "%s_%u_%u", 619*7c478bd9Sstevel@tonic-gate get_tagtype_str(unknown.tagType), 620*7c478bd9Sstevel@tonic-gate unknown.tagDense, payload_length); 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate /* 625*7c478bd9Sstevel@tonic-gate * Print the defined element 626*7c478bd9Sstevel@tonic-gate */ 627*7c478bd9Sstevel@tonic-gate print_element(payload, def, "", INDENT); 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* 633*7c478bd9Sstevel@tonic-gate * Print a segment's name and the contents of each data element in the segment 634*7c478bd9Sstevel@tonic-gate */ 635*7c478bd9Sstevel@tonic-gate static int 636*7c478bd9Sstevel@tonic-gate print_packets_in_segment(fru_seghdl_t segment, void *args) 637*7c478bd9Sstevel@tonic-gate { 638*7c478bd9Sstevel@tonic-gate char *name; 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate int status; 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate if ((status = fru_get_segment_name(segment, &name)) != FRU_SUCCESS) { 644*7c478bd9Sstevel@tonic-gate saved_status = status; 645*7c478bd9Sstevel@tonic-gate name = ""; 646*7c478bd9Sstevel@tonic-gate error(gettext("Error getting segment name: %s\n"), 647*7c478bd9Sstevel@tonic-gate fru_strerror(status)); 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (xml) 652*7c478bd9Sstevel@tonic-gate output("%*s<Segment name=\"%s\">\n", INDENT, "", name); 653*7c478bd9Sstevel@tonic-gate else 654*7c478bd9Sstevel@tonic-gate output("%*sSEGMENT: %s\n", INDENT, "", name); 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* Iterate over the packets in the segment, printing the contents */ 657*7c478bd9Sstevel@tonic-gate if ((status = fru_for_each_packet(segment, print_packet, args)) 658*7c478bd9Sstevel@tonic-gate != FRU_SUCCESS) { 659*7c478bd9Sstevel@tonic-gate saved_status = status; 660*7c478bd9Sstevel@tonic-gate error(gettext("Error processing data in segment \"%s\": %s\n"), 661*7c478bd9Sstevel@tonic-gate name, fru_strerror(status)); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate if (xml) output("%*s</Segment>\n", INDENT, ""); 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate free(name); 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 672*7c478bd9Sstevel@tonic-gate static void 673*7c478bd9Sstevel@tonic-gate print_node_path(fru_node_t fru_type, const char *path, const char *name, 674*7c478bd9Sstevel@tonic-gate end_node_fp_t *end_node, void **end_args) 675*7c478bd9Sstevel@tonic-gate { 676*7c478bd9Sstevel@tonic-gate output("%s%s\n", path, 677*7c478bd9Sstevel@tonic-gate ((fru_type == FRU_NODE_CONTAINER) ? " (container)" 678*7c478bd9Sstevel@tonic-gate : ((fru_type == FRU_NODE_FRU) ? " (fru)" : ""))); 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* 682*7c478bd9Sstevel@tonic-gate * Close the XML element for a "location" node 683*7c478bd9Sstevel@tonic-gate */ 684*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 685*7c478bd9Sstevel@tonic-gate static void 686*7c478bd9Sstevel@tonic-gate end_location_xml(fru_nodehdl_t node, const char *path, const char *name, 687*7c478bd9Sstevel@tonic-gate void *args) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate assert(args != NULL); 690*7c478bd9Sstevel@tonic-gate output("</Location> <!-- %s -->\n", args); 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate /* 694*7c478bd9Sstevel@tonic-gate * Close the XML element for a "fru" node 695*7c478bd9Sstevel@tonic-gate */ 696*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 697*7c478bd9Sstevel@tonic-gate static void 698*7c478bd9Sstevel@tonic-gate end_fru_xml(fru_nodehdl_t node, const char *path, const char *name, void *args) 699*7c478bd9Sstevel@tonic-gate { 700*7c478bd9Sstevel@tonic-gate assert(args != NULL); 701*7c478bd9Sstevel@tonic-gate output("</Fru> <!-- %s -->\n", args); 702*7c478bd9Sstevel@tonic-gate } 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate /* 705*7c478bd9Sstevel@tonic-gate * Close the XML element for a "container" node 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 708*7c478bd9Sstevel@tonic-gate static void 709*7c478bd9Sstevel@tonic-gate end_container_xml(fru_nodehdl_t node, const char *path, const char *name, 710*7c478bd9Sstevel@tonic-gate void *args) 711*7c478bd9Sstevel@tonic-gate { 712*7c478bd9Sstevel@tonic-gate assert(args != NULL); 713*7c478bd9Sstevel@tonic-gate output("</Container> <!-- %s -->\n", args); 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate /* 717*7c478bd9Sstevel@tonic-gate * Introduce a node in XML and set the appropriate node-closing function 718*7c478bd9Sstevel@tonic-gate */ 719*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 720*7c478bd9Sstevel@tonic-gate static void 721*7c478bd9Sstevel@tonic-gate print_node_xml(fru_node_t fru_type, const char *path, const char *name, 722*7c478bd9Sstevel@tonic-gate end_node_fp_t *end_node, void **end_args) 723*7c478bd9Sstevel@tonic-gate { 724*7c478bd9Sstevel@tonic-gate switch (fru_type) { 725*7c478bd9Sstevel@tonic-gate case FRU_NODE_FRU: 726*7c478bd9Sstevel@tonic-gate output("<Fru name=\"%s\">\n", name); 727*7c478bd9Sstevel@tonic-gate *end_node = end_fru_xml; 728*7c478bd9Sstevel@tonic-gate break; 729*7c478bd9Sstevel@tonic-gate case FRU_NODE_CONTAINER: 730*7c478bd9Sstevel@tonic-gate output("<Container name=\"%s\">\n", name); 731*7c478bd9Sstevel@tonic-gate *end_node = end_container_xml; 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate default: 734*7c478bd9Sstevel@tonic-gate output("<Location name=\"%s\">\n", name); 735*7c478bd9Sstevel@tonic-gate *end_node = end_location_xml; 736*7c478bd9Sstevel@tonic-gate break; 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate *end_args = (void *) name; 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate /* 743*7c478bd9Sstevel@tonic-gate * Print node info and, where appropriate, node contents 744*7c478bd9Sstevel@tonic-gate */ 745*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 746*7c478bd9Sstevel@tonic-gate static fru_errno_t 747*7c478bd9Sstevel@tonic-gate process_node(fru_nodehdl_t node, const char *path, const char *name, 748*7c478bd9Sstevel@tonic-gate void *args, end_node_fp_t *end_node, void **end_args) 749*7c478bd9Sstevel@tonic-gate { 750*7c478bd9Sstevel@tonic-gate int status; 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate fru_node_t fru_type = FRU_NODE_UNKNOWN; 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate if ((status = fru_get_node_type(node, &fru_type)) != FRU_SUCCESS) { 756*7c478bd9Sstevel@tonic-gate saved_status = status; 757*7c478bd9Sstevel@tonic-gate error(gettext("Error getting node type: %s\n"), 758*7c478bd9Sstevel@tonic-gate fru_strerror(status)); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate if (containers_only) { 762*7c478bd9Sstevel@tonic-gate if (fru_type != FRU_NODE_CONTAINER) 763*7c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 764*7c478bd9Sstevel@tonic-gate name = path; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* Introduce the node */ 768*7c478bd9Sstevel@tonic-gate assert(print_node != NULL); 769*7c478bd9Sstevel@tonic-gate print_node(fru_type, path, name, end_node, end_args); 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate if (list_only) 772*7c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate /* Print the contents of each packet in each segment of a container */ 775*7c478bd9Sstevel@tonic-gate if (fru_type == FRU_NODE_CONTAINER) { 776*7c478bd9Sstevel@tonic-gate if (xml) output("<ContainerData>\n"); 777*7c478bd9Sstevel@tonic-gate if ((status = 778*7c478bd9Sstevel@tonic-gate fru_for_each_segment(node, print_packets_in_segment, 779*7c478bd9Sstevel@tonic-gate NULL)) 780*7c478bd9Sstevel@tonic-gate != FRU_SUCCESS) { 781*7c478bd9Sstevel@tonic-gate saved_status = status; 782*7c478bd9Sstevel@tonic-gate error(gettext("Error processing node \"%s\": %s\n"), 783*7c478bd9Sstevel@tonic-gate name, fru_strerror(status)); 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate if (xml) output("</ContainerData>\n"); 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate /* 792*7c478bd9Sstevel@tonic-gate * Process the node if its path matches the search path in "args" 793*7c478bd9Sstevel@tonic-gate */ 794*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 795*7c478bd9Sstevel@tonic-gate static fru_errno_t 796*7c478bd9Sstevel@tonic-gate process_matching_node(fru_nodehdl_t node, const char *path, const char *name, 797*7c478bd9Sstevel@tonic-gate void *args, end_node_fp_t *end_node, void **end_args) 798*7c478bd9Sstevel@tonic-gate { 799*7c478bd9Sstevel@tonic-gate int status; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate if (!fru_pathmatch(path, args)) 803*7c478bd9Sstevel@tonic-gate return (FRU_SUCCESS); 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate status = process_node(node, path, path, args, end_node, end_args); 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate return ((status == FRU_SUCCESS) ? FRU_WALK_TERMINATE : status); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /* 811*7c478bd9Sstevel@tonic-gate * Write the trailer required for well-formed DTD-compliant XML 812*7c478bd9Sstevel@tonic-gate */ 813*7c478bd9Sstevel@tonic-gate static void 814*7c478bd9Sstevel@tonic-gate terminate_xml() 815*7c478bd9Sstevel@tonic-gate { 816*7c478bd9Sstevel@tonic-gate errno = 0; 817*7c478bd9Sstevel@tonic-gate if (ftell(errlog) > 0) { 818*7c478bd9Sstevel@tonic-gate char c; 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate output("<ErrorLog>\n"); 821*7c478bd9Sstevel@tonic-gate rewind(errlog); 822*7c478bd9Sstevel@tonic-gate if (!errno) 823*7c478bd9Sstevel@tonic-gate while ((c = getc(errlog)) != EOF) 824*7c478bd9Sstevel@tonic-gate xputchar(c); 825*7c478bd9Sstevel@tonic-gate output("</ErrorLog>\n"); 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate if (errno) { 829*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 830*7c478bd9Sstevel@tonic-gate errlog = NULL; 831*7c478bd9Sstevel@tonic-gate error(gettext("Error copying error messages to \"ErrorLog\""), 832*7c478bd9Sstevel@tonic-gate strerror(errno)); 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate output("</FRUID_XML_Tree>\n"); 836*7c478bd9Sstevel@tonic-gate } 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate /* 839*7c478bd9Sstevel@tonic-gate * Print available FRU ID information 840*7c478bd9Sstevel@tonic-gate */ 841*7c478bd9Sstevel@tonic-gate int 842*7c478bd9Sstevel@tonic-gate prtfru(const char *searchpath, int containers_only_flag, int list_only_flag, 843*7c478bd9Sstevel@tonic-gate int xml_flag) 844*7c478bd9Sstevel@tonic-gate { 845*7c478bd9Sstevel@tonic-gate fru_errno_t status; 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate fru_nodehdl_t frutree = 0; 848*7c478bd9Sstevel@tonic-gate 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /* Copy parameter flags to global flags */ 851*7c478bd9Sstevel@tonic-gate containers_only = containers_only_flag; 852*7c478bd9Sstevel@tonic-gate list_only = list_only_flag; 853*7c478bd9Sstevel@tonic-gate xml = xml_flag; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* Help arrange for correct, efficient interleaving of output */ 857*7c478bd9Sstevel@tonic-gate (void) setvbuf(stderr, NULL, _IOLBF, 0); 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate /* Initialize for XML--or not */ 861*7c478bd9Sstevel@tonic-gate if (xml) { 862*7c478bd9Sstevel@tonic-gate safeputchar = xputchar; 863*7c478bd9Sstevel@tonic-gate safeputs = xputs; 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate print_node = print_node_xml; 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate if ((errlog = tmpfile()) == NULL) { 868*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 869*7c478bd9Sstevel@tonic-gate "Error creating error log file: %s\n", 870*7c478bd9Sstevel@tonic-gate strerror(errno)); 871*7c478bd9Sstevel@tonic-gate return (1); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* Output the XML preamble */ 875*7c478bd9Sstevel@tonic-gate output("<?xml version=\"1.0\" ?>\n" 876*7c478bd9Sstevel@tonic-gate "<!--\n" 877*7c478bd9Sstevel@tonic-gate " Copyright 2000-2002 Sun Microsystems, Inc. " 878*7c478bd9Sstevel@tonic-gate "All rights reserved.\n" 879*7c478bd9Sstevel@tonic-gate " Use is subject to license terms.\n" 880*7c478bd9Sstevel@tonic-gate "-->\n\n" 881*7c478bd9Sstevel@tonic-gate "<!DOCTYPE FRUID_XML_Tree SYSTEM \"prtfrureg.dtd\">\n\n" 882*7c478bd9Sstevel@tonic-gate "<FRUID_XML_Tree>\n"); 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate /* Arrange to always properly terminate XML */ 885*7c478bd9Sstevel@tonic-gate if (atexit(terminate_xml)) 886*7c478bd9Sstevel@tonic-gate error(gettext("Warning: XML will not be terminated: " 887*7c478bd9Sstevel@tonic-gate "%s\n"), strerror(errno)); 888*7c478bd9Sstevel@tonic-gate } else 889*7c478bd9Sstevel@tonic-gate print_node = print_node_path; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate /* Get the root node */ 893*7c478bd9Sstevel@tonic-gate if ((status = fru_get_root(&frutree)) == FRU_NODENOTFOUND) { 894*7c478bd9Sstevel@tonic-gate error(gettext("This system does not provide FRU ID data\n")); 895*7c478bd9Sstevel@tonic-gate return (1); 896*7c478bd9Sstevel@tonic-gate } else if (status != FRU_SUCCESS) { 897*7c478bd9Sstevel@tonic-gate error(gettext("Unable to access FRU ID data: %s\n"), 898*7c478bd9Sstevel@tonic-gate fru_strerror(status)); 899*7c478bd9Sstevel@tonic-gate return (1); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* Process the tree */ 903*7c478bd9Sstevel@tonic-gate if (searchpath == NULL) { 904*7c478bd9Sstevel@tonic-gate status = fru_walk_tree(frutree, "", process_node, NULL); 905*7c478bd9Sstevel@tonic-gate } else { 906*7c478bd9Sstevel@tonic-gate status = fru_walk_tree(frutree, "", process_matching_node, 907*7c478bd9Sstevel@tonic-gate (void *)searchpath); 908*7c478bd9Sstevel@tonic-gate if (status == FRU_WALK_TERMINATE) { 909*7c478bd9Sstevel@tonic-gate status = FRU_SUCCESS; 910*7c478bd9Sstevel@tonic-gate } else if (status == FRU_SUCCESS) { 911*7c478bd9Sstevel@tonic-gate error(gettext("\"%s\" not found\n"), searchpath); 912*7c478bd9Sstevel@tonic-gate return (1); 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate } 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate if (status != FRU_SUCCESS) 917*7c478bd9Sstevel@tonic-gate error(gettext("Error processing FRU tree: %s\n"), 918*7c478bd9Sstevel@tonic-gate fru_strerror(status)); 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate return (((status == FRU_SUCCESS) && (saved_status == 0)) ? 0 : 1); 921*7c478bd9Sstevel@tonic-gate } 922