summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPascal Rigaux <pixel@mandriva.com>2005-03-14 12:32:43 +0000
committerPascal Rigaux <pixel@mandriva.com>2005-03-14 12:32:43 +0000
commit4fcbd8f87cab61e77ce04d958991ca59604b7e86 (patch)
tree8a087c2c5eba1cac85556d307daad7304efd6e96
parent869c403c497d881a099e401ebd9e3f3db0f75599 (diff)
downloadldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar
ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar.gz
ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar.bz2
ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar.xz
ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.zip
add dmitable use
-rw-r--r--Makefile3
-rw-r--r--common.c74
-rw-r--r--common.h14
-rw-r--r--dmi.c280
-rw-r--r--ldetect.spec5
-rw-r--r--libldetect-private.h1
-rw-r--r--libldetect.h15
-rw-r--r--lspcidrake.c13
-rw-r--r--pciusb.c68
9 files changed, 398 insertions, 75 deletions
diff --git a/Makefile b/Makefile
index 14ee9f8..e5fb808 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ build: $(binaries) $(libraries)
lspcidrake: lspcidrake.c libldetect.a
-libldetect.a: pciusb.o pci.o usb.o pciclass.o usbclass.o
+libldetect.a: common.o pciusb.o pci.o usb.o pciclass.o usbclass.o dmi.o
ar rsc $@ $^
pciclass.c: /usr/include/linux/pci.h /usr/include/linux/pci_ids.h
@@ -30,6 +30,7 @@ usbclass.c: /usr/share/usb.ids
pciusb.o: pciusb.c libldetect.h libldetect-private.h common.h
pci.o: pci.c libldetect.h libldetect-private.h common.h
usb.o: usb.c libldetect.h libldetect-private.h common.h
+dmi.o: dmi.c libldetect.h libldetect-private.h common.h
clean:
rm -f *~ *.o pciclass.c usbclass.c $(binaries) $(libraries)
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..e82c5fb
--- /dev/null
+++ b/common.c
@@ -0,0 +1,74 @@
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "common.h"
+
+static char *table_name_to_file(const char *name) {
+
+ char *share_path = getenv("SHARE_PATH");
+ char *fname;
+ if (!share_path || !*share_path) share_path = "/usr/share";
+
+ asprintf(&fname, "%s/ldetect-lst/%s", share_path, name);
+ return fname;
+}
+
+extern fh fh_open(const char *name) {
+ fh ret;
+ char *fname = table_name_to_file(name);
+ int length = strlen(fname);
+
+ if (access(fname, R_OK) == 0) {
+ ret.f = fopen(fname, "r");
+ ret.pid = 0;
+ } else {
+ int fdno[2];
+ char *fname_gz = alloca(length + sizeof(".gz"));
+ sprintf(fname_gz, "%s.gz", fname);
+ if (access(fname_gz, R_OK) != 0) {
+ fprintf(stderr, "Missing %s (should be %s)\n", name, fname);
+ exit(1);
+ }
+ if (pipe(fdno)) {
+ perror("pciusb");
+ exit(1);
+ }
+
+ if ((ret.pid = fork()) != 0) {
+ ret.f = fdopen(fdno[0], "r");
+ close(fdno[1]);
+ } else {
+ char* cmd[5];
+ int ip = 0;
+ char *ld_loader = getenv("LD_LOADER");
+
+ if (ld_loader && *ld_loader)
+ cmd[ip++] = ld_loader;
+
+ cmd[ip++] = "gzip";
+ cmd[ip++] = "-cd";
+ cmd[ip++] = fname_gz;
+ cmd[ip++] = NULL;
+
+ dup2(fdno[1], STDOUT_FILENO);
+ close(fdno[0]);
+ close(fdno[1]);
+ execvp(cmd[0], cmd);
+ perror("pciusb");
+ exit(2);
+ }
+ }
+ free(fname);
+ return ret;
+}
+
+extern void fh_close(fh *f) {
+ fclose(f->f);
+ if (f->pid > 0)
+ waitpid(f->pid, NULL, 0);
+}
diff --git a/common.h b/common.h
index 9957d42..0458ba5 100644
--- a/common.h
+++ b/common.h
@@ -1,8 +1,10 @@
#define psizeof(a) (sizeof(a) / sizeof(*(a)))
-
-static inline void *memdup(void *src, size_t size) {
- void *r = malloc(size);
- memcpy(r, src, size);
- return r;
-}
#define ifree(p) do { if (p) { free(p); p = NULL; } } while (0)
+
+
+typedef struct {
+ FILE *f;
+ pid_t pid;
+} fh;
+extern fh fh_open(const char *name);
+extern void fh_close(fh *f);
diff --git a/dmi.c b/dmi.c
new file mode 100644
index 0000000..a09fcd8
--- /dev/null
+++ b/dmi.c
@@ -0,0 +1,280 @@
+/* DMI (Desktop Management Interface)
+ also called
+ SMBIOS (System Management BIOS)
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libldetect.h"
+#include "libldetect-private.h"
+#include "common.h"
+
+char *dmidecode_file = NULL;
+
+
+static const char *cat_BIOS[] = { "Vendor", "Version" };
+static const char *cat_System[] = { "Manufacturer", "Product Name", "Version" };
+static const char *cat_Base_Board[] = { "Manufacturer", "Product Name", "Version" };
+
+struct category {
+ const char *cat_name;
+ unsigned int nb_fields;
+ const char **fields;
+};
+
+static struct category categories[] = {
+ { "BIOS", psizeof(cat_BIOS), cat_BIOS },
+ { "System", psizeof(cat_System), cat_System },
+ { "Base Board", psizeof(cat_Base_Board), cat_Base_Board },
+
+};
+static int nb_categories = psizeof(categories);
+
+struct criterion {
+ char *name;
+ char *val;
+};
+struct criteria {
+ unsigned int nb;
+ struct criterion *criteria;
+};
+
+/*********************************************************************************/
+static int streq(const char *s1, const char *s2) {
+ return strcmp(s1, s2) == 0;
+}
+static int str_begins_with(const char *s, const char *prefix) {
+ return strncmp(s, prefix, strlen(prefix)) == 0;
+}
+static int remove_suffix_in_place(char *s, const char *suffix) {
+ unsigned int l = strlen(s);
+ unsigned int l_suffix = strlen(suffix);
+ if (l >= l_suffix && streq(s + l - l_suffix, suffix)) {
+ s[l - l_suffix] = '\0';
+ return 1;
+ } else
+ return 0;
+}
+static void remove_ending_spaces(char *s) {
+ char *p;
+ for (p = s + strlen(s) - 1; p >= s; p--) {
+ if (*p != '\n' && *p != '\r' && *p != ' ' && *p != '\t')
+ break;
+ *p = '\0';
+ }
+}
+static char *skip_leading_spaces(char *s) {
+ for (; *s; s++)
+ if (*s != '\n' && *s != '\r' && *s != ' ' && *s != '\t')
+ break;
+ return s;
+}
+
+/*********************************************************************************/
+static char *get_after_colon(char *s) {
+ char *p = strchr(s, ':');
+ if (p) {
+ *p = '\0';
+ return p + (p[1] == ' ' ? 2 : 1);
+ } else return NULL;
+}
+
+struct category *lookup_category(const char *cat_name) {
+ int i;
+ for (i = 0; i < nb_categories; i++)
+ if (streq(categories[i].cat_name, cat_name))
+ return &categories[i];
+ return NULL;
+}
+
+int lookup_field(struct category *category, const char *field_name) {
+ unsigned int i;
+ for (i = 0; i < category->nb_fields; i++)
+ if (streq(category->fields[i], field_name))
+ return 1;
+ return 0;
+}
+
+char *lookup_criteria(struct criteria criteria, const char *field) {
+ unsigned int i;
+ for (i = 0; i < criteria.nb; i++)
+ if (streq(criteria.criteria[i].name, field))
+ return criteria.criteria[i].val;
+ return NULL;
+}
+
+/*********************************************************************************/
+static struct criteria criteria_from_dmidecode(void) {
+ FILE *f;
+ char buf[BUF_SIZE];
+
+ struct criteria r;
+
+ r.nb = 0;
+
+ if (!(f = dmidecode_file ? fopen(dmidecode_file, "r") : popen("dmidecode", "r"))) {
+ perror("dmidecode");
+ return r;
+ }
+
+ r.criteria = malloc(sizeof(*r.criteria) * MAX_DEVICES);
+
+ struct category *category = NULL;
+ while (fgets(buf, sizeof(buf) - 1, f)) {
+ if (!buf[0] || !buf[1] || buf[0] != '\t')
+ ; /* don't care */
+ else if (buf[1] != '\t') {
+ char *s = buf + 1;
+ if (!str_begins_with(s, "DMI type ")) {
+ remove_ending_spaces(s);
+ remove_suffix_in_place(s, " Information");
+ category = lookup_category(s);
+ }
+ } else if (category) {
+ /* don't even look if we don't have an interesting category */
+ char *s = buf + 2;
+ char *val = get_after_colon(s);
+ if (val && lookup_field(category, s)) {
+ struct criterion *criterion = &r.criteria[r.nb++];
+ asprintf(&criterion->name, "%s/%s", category->cat_name, s);
+ remove_ending_spaces(val);
+ criterion->val = strdup(skip_leading_spaces(val));
+ }
+ }
+ }
+ if (dmidecode_file ? fclose(f) != 0 : pclose(f) == -1) {
+ r.nb = 0;
+ return r;
+ }
+ realloc(r.criteria, sizeof(*r.criteria) * r.nb);
+
+ return r;
+}
+
+static void free_criteria(struct criteria criteria) {
+ unsigned int i;
+ for (i = 0; i < criteria.nb; i++) {
+ free(criteria.criteria[i].name);
+ free(criteria.criteria[i].val);
+ }
+ if (criteria.nb) free(criteria.criteria);
+ criteria.nb = 0;
+}
+
+static struct dmi_entries entries_matching_criteria(struct criteria criteria) {
+ fh f;
+ char buf[2048];
+ int line;
+ struct dmi_entries r;
+ #define MAX_INDENT 20
+ int valid[MAX_INDENT];
+ char *constraints[MAX_INDENT];
+
+ enum state { in_constraints, in_implies } state = in_implies;
+ int was_a_blank_line = 1;
+
+ r.nb = 0;
+ f = fh_open("dmitable");
+
+#define die(err) do { fprintf(stderr, "%s %d: " err "\n", "dmitable", line); exit(1); } while (0)
+
+ r.entries = malloc(sizeof(*r.entries) * MAX_DEVICES);
+
+#define foreach_indent(min, action) do { int i; for (i = min; i < MAX_INDENT; i++) { action; } } while (0)
+
+ foreach_indent(0, valid[i] = 1; constraints[i] = NULL);
+
+ int previous_refine = 0;
+
+ for (line = 1; fgets(buf, sizeof(buf) - 1, f.f); line++) {
+ char *s = skip_leading_spaces(buf);
+ if (*s == '#') continue; // skip comments
+
+ if (!*s) {
+ was_a_blank_line = 1;
+ } else {
+ int refine = s - buf;
+ if (refine > MAX_INDENT) die("too indented constraints");
+
+ remove_ending_spaces(s);
+ if (str_begins_with(s, "=> ")) {
+ if (refine != previous_refine) die("\"=>\" must not be indented");
+ state = in_implies;
+ was_a_blank_line = 0;
+
+ if (valid[refine]) {
+ struct dmi_entry *entry = &r.entries[r.nb++];
+
+ s += strlen("=> ");
+ char *val = get_after_colon(s);
+ if (!val) die("invalid value");
+ asprintf(&entry->module, "%s:%s", s, val);
+
+ char tmp[BUF_SIZE];
+ tmp[0] = '\0';
+
+ int i;
+ for (i = 0; i <= refine; i++)
+ if (constraints[i]) {
+ if (i) strncat(tmp, "|", BUF_SIZE);
+ strncat(tmp, constraints[i], BUF_SIZE);
+ }
+ entry->constraints = strdup(tmp);
+ }
+ } else {
+ if (state == in_constraints && refine == previous_refine) die("to refine, indent");
+ if (!was_a_blank_line) die("missing empty line");
+ state = in_constraints;
+ previous_refine = refine;
+ was_a_blank_line = 0;
+
+ if (refine == 0 || valid[refine - 1]) {
+
+ char *wanted_val = get_after_colon(s);
+ if (!wanted_val) die("bad format");
+
+ char *wanted_val_orig = strdup(wanted_val);
+ char *val = lookup_criteria(criteria, s);
+
+ int ok = wanted_val && val && (
+ remove_suffix_in_place(wanted_val, ".*") ?
+ str_begins_with(val, wanted_val) :
+ streq(val, wanted_val));
+
+ foreach_indent(refine, valid[i] = ok; ifree(constraints[i]));
+ if (ok)
+ constraints[refine] = wanted_val_orig;
+ else
+ free(wanted_val_orig);
+
+ } /* otherwise no need checking */
+ }
+ }
+ }
+ foreach_indent(0, ifree(constraints[i]));
+ fh_close(&f);
+
+ realloc(r.entries, sizeof(*r.entries) * r.nb);
+ return r;
+}
+
+extern void dmi_entries_free(struct dmi_entries entries) {
+ unsigned int i;
+ for (i = 0; i < entries.nb; i++) {
+ free(entries.entries[i].constraints);
+ free(entries.entries[i].module);
+ }
+ if (entries.nb) free(entries.entries);
+ entries.nb = 0;
+}
+
+extern struct dmi_entries dmi_probe(void) {
+ struct criteria criteria = criteria_from_dmidecode();
+ struct dmi_entries entries = entries_matching_criteria(criteria);
+ free_criteria(criteria);
+
+ return entries;
+}
+
diff --git a/ldetect.spec b/ldetect.spec
index a6aea44..55a0eb3 100644
--- a/ldetect.spec
+++ b/ldetect.spec
@@ -1,5 +1,5 @@
Name: ldetect
-Version: 0.5.5
+Version: 0.5.6
Release: 1mdk
Summary: Light hardware detection library
Source: %name.tar.bz2
@@ -50,6 +50,9 @@ rm -rf $RPM_BUILD_ROOT
%_libdir/*
%changelog
+* Mon Mar 14 2005 Pixel <pixel@mandrakesoft.com> 0.5.6-1mdk
+- add dmitable parsing and use
+
* Thu Feb 17 2005 Thierry Vignaud <tvignaud@mandrakesoft.com> 0.5.5-1mdk
- handle a few more special cases (gdth, snd-vx222, 8139too, and agp bridges)
- detect new VIA SATA controllers like kernel does
diff --git a/libldetect-private.h b/libldetect-private.h
index faa607f..341ed55 100644
--- a/libldetect-private.h
+++ b/libldetect-private.h
@@ -7,3 +7,4 @@ extern void pciusb_initialize(struct pciusb_entry *e);
extern char *proc_usb_path;
extern char *proc_pci_path;
+extern char *dmidecode_file;
diff --git a/libldetect.h b/libldetect.h
index 3a55501..9146f27 100644
--- a/libldetect.h
+++ b/libldetect.h
@@ -43,3 +43,18 @@ struct usb_class_text {
};
extern struct usb_class_text usb_class2text(unsigned long class_);
+
+/******************************************************************************/
+/* dmi ************************************************************************/
+/******************************************************************************/
+struct dmi_entry {
+ char *constraints;
+ char *module;
+};
+struct dmi_entries {
+ struct dmi_entry *entries;
+ unsigned int nb;
+};
+
+extern struct dmi_entries dmi_probe(void);
+extern void dmi_entries_free(struct dmi_entries entries);
diff --git a/lspcidrake.c b/lspcidrake.c
index e1026a7..c398aa1 100644
--- a/lspcidrake.c
+++ b/lspcidrake.c
@@ -44,6 +44,11 @@ static void print_usb_class(unsigned long class_) {
}
}
+static void print_dmi_entries(struct dmi_entries entries) {
+ unsigned int i;
+ for (i = 0; i < entries.nb; i++)
+ printf("%-16s: %s\n", entries.entries[i].module, entries.entries[i].constraints);
+}
int main(int argc, char **argv) {
char ** ptr = argv;
@@ -54,6 +59,7 @@ int main(int argc, char **argv) {
"-p <file>: pci devices source [/proc/bus/pci/devices by default]\n"
"-u <file>: usb devices source [/proc/bus/usb/devices by default]\n"
"-v : verbose mode [print ids and sub-ids], implies full probe\n"
+ "--dmidecode <file>: to use this dmidecode output instead of calling dmidecode\n"
);
return 0;
}
@@ -63,10 +69,17 @@ int main(int argc, char **argv) {
proc_usb_path = *++ptr;
else if (!strcmp(*ptr, "-p"))
proc_pci_path = *++ptr;
+ else if (!strcmp(*ptr, "--dmidecode"))
+ dmidecode_file = *++ptr;
ptr++;
}
printit(pci_probe(), print_pci_class);
printit(usb_probe(), print_usb_class);
+
+ struct dmi_entries dmi_entries = dmi_probe();
+ print_dmi_entries(dmi_entries);
+ free_dmi_entries(dmi_entries);
+
return 0;
}
diff --git a/pciusb.c b/pciusb.c
index ee9b684..8b6f706 100644
--- a/pciusb.c
+++ b/pciusb.c
@@ -1,5 +1,4 @@
#define _GNU_SOURCE
-
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
@@ -13,77 +12,12 @@
#include "libldetect-private.h"
#include "common.h"
-typedef struct {
- FILE *f;
- pid_t pid;
-} fh;
-
-static fh fh_open(char *fname) {
- fh ret;
- int length = strlen(fname);
-
- if (access(fname, R_OK) == 0) {
- ret.f = fopen(fname, "r");
- ret.pid = 0;
- } else {
- int fdno[2];
- char *fname_gz = alloca(length + sizeof(".gz"));
- sprintf(fname_gz, "%s.gz", fname);
- if (access(fname_gz, R_OK) != 0) {
- fprintf(stderr, "Missing pciusbtable (should be %s)\n", fname);
- exit(1);
- }
- if (pipe(fdno)) {
- perror("pciusb");
- exit(1);
- }
-
- if ((ret.pid = fork()) != 0) {
- ret.f = fdopen(fdno[0], "r");
- close(fdno[1]);
- } else {
- char* cmd[5];
- int ip = 0;
- char *ld_loader = getenv("LD_LOADER");
-
- if (ld_loader && *ld_loader)
- cmd[ip++] = ld_loader;
-
- cmd[ip++] = "gzip";
- cmd[ip++] = "-cd";
- cmd[ip++] = fname_gz;
- cmd[ip++] = NULL;
-
- dup2(fdno[1], STDOUT_FILENO);
- close(fdno[0]);
- close(fdno[1]);
- execvp(cmd[0], cmd);
- perror("pciusb");
- exit(2);
- }
- }
- return ret;
-}
-
-static void fh_close(fh *f) {
- fclose(f->f);
- if (f->pid > 0)
- waitpid(f->pid, NULL, 0);
-}
-
extern int pciusb_find_modules(struct pciusb_entries *entries, const char *fpciusbtable) {
fh f;
char buf[2048];
int line;
- char *share_path = getenv("SHARE_PATH");
- char *fname;
- if (!share_path || !*share_path) share_path = "/usr/share";
-
- fname = alloca(strlen(share_path) + sizeof("/ldetect-lst/") + strlen(fpciusbtable));
- sprintf(fname, "%s/ldetect-lst/%s", share_path, fpciusbtable);
-
- f = fh_open(fname);
+ f = fh_open(fpciusbtable);
for (line = 1; fgets(buf, sizeof(buf) - 1, f.f); line++) {
unsigned short vendor, device, subvendor, subdevice;