3ea658
From a909f4e024bdb5b0a8ea11f9fde62a9c74438983 Mon Sep 17 00:00:00 2001
3ea658
From: Mark Salter <msalter@redhat.com>
3ea658
Date: Mon, 26 Jan 2015 12:42:42 -0500
3ea658
Subject: [PATCH] Add libdmifs from Linaro
3ea658
3ea658
This library module comes from:
3ea658
3ea658
  git://git.linaro.org/people/ivan.khoronzhuk/libdmifs.git
3ea658
3ea658
For now, it is being built in rather than as a shared lib.
3ea658
3ea658
Signed-off-by: Mark Salter <msalter@redhat.com>
3ea658
---
3ea658
 Makefile    |   7 +-
3ea658
 dmidecode.c |   2 +-
3ea658
 libdmifs.c  | 644 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3ea658
 libdmifs.h  |  56 ++++++
3ea658
 4 files changed, 706 insertions(+), 3 deletions(-)
3ea658
 create mode 100644 libdmifs.c
3ea658
 create mode 100644 libdmifs.h
3ea658
3ea658
diff --git a/Makefile b/Makefile
3ea658
index d8457da..805d08e 100644
3ea658
--- a/Makefile
3ea658
+++ b/Makefile
3ea658
@@ -57,8 +57,8 @@ all : $(PROGRAMS)
3ea658
 # Programs
3ea658
 #
