From 5fb4a6ae8f5ae5593fb26f0d985679dbb3e31aec Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Thu, 23 Jun 2022 14:23:04 +0200 Subject: [PATCH] plugins: modprobe: Support for coldplugging more devices As it turns out, not all buses in Linux will add `modalias` attributes to their devices in sysfs. One notable exception are MDIO buses. The plugin's scan routine would thus not pick them up. Fortunately, the information is always available in the device's `uevent` attribute. Therefore, default to looking for modaliases in the device's `uevent` attribute instead, falling back to `modalias` only if `uevent` is not availble (this should never happen). --- plugins/modprobe.c | 79 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/plugins/modprobe.c b/plugins/modprobe.c index 797899a2..0ca5acbb 100644 --- a/plugins/modprobe.c +++ b/plugins/modprobe.c @@ -106,7 +106,7 @@ static void alias_remove(struct module *m) TAILQ_REMOVE(&modules, m, link); free(m->alias); free(m); -} +} static int alias_exist(char *alias) { @@ -120,27 +120,88 @@ static int alias_exist(char *alias) return 0; } -static int scan_alias(const char *path, const struct stat *st, int flag, struct FTW *unused) +static void alias_add_uniq(char *alias) +{ + + if (alias_exist(alias)) + return; + + alias_add(alias); +} + +static FILE *maybe_fopen_alias(const char *file, const char *path) +{ + const char *basename; + + basename = rindex(path, '/'); + if (!basename) + return NULL; + + basename++; + if (strcmp(file, basename)) + return NULL; + + return fopen(path, "r"); +} + +static int scan_modalias(const char *path) { FILE *fp; char buf[256]; - if (fnmatch("*/modalias", path, 0)) - return 0; - - fp = fopen(path, "r"); + fp = maybe_fopen_alias("modalias", path); if (!fp) - return 0; + return 1; + if (fgets(buf, sizeof(buf), fp)) { chomp(buf); - if (!alias_exist(buf)) - alias_add(buf); + alias_add_uniq(buf); } + fclose(fp); return 0; } +static int scan_uevent(const char *path) +{ + FILE *fp; + char buf[256]; + + fp = maybe_fopen_alias("uevent", path); + if (!fp) + return 1; + + while (fgets(buf, sizeof(buf), fp)) { + if (strstr(buf, "MODALIAS=") != buf) + continue; + + chomp(buf); + + alias_add_uniq(buf + strlen("MODALIAS=")); + break; + } + + fclose(fp); + + return 0; +} + +static int scan_alias(const char *path, const struct stat *st, + int flag, struct FTW *unused) +{ + /* Perform some basic sanity checks first: that this is a + * regular file that we can read. */ + if (!(S_ISREG(st->st_mode) && (st->st_mode & S_IRUSR))) + return 0; + + if (!scan_uevent(path)) + return 0; + + scan_modalias(path); + return 0; +} + static void coldplug(void *arg) { struct module *m, *tmp;