Index: lib/ipmi_ekanalyzer.c
===================================================================
--- lib/ipmi_ekanalyzer.c	(revision 7741)
+++ lib/ipmi_ekanalyzer.c	(working copy)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2007 Kontron Canada, Inc.  All Rights Reserved.
+ * Copyright (c) 2014 T-Platforms. All rights reserved.
  *
  * Base on code from
  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
@@ -41,6 +42,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <limits.h>
 
 #define NO_MORE_INFO_FIELD         0xc1
 #define TYPE_CODE 0xc0 /*Language code*/
@@ -2390,8 +2392,8 @@
 	printf("FRU Header Info\n");
 	printf("%s\n", EQUAL_LINE_LIMITER);
 	printf("Format Version          :0x%02x %s\n",
-		(header.version & 0x0f),
-		((header.version & 0x0f) == 1) ? "" : "{unsupported}");
+		FRU_VERSION(header.version),
+		(FRU_VERSION(header.version) == SUPPORTED_FORMAT_VERSION) ? "" : "{unsupported}");
 	printf("Internal Use Offset     :0x%02x\n", header.offset.internal);
 	printf("Chassis Info Offset     :0x%02x\n", header.offset.chassis);
 	printf("Board Info Offset       :0x%02x\n", header.offset.board);
@@ -2433,10 +2435,19 @@
 	struct fru_header header;
 	time_t tval;
 	int ret = 0;
+	int i;
 	unsigned char data = 0;
 	unsigned char lan_code = 0;
 	unsigned char mfg_date[SIZE_MFG_DATE];
 	unsigned int board_length = 0;
+	char *board_fields[] = {
+		"Board Manufacturer",
+		"Board Product Name",
+		"Board Serial Number",
+		"Board Part Number",
+		"FRU File ID",
+		"Custom Mfg. Data",
+	};
 
 	input_file = fopen(filename, "r");
 	if (input_file == NULL) {
@@ -2454,9 +2465,12 @@
 		return (-1);
 	}
 	/*** Display FRU Internal Use Info ***/