3ea658
3ea658
-dmidecode : dmidecode.o dmiopt.o dmioem.o util.o
3ea658
-	$(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o util.o -ldmifs -o $@
3ea658
+dmidecode : dmidecode.o dmiopt.o dmioem.o util.o libdmifs.o
3ea658
+	$(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o util.o libdmifs.o -o $@
3ea658
3ea658
 biosdecode : biosdecode.o util.o
3ea658
	$(CC) $(LDFLAGS) biosdecode.o util.o -o $@
3ea658
@@ -98,6 +98,9 @@ vpdopt.o : vpdopt.c config.h util.h vpdopt.h
3ea658
 util.o : util.c types.h util.h config.h
3ea658
	$(CC) $(CFLAGS) -c $< -o $@
3ea658
3ea658
+libdmifs.o: libdmifs.c libdmifs.h
3ea658
+	$(CC) $(CFLAGS) -c $< -o $@
3ea658
+
3ea658
 #
3ea658
 # Commands
3ea658
 #
3ea658
diff --git a/dmidecode.c b/dmidecode.c
3ea658
index 4663cc6..fee3af1 100644
3ea658
--- a/dmidecode.c
3ea658
+++ b/dmidecode.c
3ea658
@@ -57,7 +57,7 @@
3ea658
 #include <strings.h>
3ea658
 #include <stdlib.h>
3ea658
 #include <unistd.h>
3ea658
-#include <libdmifs.h>
3ea658
+#include "libdmifs.h"
3ea658
3ea658
 #include "version.h"
3ea658
 #include "config.h"
3ea658
diff --git a/libdmifs.c b/libdmifs.c
3ea658
new file mode 100644
3ea658
index 0000000..9ad2414
3ea658
--- /dev/null
3ea658
+++ b/libdmifs.c
3ea658
@@ -0,0 +1,644 @@
3ea658
+#include <stdio.h>
3ea658
+#include <stdlib.h>
3ea658
+#include <string.h>
3ea658
+#include <dirent.h>
3ea658
+#include <unistd.h>
3ea658
+#include <errno.h>
3ea658
+#include <endian.h>
3ea658
+#include "libdmifs.h"
3ea658
+
3ea658
+/*
3ea658
+ * maximum number of entries can be calculated based on maximum table
3ea658
+ * size and minimum size of structure (4 + 2 NULL symbols).
3ea658
+ */
3ea658
+#define MIN_HEADER_SIZE			4
3ea658
+#define MIN_DMI_STRUCT_SIZE		(MIN_HEADER_SIZE + 2)
3ea658
+#define MAX_ENTRIES_COUNT		(~0U/MIN_DMI_STRUCT_SIZE)
3ea658
+#define POSITION_ERR			(MAX_ENTRIES_COUNT + 1)
3ea658
+
3ea658
+/* list of dmi entries */
3ea658
+
3ea658
+/**
3ea658
+ * dmilist_insert - inserts new dmi entry to ordered dmi_list,
3ea658
+ * sorting according to the position in dmi table
3ea658
+ * @dmi_list: pointer on pointer to the first dmi entry in the list
3ea658
+ * @new: new entry to be inserted in the ordered dmi_list.
3ea658
+ *
3ea658
+ * Returns 0 on success and -1 when error.
3ea658
+ */
3ea658
+static int dmilist_insert(struct dmi_entry **dmi_list, struct dmi_entry *new)
3ea658
+{
3ea658
+	struct dmi_entry *old;
3ea658
+	struct dmi_entry *cur = *dmi_list;
3ea658
+
3ea658
+	if (!cur) {
3ea658
+		new->next = NULL;
3ea658
+		*dmi_list = new;
3ea658
+		return 0;
3ea658
+	}
3ea658
+
3ea658
+	old = NULL;
3ea658
+	while (cur) {
3ea658
+		if (cur->position < new->position) {
3ea658
+			old = cur;
3ea658
+			cur = cur->next;
3ea658
+			continue;
3ea658
+		} else if (cur->position > new->position) {
3ea658
+			if (old) {
3ea658
+				old->next = new;
3ea658
+				new->next = cur;
3ea658
+				return 0;
3ea658
+			}
3ea658
+			new->next = cur;
3ea658
+			*dmi_list = new;
3ea658
+			return 0;
3ea658
+		}
3ea658
+
3ea658
+		fprintf(stderr, "dmitable is broken");
3ea658
+		return -1;
3ea658
+	}
3ea658
+
3ea658
+	old->next = new;
3ea658
+	new->next = NULL;
3ea658
+
3ea658
+	return 0;
3ea658
+}
3ea658
+
3ea658
+static void dmilist_free_entry(struct dmi_entry *entry)
3ea658
+{
3ea658
+	free(entry->d_name);
3ea658
+	free(entry);
3ea658
+}
3ea658
+
3ea658
+static void dmilist_free(struct dmi_entry **dmi_list)
3ea658
+{
3ea658
+	struct dmi_entry *old;
3ea658
+	struct dmi_entry *cur = *dmi_list;
3ea658
+
3ea658
+	if (!cur)
3ea658
+		return;
3ea658
+
3ea658
+	while (cur) {
3ea658
+		old = cur;
3ea658
+		cur = cur->next;
3ea658
+		dmilist_free_entry(old);
3ea658
+	}
3ea658
+
3ea658
+	*dmi_list = NULL;
3ea658
+}
3ea658
+
3ea658
+/* dmi sysfs attribute reading */
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_smbios - get smbios data
3ea658
+ * @smbios: pointer on array to read raw smbios table in
3ea658
+ *
3ea658
+ * Returns read data size in bytes on success and 0 when error.
3ea658
+ */
3ea658
+static int dmi_get_smbios(unsigned char *smbios)
3ea658
+{
3ea658
+	FILE *file;
3ea658
+	int count = 0;
3ea658
+	enum {SMBIOS_SIZE = 32};
3ea658
+
3ea658
+	file = fopen("/sys/firmware/dmi/smbios_raw_header", "rb");
3ea658
+	if (!file) {
3ea658
+		fprintf(stderr, "no \"smbios\" sysfs entry\n");
3ea658
+		return count;
3ea658
+	}
3ea658
+
3ea658
+	count = fread(smbios, sizeof(char), SMBIOS_SIZE, file);
3ea658
+	if (!feof(file)) {
3ea658
+		fprintf(stderr, "Error while reading a file\n");
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+err:
3ea658
+	fclose(file);
3ea658
+	return count;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * read_position - reads position of dmi entry as it's inside dmi table
3ea658
+ * @dir: appropriate directory of dmi entry position
3ea658
+ *
3ea658
+ * returns dmi entry position in dmi table on success and POSITION_ERR when
3ea658
+ * error occurred.
3ea658
+ */
3ea658
+static unsigned int read_position(char *dir)
3ea658
+{
3ea658
+	FILE *file;
3ea658
+	char pos[10];
3ea658
+	unsigned int position;
3ea658
+
3ea658
+	file = fopen("position", "r");
3ea658
+	if (!file) {
3ea658
+		fprintf(stderr, "no \"position\" in \"%s\"\n", dir);
3ea658
+		return POSITION_ERR;
3ea658
+	}
3ea658
+
3ea658
+	if (!fgets(pos, 10, file) && ferror(file)) {
3ea658
+		fclose(file);
3ea658
+		fprintf(stderr, "Error while working with \"position\" in %s\n",
3ea658
+			dir);
3ea658
+		return POSITION_ERR;
3ea658
+	}
3ea658
+
3ea658
+	fclose(file);
3ea658
+
3ea658
+	position = strtoul(pos, NULL, 0);
3ea658
+	/* position can't be more than number of entries */
3ea658
+	if (position > MAX_ENTRIES_COUNT) {
3ea658
+		fprintf(stderr, "position is incorrect %d\n", position);
3ea658
+		return POSITION_ERR;
3ea658
+	}
3ea658
+
3ea658
+	return position;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * read_raw - reads raw data of dmi entry
3ea658
+ * @dir: appropriate directory of dmi entry position
3ea658
+ * @data: pointer to the array where raw data will be read
3ea658
+ * @max_size: maximum data size possible to read
3ea658
+ *
3ea658
+ * Returns read data size in bytes on success and 0 when error.
3ea658
+ * In the same time return value < 6 is also error as at least header is
3ea658
+ * 4 bytes in size + 2 NULLs.
3ea658
+ */
3ea658
+static unsigned int read_raw(char *dir,
3ea658
+			     unsigned char *buf, unsigned int max_size)
3ea658
+{
3ea658
+	FILE *file;
3ea658
+	unsigned int count;
3ea658
+	unsigned int size = 0;
3ea658
+
3ea658
+	file = fopen("raw", "rb");
3ea658
+	if (!file) {
3ea658
+		fprintf(stderr, "no \"raw\" in \"%s\"\n", dir);
3ea658
+		return 0;
3ea658
+	}
3ea658
+
3ea658
+	count = fread(buf, sizeof(char), max_size, file);
3ea658
+	if (!feof(file)) {
3ea658
+		fprintf(stderr, "Error while reading \"raw\" file\n");
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+	if (count < MIN_DMI_STRUCT_SIZE) {
3ea658
+		fprintf(stderr, "DMI header cannot be less than 4 bytes");
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+	/* check if structure is correct */
3ea658
+	if (buf[count - 1] || buf[count - 2]) {
3ea658
+		fprintf(stderr, "Bad raw file of \"%s\"\n", dir);
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+	size = count;
3ea658
+err:
3ea658
+	fclose(file);
3ea658
+	return size;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * add_entry_to_dmilist - generates empty dmi entry and places it to dmi list
3ea658
+ * @dmi_list: dmi list where allocated dmi entry will be put
3ea658
+ * @dir: the directory name appropriate to dmi entry
3ea658
+ *
3ea658
+ * Returns 0 on success and -1 on error
3ea658
+ */
3ea658
+static int add_entry_to_dmilist(struct dmi_entry **dmi_list, char *dir)
3ea658
+{
3ea658
+	char *dir_name;
3ea658
+	unsigned int position;
3ea658
+	struct dmi_entry *entry;
3ea658
+
3ea658
+	position = read_position(dir);
3ea658
+	if (position == POSITION_ERR) {
3ea658
+		fprintf(stderr,
3ea658
+			"Cannot read smbios position for \"%s\"\n", dir);
3ea658
+		return -1;
3ea658
+	}
3ea658
+
3ea658
+	dir_name = malloc(strlen(dir) + 1);
3ea658
+	if (!dir_name) {
3ea658
+		fprintf(stderr, "Cannot allocate memory for dir\n");
3ea658
+		return -1;
3ea658
+	}
3ea658
+	strcpy(dir_name, dir);
3ea658
+
3ea658
+	entry = malloc(sizeof(struct dmi_entry));
3ea658
+	if (!entry) {
3ea658
+		fprintf(stderr, "Cannot allocate memory for dmi struct\n");
3ea658
+		free(dir_name);
3ea658
+		return -1;
3ea658
+	}
3ea658
+
3ea658
+	entry->d_name = dir_name;
3ea658
+	entry->position = position;
3ea658
+
3ea658
+	if (dmilist_insert(dmi_list, entry)) {
3ea658
+		fprintf(stderr, "Cannot insert new dmientry in the list");
3ea658
+		dmilist_free_entry(entry);
3ea658
+		return -1;
3ea658
+	}
3ea658
+
3ea658
+	return 0;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * gather_entry_data - reads data from given dmi directory raw attribute end
3ea658
+ * binds it with given dmi entry.
3ea658
+ * @entry: dmi entry for what data will be read
3ea658
+ * @rdata: pointer to array where data will be read in
3ea658
+ * @max_size: maximum data size possible to read for now
3ea658
+ *
3ea658
+ * Returns read raw data size including two NULLs at the end
3ea658
+ * On error returns 0
3ea658
+ */
3ea658
+static unsigned int gather_entry_data(struct dmi_entry *entry,
3ea658
+				      unsigned char *rdata,
3ea658
+				      unsigned int max_size)
3ea658
+{
3ea658
+	unsigned int dsize;
3ea658
+
3ea658
+	dsize = read_raw(entry->d_name, rdata, max_size);
3ea658
+	if (dsize < MIN_DMI_STRUCT_SIZE) {
3ea658
+		fprintf(stderr,
3ea658
+			"Cannot read DMI raw for \"%s\"\n", entry->d_name);
3ea658
+		return 0;
3ea658
+	}
3ea658
+
3ea658
+	entry->h.data = rdata;
3ea658
+	entry->h.type = rdata[0];
3ea658
+	entry->h.length = rdata[1];
3ea658
+	entry->h.handle = le16toh(rdata[2] | (rdata[3] << 8));
3ea658
+
3ea658
+	return dsize;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * populate_dmilist - populate dmi entries in dmi list by raw data
3ea658
+ * @dmi_list: dmi list with dmi entries to be populated
3ea658
+ * @max_size: supposed size of whole dmi table. Can be taken from
3ea658
+ *	table SMBIOS entry.
3ea658
+ *
3ea658
+ * Returns dmi raw table size on success, otherwise 0.
3ea658
+ */
3ea658
+static unsigned int populate_dmilist(struct dmi_entry *dmi_list,
3ea658
+				     unsigned int max_size)
3ea658
+{
3ea658
+	unsigned int dsize;
3ea658
+	struct dmi_entry *entry;
3ea658
+	unsigned char *raw_table, *tp;
3ea658
+
3ea658
+	/* allocate memory for whole dmi table */
3ea658
+	raw_table = malloc(max_size);
3ea658
+	if (!raw_table) {
3ea658
+		fprintf(stderr, "Cannot allocate memory for DMI table\n");
3ea658
+		return 0;
3ea658
+	}
3ea658
+
3ea658
+	tp = raw_table;
3ea658
+	for (entry = dmi_list; entry; entry = entry->next) {
3ea658
+		if (max_size < MIN_DMI_STRUCT_SIZE) {
3ea658
+			fprintf(stderr, "Max size of DMI table is reached\n");
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		if (chdir(entry->d_name)) {
3ea658
+			fprintf(stderr, "Cannot change dir to %s\n",
3ea658
+				entry->d_name);
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		dsize = gather_entry_data(entry, tp, max_size);
3ea658
+		if (dsize < MIN_DMI_STRUCT_SIZE) {
3ea658
+			if (chdir("../"))
3ea658
+				fprintf(stderr, "Cannot change dir to ../\n");
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		if (chdir("../")) {
3ea658
+			fprintf(stderr, "Cannot change dir to ../\n");
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		tp += dsize;
3ea658
+		max_size -= dsize;
3ea658
+	}
3ea658
+
3ea658
+	return tp - raw_table;
3ea658
+
3ea658
+err:
3ea658
+	fprintf(stderr, "Cannot gather data for dir %s\n", entry->d_name);
3ea658
+	free(raw_table);
3ea658
+	return 0;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * create_dmilist - creates ordered linked dmi list with empty entries.
3ea658
+ * The empty entry is entry with empty dmi header data
3ea658
+ * @entry_count: pointer to dmi entry count to be updated while creating.
3ea658
+ *
3ea658
+ * On success returns dmi_entry pointer on first entry in the list
3ea658
+ * Otherwise returns NULL. Updates entry_count.
3ea658
+ */
3ea658
+static struct dmi_entry *create_dmilist(unsigned int *entry_count)
3ea658
+{
3ea658
+	DIR *dmi;
3ea658
+	char *cwd;
3ea658
+	void *ret = NULL;
3ea658
+	struct dirent *dir_entry;
3ea658
+	struct dmi_entry *dmi_list = NULL;
3ea658
+
3ea658
+	dmi = opendir(".");
3ea658
+	if (!dmi) {
3ea658
+		fprintf(stderr, "Cannot open cwd\n");
3ea658
+		return ret;
3ea658
+	}
3ea658
+
3ea658
+	*entry_count = 0;
3ea658
+	readdir(dmi); /* miss "." */
3ea658
+	readdir(dmi); /* miss ".." */
3ea658
+	while ((dir_entry = readdir(dmi))) {
3ea658
+		if (chdir(dir_entry->d_name)) {
3ea658
+			fprintf(stderr, "Cannot change dir to %s\n",
3ea658
+				dir_entry->d_name);
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		if (add_entry_to_dmilist(&dmi_list, dir_entry->d_name)) {
3ea658
+			fprintf(stderr, "Cannot add \"%s\" to dmi_list\n",
3ea658
+				dir_entry->d_name);
3ea658
+			if (chdir("../"))
3ea658
+				fprintf(stderr, "Cannot change dir to ../\n");
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		if (chdir("../")) {
3ea658
+			fprintf(stderr, "Cannot change dir to ../\n");
3ea658
+			goto err;
3ea658
+		}
3ea658
+
3ea658
+		(*entry_count)++;
3ea658
+	}
3ea658
+	/* now dmilist is complete */
3ea658
+	ret = dmi_list;
3ea658
+err:
3ea658
+	if (closedir(dmi)) {
3ea658
+		cwd = getcwd(NULL, 1024);
3ea658
+		fprintf(stderr, "Cannot close %s", cwd);
3ea658
+		free(cwd);
3ea658
+		ret = NULL;
3ea658
+	}
3ea658
+
3ea658
+	if (ret == dmi_list)
3ea658
+		return dmi_list;
3ea658
+
3ea658
+	dmilist_free(&dmi_list);
3ea658
+	return ret;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_put_dmilist - frees dmi list alloted by dmi_get_dmilist()
3ea658
+ * @dmi_list: dmi list to be free
3ea658
+ *
3ea658
+ * Returns 0 on success, -1 otherwise.
3ea658
+ */
3ea658
+static int dmi_put_dmilist(struct dmi_entry *dmi_list)
3ea658
+{
3ea658
+	unsigned char *raw_table;
3ea658
+
3ea658
+	if (!dmi_list) {
3ea658
+		fprintf(stderr, "Cannot free dmi_list NULL pointer\n");
3ea658
+		return -1;
3ea658
+	}
3ea658
+
3ea658
+	raw_table = dmi_list->h.data;
3ea658
+	if (!raw_table) {
3ea658
+		fprintf(stderr, "Cannot free raw_table NULL pointer\n");
3ea658
+		return -1;
3ea658
+	}
3ea658
+
3ea658
+	free(raw_table);
3ea658
+	dmilist_free(&dmi_list);
3ea658
+
3ea658
+	return 0;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_dmilist - creates ordered dmi list with all dmi entries present
3ea658
+ * on dmi sysfs. All raw entries data are situated contiguously in the RAM.
3ea658
+ * @entry_count: read count of dmi list entries, that's dmi structs in dmi table
3ea658
+ * @dmi_size: read whole size in bytes of dmi table.
3ea658
+ * @max_size: supposed size of whole dmi table. Can be taken from SMBIOS
3ea658
+ *	entry point table.
3ea658
+ *
3ea658
+ * Returns a pointer to first dmi entry in the list. When list is no longer
3ea658
+ * needed it has to be freed with dmi_put_dmilist().
3ea658
+ * In case of error returns NULL.
3ea658
+ */
3ea658
+static struct dmi_entry *dmi_get_dmilist(unsigned int *entry_count,
3ea658
+					 unsigned int *dmi_size,
3ea658
+					 unsigned int max_size)
3ea658
+{
3ea658
+	char *cwd;
3ea658
+	struct dmi_entry *dmi_list = NULL;
3ea658
+	char root[] = "/sys/firmware/dmi/entries/";
3ea658
+
3ea658
+	cwd = getcwd(NULL, 1024);
3ea658
+	if (!cwd) {
3ea658
+		fprintf(stderr, "Cannot get current directory\n");
3ea658
+		return NULL;
3ea658
+	}
3ea658
+
3ea658
+	if (chdir(root)) {
3ea658
+		fprintf(stderr, "Cannot change dir to %s\n", root);
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+	/*
3ea658
+	 * Create dmi_list then fill it in. Do this in two steps to
3ea658
+	 * have contiguous raw data for whole table
3ea658
+	 */
3ea658
+	dmi_list = create_dmilist(entry_count);
3ea658
+	if (!dmi_list) {
3ea658
+		fprintf(stderr, "Cannot create dmi_list\n");
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+	*dmi_size = populate_dmilist(dmi_list, max_size);
3ea658
+	if (*dmi_size == 0) {
3ea658
+		dmilist_free(&dmi_list);
3ea658
+		fprintf(stderr, "Cannot fill in dmi_list by data from raw\n");
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+err:
3ea658
+	if (chdir(cwd)) {
3ea658
+		fprintf(stderr, "Cannot change root dir to %s\n", cwd);
3ea658
+		dmi_put_dmilist(dmi_list);
3ea658
+		dmi_list = NULL;
3ea658
+	}
3ea658
+
3ea658
+	free(cwd);
3ea658
+	return dmi_list;
3ea658
+}
3ea658
+
3ea658
+static int dmi_checksum(unsigned char *buf, unsigned char len)
3ea658
+{
3ea658
+	int i;
3ea658
+	unsigned char sum = 0;
3ea658
+
3ea658
+	for (i = 0; i < len; i++)
3ea658
+		sum += buf[i];
3ea658
+
3ea658
+	return sum == 0;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_expected_size - read dmi table size from SMBIOS entry point table.
3ea658
+ * Verify SMBIOS entry point table checksum.
3ea658
+ *
3ea658
+ * Returns dmi table size read from SMBIOS entry point table. Return 0 on error.
3ea658
+ */
3ea658
+static unsigned int dmi_get_expected_size(unsigned char *smbios)
3ea658
+{
3ea658
+	if (!memcmp(smbios, "_SM3_", 5) &&
3ea658
+	    dmi_checksum(smbios, smbios[0x06]))
3ea658
+		return le32toh(smbios[0x0C] | (smbios[0x0D] << 8) |
3ea658
+			       (smbios[0x0E] << 16) | (smbios[0x0F] << 24));
3ea658
+	else if (!memcmp(smbios, "_SM_", 4) &&
3ea658
+		 dmi_checksum(smbios, smbios[0x05]) &&
3ea658
+		 dmi_checksum(smbios + 0x10, 0x0F))
3ea658
+		return le16toh(smbios[0x16] | (smbios[0x17] << 8));
3ea658
+	else if (!memcmp(smbios, "_DMI_", 5) &&
3ea658
+		 dmi_checksum(smbios, 0x0F))
3ea658
+		return le16toh(smbios[0x06] | (smbios[0x07] << 8));
3ea658
+
3ea658
+	return 0;
3ea658
+}
3ea658
+
3ea658
+/* API */
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_table - allocate dmi table
3ea658
+ *
3ea658
+ * Returns pointer on allocated dmi_table struct on success,
3ea658
+ * otherwise returns NULL. When table is not needed it has to be
3ea658
+ * put by dmi_put_table.
3ea658
+ */
3ea658
+struct dmi_table *dmi_get_table(void)
3ea658
+{
3ea658
+	struct dmi_table *dt;
3ea658
+	unsigned int max_dmisize;
3ea658
+
3ea658
+	dt = malloc(sizeof(struct dmi_table));
3ea658
+
3ea658
+	if (!dmi_get_smbios(dt->smbios))
3ea658
+		goto err;
3ea658
+
3ea658
+	max_dmisize = dmi_get_expected_size(dt->smbios);
3ea658
+	if (max_dmisize < MIN_DMI_STRUCT_SIZE) {
3ea658
+		fprintf(stderr, "SMBIOS entry point is incorrect\n");
3ea658
+		goto err;
3ea658
+	}
3ea658
+
3ea658
+	dt->dmi_list = dmi_get_dmilist(&dt->dmi_count,
3ea658
+				       &dt->dmi_size, max_dmisize + 1);
3ea658
+	if (!dt->dmi_list)
3ea658
+		goto err;
3ea658
+
3ea658
+	return dt;
3ea658
+
3ea658
+err:
3ea658
+	free(dt);
3ea658
+	return NULL;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_put_table - used in pair with dmi_get_dmitable
3ea658
+ * @dt: dmi table pointer taken by dmi_get_table
3ea658
+ */
3ea658
+int dmi_put_table(struct dmi_table *dt)
3ea658
+{
3ea658
+	int ret = -1;
3ea658
+
3ea658
+	if (!dt) {
3ea658
+		fprintf(stderr, "pointer for DMI table is incorrect\n");
3ea658
+		return ret;
3ea658
+	}
3ea658
+
3ea658
+	ret = dmi_put_dmilist(dt->dmi_list);
3ea658
+	free(dt);
3ea658
+
3ea658
+	return ret;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_raw_data - give a pointer to raw dmi table, all raw dmi entries are
3ea658
+ * contiguously situated within this memory in original right order.
3ea658
+ * @dmi_list: dmi list only taken by dmi_get_dmilist
3ea658
+ */
3ea658
+void *dmi_get_raw_data(struct dmi_entry *dmi_list)
3ea658
+{
3ea658
+	return dmi_list->h.data;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_entry_by_handle - searches an entry in dmi list by given handle
3ea658
+ * @dmi_list: dmi list to search for
3ea658
+ * @handle: handle to find entry with
3ea658
+ *
3ea658
+ * Returns entry with given handle on success and NULL otherwise
3ea658
+ */
3ea658
+struct dmi_entry *dmi_get_entry_by_handle(struct dmi_entry *dmi_list,
3ea658
+					  int handle)
3ea658
+{
3ea658
+	struct dmi_entry *entry;
3ea658
+
3ea658
+	for (entry = dmi_list; entry; entry = entry->next)
3ea658
+		if (handle == entry->h.handle)
3ea658
+			return entry;
3ea658
+
3ea658
+	return NULL;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmi_get_next_entry_by_type - searches a next entry in dmi list by type
3ea658
+ * @dmi_entry: the dmi_entry in dmi list to search beginnig with
3ea658
+ * @type: type of dmi entry to find
3ea658
+ */
3ea658
+struct dmi_entry *dmi_get_next_entry_by_type(struct dmi_entry *dmi_entry,
3ea658
+					     unsigned char type)
3ea658
+{
3ea658
+	struct dmi_entry *entry;
3ea658
+
3ea658
+	for (entry = dmi_entry->next; entry; entry = entry->next)
3ea658
+		if (type == entry->h.type)
3ea658
+			return entry;
3ea658
+
3ea658
+	return NULL;
3ea658
+}
3ea658
+
3ea658
+/**
3ea658
+ * dmifs_is_exist - checks if dmi sysfs exists
3ea658
+ *
3ea658
+ * Returns 1 on success and 0 if no
3ea658
+ */
3ea658
+int dmifs_is_exist(void)
3ea658
+{
3ea658
+	int ret;
3ea658
+	char dmi_cat[] = "/sys/firmware/dmi/entries/";
3ea658
+	DIR *dmi_dir = opendir(dmi_cat);
3ea658
+
3ea658
+	ret = dmi_dir ? 1 : 0;
3ea658
+
3ea658
+	if (closedir(dmi_dir))
3ea658
+		fprintf(stderr, "Cannot close %s", dmi_cat);
3ea658
+
3ea658
+	return ret;
3ea658
+}
3ea658
diff --git a/libdmifs.h b/libdmifs.h
3ea658
new file mode 100644
3ea658
index 0000000..218d07f
3ea658
--- /dev/null
3ea658
+++ b/libdmifs.h
3ea658
@@ -0,0 +1,56 @@
3ea658
+#ifndef LIBDMIFS_H
3ea658
+#define LIBDMIFS_H
3ea658
+
3ea658
+/**
3ea658
+ * dmi_hdata - information of dmi entry header
3ea658
+ * type: type of dmi entry
3ea658
+ * length: length of formated area of dmi entry
3ea658
+ * data: pointer to whole raw dmi entry data
3ea658
+ */
3ea658
+struct dmi_hdata {
3ea658
+	unsigned char type;
3ea658
+	unsigned char length;
3ea658
+	unsigned short handle;
3ea658
+	unsigned char *data;
3ea658
+};
3ea658
+
3ea658
+/**
3ea658
+ * dmi_entry - holds information about dmi entry
3ea658
+ * next: internal in list pointer
3ea658
+ * h: dmi header data, including raw data
3ea658
+ * position: position within the dmi table
3ea658
+ * d_name: dirctory entry name in sysfs
3ea658
+ */
3ea658
+struct dmi_entry {
3ea658
+	struct dmi_entry *next;
3ea658
+	struct dmi_hdata h;
3ea658
+	unsigned int position;
3ea658
+	char *d_name;
3ea658
+};
3ea658
+
3ea658
+/**
3ea658
+ * dmi_table - contains whole information about smbios/dmi tables
3ea658
+ * @smbios: pointer to raw data of smbios table
3ea658
+ * @dmi_count: number of dmi entries in dmi table
3ea658
+ * @dmi_size: length of dmi table in bytes
3ea658
+ * @dmi_list: single list of dmi table entries, raw data of which contiguously
3ea658
+ *	situated in memnory. The list can be used to take a pointer to raw data
3ea658
+ *	of whole dmi table.
3ea658
+ */
3ea658
+struct dmi_table {
3ea658
+	unsigned char smbios[32];
3ea658
+	unsigned int dmi_count;
3ea658
+	unsigned int dmi_size;
3ea658
+	struct dmi_entry *dmi_list;
3ea658
+};
3ea658
+
3ea658
+int dmifs_is_exist(void);
3ea658
+struct dmi_table *dmi_get_table(void);
3ea658
+int dmi_put_table(struct dmi_table *dt);
3ea658
+void *dmi_get_raw_data(struct dmi_entry *dmi_list);
3ea658
+struct dmi_entry *dmi_get_entry_by_handle(struct dmi_entry *dmi_list,
3ea658
+					  int handle);
3ea658
+struct dmi_entry *dmi_get_next_entry_by_type(struct dmi_entry *dmi_entry,
3ea658
+					     unsigned char type);
3ea658
+
3ea658
+#endif
3ea658
--
3ea658
1.9.3