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