-	if (!feof(input_file)) {
+	if (!feof(input_file) && header.offset.internal) {
 		unsigned char format_version;
 		unsigned long len = 0;
+		uint8_t *offset;
+		uint8_t next_offset;
+		int i;
 
 		printf("%s\n", EQUAL_LINE_LIMITER);
 		printf("FRU Internal Use Info\n");
@@ -2464,20 +2478,55 @@
 
 		ret = fread(&format_version, 1, 1, input_file);
 		if ((ret != 1) || ferror(input_file)) {
-			lprintf(LOG_ERR, "Invalid format version!");
+			lprintf(LOG_ERR, "Couldn't read format version!");
 			fclose(input_file);
 			return (-1);
 		}
-		printf("Format Version: %d\n", (format_version & 0x0f));
+		printf("Format Version: %d\n", FRU_VERSION(format_version));
+		if(FRU_VERSION(format_version) != SUPPORTED_FORMAT_VERSION) {
+			printf("WARNING: Format version %d is not supported.\n"
+			       "         Decoding as format version %d.\n"
+			       "         Expect decoding errors.\n",
+			       FRU_VERSION(format_version),
+			       SUPPORTED_FORMAT_VERSION
+			      );
+		}
 
-		if (header.offset.chassis > 0) {
-			len = (header.offset.chassis * FACTOR_OFFSET)
-				- (header.offset.internal * FACTOR_OFFSET);
-		} else {
-			len = (header.offset.board * FACTOR_OFFSET)
-				- (header.offset.internal * FACTOR_OFFSET);
+		/* 
+		 * Find the next area offset to calculate the length of this area as
+		 * it doesn't contain a length field itself.
+		 *
+		 * We can't just take some area like Chassis Info, because it may
+		 * not be the next one, or it may be completely absent.
+		 */
+		len = 0;
+		for(offset = &header.offset.multi;
+			offset > &header.offset.internal &&
+			(*offset > header.offset.internal || !(*offset));
+			offset--) {
+			len = (*offset * FACTOR_OFFSET)
+				- (header.offset.internal * FACTOR_OFFSET)
+				- 1; // Account for the previously read version byte
+		};
+
+		/* 
+		 * If next section wasn't found, try to guess the internal use area length
+		 * from the file size assuming that there is no other data in the file
+		 * past this area
+		 */
+		if(!len) {
+			long cur_pos = ftell(input_file);
+
+			fseek(input_file, 0, SEEK_END);
+			len = ftell(input_file) - cur_pos;
+			fseek(input_file, cur_pos, SEEK_SET);
+
+			printf("Unable to determine area length\n"
+			       "No other areas present.\n"
+			       "Assuming %d bytes data length from file length.\n", len);
 		}
-		printf("Length: %ld\n", len);
+
+		printf("Data length: %ld\n", len);
 		printf("Data dump:\n");
 		while ((len > 0) && (!feof(input_file))) {
 			unsigned char data;
@@ -2491,7 +2540,13 @@
 			len--;
 		}
 		printf("\n");
+
 	}
+	else if(header.offset.internal) {
+		printf("FRU file is corrupt (too short)\n");
+		close(input_file);
+		return (-1);
+	}
 	/*** Chassis Info Area ***/
 	if (header.offset.chassis != 0) {
 		long offset = 0;
@@ -2499,15 +2554,14 @@
 		ret = ipmi_ek_display_chassis_info_area(input_file, offset);
 	}
 	/*** Display FRU Board Info Area ***/
-	while (1) {
 		if (header.offset.board == 0) {
-			break;
+		goto board_done;
 		}
 		ret = fseek(input_file,
 				(header.offset.board * FACTOR_OFFSET),
 				SEEK_SET);
 		if (feof(input_file)) {
-			break;
+		goto board_done;
 		}
 		file_offset = ftell(input_file);
 		printf("%s\n", EQUAL_LINE_LIMITER);
@@ -2522,7 +2576,7 @@
 		}
 		printf("Format Version: %d\n", (data & 0x0f));
 		if (feof(input_file)) {
-			break;
+		goto board_done;
 		}
 		ret = fread(&data, 1, 1, input_file); /* Board Area Length */
 		if ((ret != 1) || ferror(input_file)) {
@@ -2538,7 +2592,7 @@
 		 */
 		board_length -= 2;
 		if (feof(input_file)) {
-			break;
+		goto board_done;
 		}
 		ret = fread(&lan_code, 1, 1, input_file); /* Language Code */
 		if ((ret != 1) || ferror(input_file)) {
@@ -2550,7 +2604,7 @@
 		board_length--;
 		/* Board Mfg Date */
 		if (feof(input_file)) {
-			break;
+		goto board_done;
 		}
 
 		ret = fread(mfg_date, SIZE_MFG_DATE, 1, input_file);
@@ -2566,31 +2620,19 @@
 		printf("Board Mfg Date: %ld, %s", tval,
 				asctime(localtime(&tval)));
 		board_length -= SIZE_MFG_DATE;
-		/* Board Mfg */
-		file_offset = ipmi_ek_display_board_info_area(
-				input_file, "Board Manufacture Data", &board_length);
-		ret = fseek(input_file, file_offset, SEEK_SET);
-		/* Board Product */
-		file_offset = ipmi_ek_display_board_info_area(
-				input_file, "Board Product Name", &board_length);
-		ret = fseek(input_file, file_offset, SEEK_SET);
-		/* Board Serial */
-		file_offset = ipmi_ek_display_board_info_area(
-				input_file, "Board Serial Number", &board_length);
-		ret = fseek(input_file, file_offset, SEEK_SET);
-		/* Board Part */
-		file_offset = ipmi_ek_display_board_info_area(
-				input_file, "Board Part Number", &board_length);
-		ret = fseek(input_file, file_offset, SEEK_SET);
-		/* FRU file ID */
-		file_offset = ipmi_ek_display_board_info_area(
-				input_file, "FRU File ID", &board_length);
-		ret = fseek(input_file, file_offset, SEEK_SET);
-		/* Additional Custom Mfg. */
-		file_offset = ipmi_ek_display_board_info_area(
-				input_file, "Custom", &board_length);
+	/* Display Board Info fields */
+	for(i = 0; i < ARRAY_SZ(board_fields); i++) {
+		file_offset = ipmi_ek_display_board_info_area(input_file,
+		                                              board_fields[i],
+		                                              &board_length);
+		if(file_offset < 0) {
+			printf("Error processing Board Information\n");
 		break;
 	}
+	}
+
+board_done:
+
 	/* Product Info Area */
 	if (header.offset.product && (!feof(input_file))) {
 		long offset = 0;
@@ -2714,110 +2756,96 @@
 	int ret = 0;
 	unsigned char len = 0;
 	unsigned int size_board = 0;
+	int items;
+	unsigned char *data = NULL;
+
 	if (input_file == NULL || board_type == NULL
 			|| board_length == NULL) {
 		return (size_t)(-1);
 	}
 	file_offset = ftell(input_file);
 
+	if (strncmp(board_type, "Custom", 6 ) != 0) {
+		items = 1;
+	}
+	else {
+		items = INT_MAX;
+	}
+
+	do {
+		int i;
+
 	/* Board length*/
 	ret = fread(&len, 1, 1, input_file);
 	if ((ret != 1) || ferror(input_file)) {
-		lprintf(LOG_ERR, "Invalid Length!");
+			lprintf(LOG_ERR, "Couldn't read type/length!");
 		goto out;
 	}
 	(*board_length)--;
 
-	/* Bit 5:0 of Board Mfg type represent legnth */
-	size_board = (len & 0x3f);
-	if (size_board == 0) {
-		printf("%s: None\n", board_type);
-		goto out;
-	}
-	if (strncmp(board_type, "Custom", 6 ) != 0) {
-		unsigned char *data;
-		unsigned int i = 0;
-		data = malloc(size_board);
-		if (data == NULL) {
-			lprintf(LOG_ERR, "ipmitool: malloc failure");
-			return (size_t)(-1);
-		}
-		ret = fread(data, size_board, 1, input_file);
-		if ((ret != 1) || ferror(input_file)) {
-			lprintf(LOG_ERR, "Invalid board type size!");
-			free(data);
-			data = NULL;
-			goto out;
-		}
 		printf("%s type: 0x%02x\n", board_type, len);
 		printf("%s: ", board_type);
-		for (i = 0; i < size_board; i++) {
-			if ((len & TYPE_CODE) == TYPE_CODE) {
-				printf("%c", data[i]);
-			} else {
-				/* other than language code (binary, BCD,
-				 * ASCII 6 bit...) is not supported
-				 */
-				printf("%02x", data[i]);
-			}
-		}
-		printf("\n");
-		free(data);
-		data = NULL;
-		(*board_length) -= size_board;
-		goto out;
-	}
-	while (!feof(input_file)) {
+
 		if (len == NO_MORE_INFO_FIELD) {
 			unsigned char padding;
 			unsigned char checksum = 0;
+
+			printf("This is the last record.\n");
+
 			/* take the rest of data in the area minus 1 byte of 
 			 * checksum
 			 */
-			printf("Additional Custom Mfg. length: 0x%02x\n", len);
 			padding = (*board_length) - 1;
 			if ((padding > 0) && (!feof(input_file))) {
 				printf("Unused space: %d (bytes)\n", padding);
 				fseek(input_file, padding, SEEK_CUR);
+				(*board_length) -= padding;
 			}
+
 			ret = fread(&checksum, 1, 1, input_file);
 			if ((ret != 1) || ferror(input_file)) {
-				lprintf(LOG_ERR, "Invalid Checksum!");
+				lprintf(LOG_ERR, "Can't read checksum!");
 				goto out;
 			}
-			printf("Checksum: 0x%02x\n", checksum);
+			(*board_length)--;
+			printf("Checksum: 0x%02x (Not checked)\n", checksum);
 			goto out;
 		}
-		printf("Additional Custom Mfg. length: 0x%02x\n", len);
-		if ((size_board > 0) && (size_board < (*board_length))) {
-			unsigned char * additional_data = NULL;
-			unsigned int i = 0;
-			additional_data = malloc(size_board);
-			if (additional_data == NULL) {
+
+		/* Bit 5:0 of Board Mfg type represent legnth */
+		size_board = (len & 0x3f);
+		if (size_board == 0) {
+			printf("%s: None\n", board_type);
+			goto out;
+		}
+
+		data = malloc(size_board);
+		if (data == NULL) {
 				lprintf(LOG_ERR, "ipmitool: malloc failure");
 				return (size_t)(-1);
 			}
 				
-			ret = fread(additional_data, size_board, 1, input_file);
+		ret = fread(data, size_board, 1, input_file);
 			if ((ret != 1) || ferror(input_file)) {
-				lprintf(LOG_ERR, "Invalid Additional Data!");
+			lprintf(LOG_ERR, "Couldn't read data (%d)!", ret);
+			free(data);
 				goto out;
 			}
-			printf("Additional Custom Mfg. Data: %02x",
-					additional_data[0]);
-			for (i = 1; i < size_board; i++) {
-				printf("-%02x", additional_data[i]);
-			}
-			printf("\n");
-			free(additional_data);
-			additional_data = NULL;
 			(*board_length) -= size_board;
+
+		for (i = 0; i < size_board; i++) {
+			if ((len & TYPE_CODE) == TYPE_CODE) {
+				printf("%c", data[i]);
+			} else {
+				/* other than language code (binary, BCD,
+				 * ASCII 6 bit...) is not supported
+				 */
+				printf("%02x", data[i]);
 		}
-		else {
-			printf("No Additional Custom Mfg. %d\n", *board_length);
-			goto out;
 		}
-	}
+		printf("\n");
+		free(data);
+	} while (!feof(input_file) && --items);
  
 out:
 	file_offset = ftell(input_file);
@@ -2868,7 +2896,7 @@
 	}
 	ret = fread(&data, 1, 1, input_file);
 	if ((ret != 1) || ferror(input_file)) {
-		lprintf(LOG_ERR, "Invalid Data!");
+		lprintf(LOG_ERR, "Couldn't read Data!");
 		return (-1);
 	}
 	printf("Format Version Number: %d\n", (data & 0x0f));
@@ -2879,7 +2907,7 @@
 	 * it ends up byte swapped on big endian machines */
 	ret = fread(&ch_len, 1, 1, input_file);
 	if ((ret != 1) || ferror(input_file)) {
-		lprintf(LOG_ERR, "Invalid Length!");
+		lprintf(LOG_ERR, "Couldn't read Length!");
 		return (-1);
 	}
 	/* length is in factor of 8 bytes */
@@ -2889,11 +2917,15 @@
 
 	ret = fread(&data, 1, 1, input_file);
 	if ((ret != 1) || ferror(input_file)) {
-		lprintf(LOG_ERR, "Invalid Length!");
+		lprintf(LOG_ERR, "Couldn't read Length!");
 		return (-1);
 	}
 
-	fread(&data, 1, 1, input_file);
+	ret = fread(&data, 1, 1, input_file);
+	if ((ret != 1) || ferror(input_file)) {
+		lprintf(LOG_ERR, "Couldn't read language code!");
+		return (-1);
+	}
 	printf("Language Code: %d\n", data);
 	len--;
 	/* Product Mfg */
Index: include/ipmitool/helper.h
===================================================================
--- include/ipmitool/helper.h	(revision 7741)
+++ include/ipmitool/helper.h	(working copy)
@@ -101,6 +101,8 @@
 void ipmi_start_daemon(struct ipmi_intf *intf);
 uint16_t ipmi_get_oem_id(struct ipmi_intf *intf);
 
+#define ARRAY_SZ(a) (sizeof(a) / sizeof((a)[0]))
+
 #define ipmi_open_file_read(file)	ipmi_open_file(file, 0)
 #define ipmi_open_file_write(file)	ipmi_open_file(file, 1)
 
Index: include/ipmitool/ipmi_fru.h
===================================================================
--- include/ipmitool/ipmi_fru.h	(revision 7741)
+++ include/ipmitool/ipmi_fru.h	(working copy)
@@ -72,6 +72,8 @@
 #endif
 struct fru_header {
 	uint8_t version;
+#define FRU_VERSION(v) ((v) & 0x0F)
+#define SUPPORTED_FORMAT_VERSION 1
 	union {
 		struct {
 			uint8_t internal;
