From 17ec7e70ea71a3ccbccf9f3b9cfe846eb1200e0d Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Mon, 1 Apr 2013 15:44:12 +0200 Subject: [PATCH] On newer Linux systems, use libkmod to look up kernel modules With modutils built upon libkmod, modules.pcimap does not exist any longer. --- Makefile | 8 ++- lib/configure | 33 +++++++++- ls-kernel.c | 167 ++++++++++++++++++++++++++++++++++++++++++-------- lspci.c | 1 + lspci.h | 1 + 5 files changed, 184 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index fb240ca..fbc045d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Makefile for The PCI Utilities -# (c) 1998--2012 Martin Mares +# (c) 1998--2013 Martin Mares OPT=-O2 CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes @@ -21,6 +21,9 @@ DNS= # Build libpci as a shared library (yes/no; or local for testing; requires GCC) SHARED=no +# Use libkmod to resolve kernel modules on Linux (yes/no, default: detect) +LIBKMOD= + # ABI version suffix in the name of the shared library # (as we use proper symbol versioning, this seldom needs changing) ABI_VERSION=.3 @@ -78,6 +81,9 @@ ls-map.o: ls-map.c $(LSPCIINC) setpci.o: setpci.c pciutils.h $(PCIINC) common.o: common.c pciutils.h $(PCIINC) +lspci: LDLIBS+=$(LIBKMOD_LIBS) +ls-kernel.o: CFLAGS+=$(LIBKMOD_CFLAGS) + update-pciids: update-pciids.sh sed <$< >$@ "s@^DEST=.*@DEST=$(IDSDIR)/$(PCI_IDS)@;s@^PCI_COMPRESSED_IDS=.*@PCI_COMPRESSED_IDS=$(PCI_COMPRESSED_IDS)@" chmod +x $@ diff --git a/lib/configure b/lib/configure index 4ae20d4..86bd43c 100755 --- a/lib/configure +++ b/lib/configure @@ -1,6 +1,6 @@ #!/bin/sh # Configuration script for the PCI library -# (c) 1998--2009 Martin Mares +# (c) 1998--2013 Martin Mares LC_ALL=C export LC_ALL @@ -179,6 +179,37 @@ if [ "$DNS" = yes ] ; then echo >>$m "WITH_LIBS+=$LIBRESOLV" fi +if [ "$sys" = linux ] ; then + echo_n "Checking for libkmod... " + LIBKMOD_DETECTED= + if [ "$LIBKMOD" != no ] ; then + if ! which pkg-config >/dev/null ; then + echo_n "(pkg-config not found) " + elif pkg-config libkmod ; then + LIBKMOD_DETECTED=1 + fi + fi + if [ "$LIBKMOD" = yes -o "$LIBKMOD" = no ] ; then + echo "$LIBKMOD (set manually)" + if [ "$LIBKMOD" = yes -a -z "$LIBKMOD_DETECTED" ] ; then + echo "Requested use of libkmod, but it is not available. Giving up." + exit 1 + fi + else + if [ -n "$LIBKMOD_DETECTED" ] ; then + LIBKMOD=yes + else + LIBKMOD=no + fi + echo "$LIBKMOD (auto-detected)" + fi + if [ "$LIBKMOD" = yes ] ; then + echo >>$c "#define PCI_USE_LIBKMOD" + echo >>$m "LIBKMOD_CFLAGS=$(pkg-config --cflags libkmod)" + echo >>$m "LIBKMOD_LIBS=$(pkg-config --libs libkmod)" + fi +fi + echo "Checking whether to build a shared library... $SHARED (set manually)" if [ "$SHARED" = no ] ; then echo >>$m 'PCILIB=$(LIBNAME).a' diff --git a/ls-kernel.c b/ls-kernel.c index 41afefe..15aa46a 100644 --- a/ls-kernel.c +++ b/ls-kernel.c @@ -1,7 +1,7 @@ /* * The PCI Utilities -- Show Kernel Drivers * - * Copyright (c) 1997--2008 Martin Mares + * Copyright (c) 1997--2013 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -16,6 +16,94 @@ #include +#ifdef PCI_USE_LIBKMOD + +#include + +static struct kmod_ctx *kmod_ctx; + +static int +show_kernel_init(void) +{ + static int show_kernel_inited = -1; + if (show_kernel_inited >= 0) + return show_kernel_inited; + + struct utsname uts; + if (uname(&uts) < 0) + die("uname() failed: %m"); + char *name = alloca(64 + strlen(uts.release)); + sprintf(name, "/lib/modules/%s", uts.release); + + kmod_ctx = kmod_new(name, NULL); + if (!kmod_ctx) + { + fprintf(stderr, "lspci: Unable to initialize libkmod context\n"); + goto failed; + } + + int err; + if ((err = kmod_load_resources(kmod_ctx)) < 0) + { + fprintf(stderr, "lspci: Unable to load libkmod resources: error %d\n", err); + goto failed; + } + + show_kernel_inited = 1; + return 1; + +failed: + show_kernel_inited = 0; + return 0; +} + +void +show_kernel_cleanup(void) +{ + if (kmod_ctx) + kmod_unref(kmod_ctx); +} + +static const char *next_module(struct device *d) +{ + static struct kmod_list *klist, *kcurrent; + static struct kmod_module *kmodule; + + if (kmodule) + { + kmod_module_unref(kmodule); + kmodule = NULL; + } + + if (!klist) + { + pci_fill_info(d->dev, PCI_FILL_MODULE_ALIAS); + if (!d->dev->module_alias) + return NULL; + int err = kmod_module_new_from_lookup(kmod_ctx, d->dev->module_alias, &klist); + if (err < 0) + { + fprintf(stderr, "lspci: libkmod lookup failed: error %d\n", err); + return NULL; + } + kcurrent = klist; + } + else + kcurrent = kmod_list_next(klist, kcurrent); + + if (kcurrent) + { + kmodule = kmod_module_get_module(kcurrent); + return kmod_module_get_name(kmodule); + } + + kmod_module_unref_list(klist); + klist = NULL; + return NULL; +} + +#else + struct pcimap_entry { struct pcimap_entry *next; unsigned int vendor, device; @@ -26,8 +114,8 @@ struct pcimap_entry { static struct pcimap_entry *pcimap_head; -static void -load_pcimap(void) +static int +show_kernel_init(void) { static int tried_pcimap; struct utsname uts; @@ -35,7 +123,7 @@ load_pcimap(void) FILE *f; if (tried_pcimap) - return; + return 1; tried_pcimap = 1; if (name = opt_pcimap) @@ -52,7 +140,7 @@ load_pcimap(void) sprintf(name, "/lib/modules/%s/modules.pcimap", uts.release); f = fopen(name, "r"); if (!f) - return; + return 1; } while (fgets(line, sizeof(line), f)) @@ -84,6 +172,8 @@ load_pcimap(void) strcpy(e->module, line); } fclose(f); + + return 1; } static int @@ -104,6 +194,35 @@ match_pcimap(struct device *d, struct pcimap_entry *e) #undef MATCH } +static const char *next_module(struct device *d) +{ + static struct pcimap_entry *current, *last_printed; + + if (!current) + { + current = pcimap_head; + last_printed = NULL; + } + else + current = current->next; + + while (current) + { + if (match_pcimap(d, current) && (!last_printed || strcmp(last_printed->module, current->module))) + return current->module; + current = current->next; + } + + return NULL; +} + +void +show_kernel_cleanup(void) +{ +} + +#endif + #define DRIVER_BUF_SIZE 1024 static char * @@ -142,20 +261,18 @@ void show_kernel(struct device *d) { char buf[DRIVER_BUF_SIZE]; - char *driver; - struct pcimap_entry *e, *last = NULL; + const char *driver, *module; if (driver = find_driver(d, buf)) printf("\tKernel driver in use: %s\n", driver); - load_pcimap(); - for (e=pcimap_head; e; e=e->next) - if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module))) - { - printf("%s %s", (last ? "," : "\tKernel modules:"), e->module); - last = e; - } - if (last) + if (!show_kernel_init()) + return; + + int cnt = 0; + while (module = next_module(d)) + printf("%s %s", (cnt++ ? "," : "\tKernel modules:"), module); + if (cnt) putchar('\n'); } @@ -163,19 +280,16 @@ void show_kernel_machine(struct device *d) { char buf[DRIVER_BUF_SIZE]; - char *driver; - struct pcimap_entry *e, *last = NULL; + const char *driver, *module; if (driver = find_driver(d, buf)) printf("Driver:\t%s\n", driver); - load_pcimap(); - for (e=pcimap_head; e; e=e->next) - if (match_pcimap(d, e) && (!last || strcmp(last->module, e->module))) - { - printf("Module:\t%s\n", e->module); - last = e; - } + if (!show_kernel_init()) + return; + + while (module = next_module(d)) + printf("Module:\t%s\n", module); } #else @@ -190,5 +304,10 @@ show_kernel_machine(struct device *d UNUSED) { } +void +show_kernel_cleanup(void) +{ +} + #endif diff --git a/lspci.c b/lspci.c index a67a516..bd81014 100644 --- a/lspci.c +++ b/lspci.c @@ -1013,6 +1013,7 @@ main(int argc, char **argv) else show(); } + show_kernel_cleanup(); pci_cleanup(pacc); return (seen_errors ? 2 : 0); diff --git a/lspci.h b/lspci.h index d040492..81aca26 100644 --- a/lspci.h +++ b/lspci.h @@ -74,6 +74,7 @@ void show_ext_caps(struct device *d); void show_kernel_machine(struct device *d UNUSED); void show_kernel(struct device *d UNUSED); +void show_kernel_cleanup(void); /* ls-tree.c */ -- 2.39.2