diff options
author | Pascal Rigaux <pixel@mandriva.com> | 2005-03-14 12:32:43 +0000 |
---|---|---|
committer | Pascal Rigaux <pixel@mandriva.com> | 2005-03-14 12:32:43 +0000 |
commit | 4fcbd8f87cab61e77ce04d958991ca59604b7e86 (patch) | |
tree | 8a087c2c5eba1cac85556d307daad7304efd6e96 | |
parent | 869c403c497d881a099e401ebd9e3f3db0f75599 (diff) | |
download | ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar.gz ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar.bz2 ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.tar.xz ldetect-4fcbd8f87cab61e77ce04d958991ca59604b7e86.zip |
add dmitable use
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | common.c | 74 | ||||
-rw-r--r-- | common.h | 14 | ||||
-rw-r--r-- | dmi.c | 280 | ||||
-rw-r--r-- | ldetect.spec | 5 | ||||
-rw-r--r-- | libldetect-private.h | 1 | ||||
-rw-r--r-- | libldetect.h | 15 | ||||
-rw-r--r-- | lspcidrake.c | 13 | ||||
-rw-r--r-- | pciusb.c | 68 |
9 files changed, 398 insertions, 75 deletions
@@ -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); +} @@ -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); @@ -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; } @@ -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; |