From ac357d3bb8342b2fc22980e0914cdce7758ca310 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 1 Nov 2014 18:38:08 +0100 Subject: Rewritten support for UDEV's HWDB HWDB is now handled in a way very similar to the DNS resolver. The interface lives in a separate source file (lib/names-hwdb.c), results of lookups are cached. Use of HWDB can be disabled either by passing PCI_LOOKUP_NO_HWDB or by setting the hwdb.disabled configuration parameter. Also, there should be no more leaks of libudev's structures. --- lib/Makefile | 5 ++- lib/init.c | 5 ++- lib/internal.h | 2 +- lib/names-hash.c | 61 ++---------------------------- lib/names-hwdb.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/names-parse.c | 1 + lib/names.c | 12 +++++- lib/names.h | 8 +++- lib/params.c | 1 - lib/pci.h | 5 ++- pcilib.man | 5 +++ 11 files changed, 149 insertions(+), 65 deletions(-) create mode 100644 lib/names-hwdb.c diff --git a/lib/Makefile b/lib/Makefile index 6f6efec..f119b72 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,9 +1,9 @@ # Makefile for The PCI Library -# (c) 1999--2008 Martin Mares +# (c) 1999--2014 Martin Mares # Expects to be invoked from the top-level Makefile and uses lots of its variables. -OBJS=init access generic dump names filter names-hash names-parse names-net names-cache params caps +OBJS=init access generic dump names filter names-hash names-parse names-net names-cache names-hwdb params caps INCL=internal.h pci.h config.h header.h sysdep.h types.h ifdef PCI_HAVE_PM_LINUX_SYSFS @@ -88,5 +88,6 @@ names-cache.o: names-cache.c $(INCL) names.h names-hash.o: names-hash.c $(INCL) names.h names-net.o: names-net.c $(INCL) names.h names-parse.o: names-parse.c $(INCL) names.h +names-hwdb.o: names-hwdb.c $(INCL) names.h filter.o: filter.c $(INCL) nbsd-libpci.o: nbsd-libpci.c $(INCL) diff --git a/lib/init.c b/lib/init.c index d28271e..064c932 100644 --- a/lib/init.c +++ b/lib/init.c @@ -82,7 +82,7 @@ pci_mfree(void *x) } char * -pci_strdup(struct pci_access *a, char *s) +pci_strdup(struct pci_access *a, const char *s) { int len = strlen(s) + 1; char *t = pci_malloc(a, len); @@ -162,6 +162,9 @@ pci_alloc(void) pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's"); pci_define_param(a, "net.cache_name", "~/.pciids-cache", "Name of the ID cache file"); a->id_lookup_mode = PCI_LOOKUP_CACHE; +#endif +#ifdef PCI_HAVE_HWDB + pci_define_param(a, "hwdb.disable", "0", "Do not look up names in UDEV's HWDB if non-zero"); #endif for (i=0; iconfig) diff --git a/lib/internal.h b/lib/internal.h index 18a59e2..ea63738 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -59,7 +59,7 @@ int pci_generic_block_write(struct pci_dev *, int pos, byte *buf, int len); /* init.c */ void *pci_malloc(struct pci_access *, int); void pci_mfree(void *); -char *pci_strdup(struct pci_access *a, char *s); +char *pci_strdup(struct pci_access *a, const char *s); /* access.c */ struct pci_dev *pci_alloc_dev(struct pci_access *); diff --git a/lib/names-hash.c b/lib/names-hash.c index 9661d03..2f5bc3c 100644 --- a/lib/names-hash.c +++ b/lib/names-hash.c @@ -11,11 +11,6 @@ #include "internal.h" #include "names.h" -#ifdef PCI_HAVE_HWDB -#include -#include -#endif - struct id_bucket { struct id_bucket *next; unsigned int full; @@ -91,58 +86,8 @@ char *pci_id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4) { struct id_entry *n, *best; - u32 id12, id34; - -#ifdef PCI_HAVE_HWDB - if (!(flags & PCI_LOOKUP_SKIP_LOCAL)) - { - char modalias[64]; - const char *key = NULL; - struct udev *udev = udev_new(); - struct udev_hwdb *hwdb = udev_hwdb_new(udev); - struct udev_list_entry *entry; - - switch(cat) - { - case ID_VENDOR: - sprintf(modalias, "pci:v%08X*", id1); - key = "ID_VENDOR_FROM_DATABASE"; - break; - case ID_DEVICE: - sprintf(modalias, "pci:v%08Xd%08X*", id1, id2); - key = "ID_MODEL_FROM_DATABASE"; - break; - case ID_SUBSYSTEM: - sprintf(modalias, "pci:v%08Xd%08Xsv%08Xsd%08X*", id1, id2, id3, id4); - key = "ID_MODEL_FROM_DATABASE"; - break; - case ID_GEN_SUBSYSTEM: - sprintf(modalias, "pci:v*d*sv%08Xsd%08X*", id1, id2); - key = "ID_MODEL_FROM_DATABASE"; - break; - case ID_CLASS: - sprintf(modalias, "pci:v*d*sv*sd*bc%02X*", id1); - key = "ID_PCI_CLASS_FROM_DATABASE"; - break; - case ID_SUBCLASS: - sprintf(modalias, "pci:v*d*sv*sd*bc%02Xsc%02X*", id1, id2); - key = "ID_PCI_SUBCLASS_FROM_DATABASE"; - break; - case ID_PROGIF: - sprintf(modalias, "pci:v*d*sv*sd*bc%02Xsc%02Xi%02X*", id1, id2, id3); - key = "ID_PCI_INTERFACE_FROM_DATABASE"; - break; - } - - if (key) - udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) - if (strcmp(udev_list_entry_get_name(entry), key) == 0) - return udev_list_entry_get_value(entry); - } -#endif - - id12 = id_pair(id1, id2); - id34 = id_pair(id3, id4); + u32 id12 = id_pair(id1, id2); + u32 id34 = id_pair(id3, id4); if (a->id_hash) { @@ -158,6 +103,8 @@ char continue; if (n->src == SRC_CACHE && !(flags & PCI_LOOKUP_CACHE)) continue; + if (n->src == SRC_HWDB && (flags & (PCI_LOOKUP_SKIP_LOCAL | PCI_LOOKUP_NO_HWDB))) + continue; if (!best || best->src < n->src) best = n; } diff --git a/lib/names-hwdb.c b/lib/names-hwdb.c new file mode 100644 index 0000000..07b3499 --- /dev/null +++ b/lib/names-hwdb.c @@ -0,0 +1,109 @@ +/* + * The PCI Library -- Looking up Names via UDEV and HWDB + * + * Copyright (c) 2013--2014 Tom Gundersen + * Copyright (c) 2014 Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include + +#include "internal.h" +#include "names.h" + +#ifdef PCI_HAVE_HWDB + +#include +#include +#include + +char * +pci_id_hwdb_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4) +{ + char modalias[64]; + const char *key = NULL; + + const char *disabled = pci_get_param(a, "hwdb.disable"); + if (disabled && atoi(disabled)) + return NULL; + + switch (cat) + { + case ID_VENDOR: + sprintf(modalias, "pci:v%08X*", id1); + key = "ID_VENDOR_FROM_DATABASE"; + break; + case ID_DEVICE: + sprintf(modalias, "pci:v%08Xd%08X*", id1, id2); + key = "ID_MODEL_FROM_DATABASE"; + break; + case ID_SUBSYSTEM: + sprintf(modalias, "pci:v%08Xd%08Xsv%08Xsd%08X*", id1, id2, id3, id4); + key = "ID_MODEL_FROM_DATABASE"; + break; + case ID_GEN_SUBSYSTEM: + sprintf(modalias, "pci:v*d*sv%08Xsd%08X*", id1, id2); + key = "ID_MODEL_FROM_DATABASE"; + break; + case ID_CLASS: + sprintf(modalias, "pci:v*d*sv*sd*bc%02X*", id1); + key = "ID_PCI_CLASS_FROM_DATABASE"; + break; + case ID_SUBCLASS: + sprintf(modalias, "pci:v*d*sv*sd*bc%02Xsc%02X*", id1, id2); + key = "ID_PCI_SUBCLASS_FROM_DATABASE"; + break; + case ID_PROGIF: + sprintf(modalias, "pci:v*d*sv*sd*bc%02Xsc%02Xi%02X*", id1, id2, id3); + key = "ID_PCI_INTERFACE_FROM_DATABASE"; + break; + } + + if (key) + { + if (!a->id_udev_hwdb) + { + a->debug("Initializing UDEV HWDB\n"); + a->id_udev = udev_new(); + a->id_udev_hwdb = udev_hwdb_new(a->id_udev); + } + + struct udev_list_entry *entry; + udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(a->id_udev_hwdb, modalias, 0)) + if (strcmp(udev_list_entry_get_name(entry), key) == 0) + return pci_strdup(a, udev_list_entry_get_value(entry)); + } + + return NULL; +} + +void +pci_id_hwdb_free(struct pci_access *a) +{ + if (a->id_udev_hwdb) + { + udev_hwdb_unref(a->id_udev_hwdb); + a->id_udev_hwdb = NULL; + } + if (a->id_udev) + { + udev_unref(a->id_udev); + a->id_udev = NULL; + } +} + +#else + +char * +pci_id_hwdb_lookup(struct pci_access *a UNUSED, int cat UNUSED, int id1 UNUSED, int id2 UNUSED, int id3 UNUSED, int id4 UNUSED) +{ + return NULL; +} + +void +pci_id_hwdb_free(struct pci_access *a UNUSED) +{ +} + +#endif diff --git a/lib/names-parse.c b/lib/names-parse.c index 4997b58..f3b7da9 100644 --- a/lib/names-parse.c +++ b/lib/names-parse.c @@ -238,6 +238,7 @@ pci_free_name_list(struct pci_access *a) { pci_id_cache_flush(a); pci_id_hash_free(a); + pci_id_hwdb_free(a); a->id_load_failed = 0; } diff --git a/lib/names.c b/lib/names.c index bda8c90..d5353a8 100644 --- a/lib/names.c +++ b/lib/names.c @@ -1,7 +1,7 @@ /* * The PCI Library -- ID to Name Translation * - * Copyright (c) 1997--2008 Martin Mares + * Copyright (c) 1997--2014 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -16,6 +16,7 @@ static char *id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4) { char *name; + int tried_hwdb = 0; while (!(name = pci_id_lookup(a, flags, cat, id1, id2, id3, id4))) { @@ -24,6 +25,15 @@ static char *id_lookup(struct pci_access *a, int flags, int cat, int id1, int id if (pci_id_cache_load(a, flags)) continue; } + if (!tried_hwdb && !(flags & (PCI_LOOKUP_SKIP_LOCAL | PCI_LOOKUP_NO_HWDB))) + { + tried_hwdb = 1; + if (name = pci_id_hwdb_lookup(a, cat, id1, id2, id3, id4)) + { + pci_id_insert(a, cat, id1, id2, id3, id4, name, SRC_HWDB); + continue; + } + } if (flags & PCI_LOOKUP_NETWORK) { if (name = pci_id_net_lookup(a, cat, id1, id2, id3, id4)) diff --git a/lib/names.h b/lib/names.h index 81c373f..d7e71ff 100644 --- a/lib/names.h +++ b/lib/names.h @@ -1,7 +1,7 @@ /* * The PCI Library -- ID to Name Translation * - * Copyright (c) 1997--2008 Martin Mares + * Copyright (c) 1997--2014 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -33,6 +33,7 @@ enum id_entry_src { SRC_UNKNOWN, SRC_CACHE, SRC_NET, + SRC_HWDB, SRC_LOCAL, }; @@ -67,3 +68,8 @@ void pci_id_hash_free(struct pci_access *a); /* names-dns.c */ char *pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4); + +/* names-hwdb.c */ + +char *pci_id_hwdb_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4); +void pci_id_hwdb_free(struct pci_access *a); diff --git a/lib/params.c b/lib/params.c index 0e6edbb..4d48cab 100644 --- a/lib/params.c +++ b/lib/params.c @@ -85,4 +85,3 @@ pci_walk_params(struct pci_access *acc, struct pci_param *prev) else return prev->next; } - diff --git a/lib/pci.h b/lib/pci.h index 37f08e6..8b1d024 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -1,7 +1,7 @@ /* * The PCI Library * - * Copyright (c) 1997--2013 Martin Mares + * Copyright (c) 1997--2014 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -73,6 +73,8 @@ struct pci_access { struct id_bucket *current_id_bucket; int id_load_failed; int id_cache_status; /* 0=not read, 1=read, 2=dirty */ + struct udev *id_udev; /* names-hwdb.c */ + struct udev_hwdb *id_udev_hwdb; int fd; /* proc/sys: fd for config space */ int fd_rw; /* proc/sys: fd opened read-write */ int fd_pos; /* proc/sys: current position */ @@ -240,6 +242,7 @@ enum pci_lookup_mode { PCI_LOOKUP_SKIP_LOCAL = 0x100000, /* Do not consult local database */ PCI_LOOKUP_CACHE = 0x200000, /* Consult the local cache before using DNS */ PCI_LOOKUP_REFRESH_CACHE = 0x400000, /* Forget all previously cached entries, but still allow updating the cache */ + PCI_LOOKUP_NO_HWDB = 0x800000, /* Do not ask udev's hwdb */ }; #endif diff --git a/pcilib.man b/pcilib.man index 60c0bb1..dde7e2f 100644 --- a/pcilib.man +++ b/pcilib.man @@ -104,6 +104,11 @@ DNS domain containing the ID database. .B net.cache_name Name of the file used for caching of resolved ID's. +.SS Parameters for resolving of ID's via UDEV's HWDB +.TP +.B hwdb.disable +Disable use of HWDB if set to a non-zero value. + .SH SEE ALSO .BR lspci (8), -- cgit v1.2.1