#include <libgen.h>
#include <glob.h>
#include <elf.h>
+#include <ctype.h>
#include <libubox/avl.h>
#include <libubox/avl-cmp.h>
#include <libubox/utils.h>
#include <libubox/ulog.h>
+#include <libubox/kvlist.h>
#define DEF_MOD_PATH "/modules/%s/"
/* duplicated from in-kernel include/linux/module.h */
SCANNED,
PROBE,
LOADED,
+ BLACKLISTED,
};
struct module {
};
static struct avl_tree modules;
+static KVLIST(options, kvlist_strlen);
static char **module_folders = NULL;
/* possibly a module outside /lib/modules/<ver>/ */
n = alloc_module(m.name, NULL, 0, m.depends, m.size);
}
+ if (!n) {
+ ULOG_ERR("Failed to allocate memory for module\n");
+ return -1;
+ }
+
n->usage = m.usage;
n->state = LOADED;
}
unsigned int offset, size;
char *map = MAP_FAILED, *strings, *dep = NULL;
const char **aliases = NULL;
+ const char **aliasesr;
int naliases = 0;
struct module *m = NULL;
struct stat s;
if (!strncmp(strings, "depends=", len + 1))
dep = sep;
else if (!strncmp(strings, "alias=", len + 1)) {
- aliases = realloc(aliases, sizeof(sep) * (naliases + 1));
- if (!aliases) {
+ aliasesr = realloc(aliases, sizeof(sep) * (naliases + 1));
+ if (!aliasesr) {
ULOG_ERR("out of memory\n");
goto out;
}
+ aliases = aliasesr;
aliases[naliases++] = sep;
}
strings = &sep[strlen(sep)];
for (j = 0; j < gl.gl_pathc; j++) {
char *name = get_module_name(gl.gl_pathv[j]);
struct module *m;
+ char *opts;
if (!name)
continue;
m = find_module(name);
+ if (m)
+ continue;
+
+ m = get_module_info(gl.gl_pathv[j], name);
if (!m) {
- if (!get_module_info(gl.gl_pathv[j], name))
- rv |= -1;
+ rv |= -1;
+ continue;
}
+
+ opts = kvlist_get(&options, name);
+ if (!opts)
+ continue;
+
+ if (*opts == '\x01')
+ m->state = BLACKLISTED;
+ else
+ m->opts = strdup(opts);
}
globfree(&gl);
struct stat s;
int fd, ret = -1;
+ if (!path) {
+ ULOG_ERR("Path not specified\n");
+ return ret;
+ }
+
if (stat(path, &s)) {
ULOG_ERR("missing module %s\n", path);
return ret;
name = get_module_name(argv[optind]);
m = find_module(name);
- if (m && m->state == LOADED) {
+ if (m && m->state == BLACKLISTED) {
+ if (!quiet)
+ ULOG_INFO("%s is blacklisted\n", name);
+ } else if (m && m->state == LOADED) {
if (!quiet)
ULOG_INFO("%s is already loaded\n", name);
} else if (!m) {
struct module *m;
glob_t gl;
char *path;
- int fail, j;
+ int ret = 0, fail, j;
if (argc > 1)
dir = argv[1];
strcat(path, "*");
if (scan_module_folders()) {
- free (path);
- return -1;
+ ret = -1;
+ goto free_path;
}
if (scan_loaded_modules()) {
- free (path);
- return -1;
+ ret = -1;
+ goto free_path;
}
ULOG_INFO("loading kernel modules from %s\n", path);
*opts++ = '\0';
m = find_module(get_module_name(mod));
- if (!m || (m->state == LOADED))
+ if (!m || m->state == LOADED || m->state == BLACKLISTED)
continue;
- if (opts)
- m->opts = strdup(opts);
+ if (opts) {
+ if (m->opts) {
+ char *prev = m->opts;
+
+ fail = asprintf(&m->opts, "%s %s", prev, opts);
+ free(prev);
+ if (fail < 0) {
+ ULOG_ERR("out of memory for opts %s\n", opts);
+ free(mod);
+ fclose(fp);
+ ret = -1;
+ goto out;
+ }
+ } else {
+ m->opts = strdup(opts);
+ }
+ }
m->state = PROBE;
if (basename(gl.gl_pathv[j])[0] - '0' <= 9)
load_modprobe(false);
out:
globfree(&gl);
+free_path:
free(path);
- return 0;
+ return ret;
}
static inline char weight(char c)
return (unsigned char)weight(*s1) - (unsigned char)weight(*s2);
}
+static void
+load_options(void)
+{
+ static char buf[512];
+ char *s;
+ FILE *f;
+
+ f = fopen("/etc/modules.conf", "r");
+ if (!f)
+ return;
+
+ while ((s = fgets(buf, sizeof(buf), f)) != NULL) {
+ char *c, *cmd, *mod;
+
+ while (isspace(*s))
+ s++;
+
+ c = strchr(s, '#');
+ if (c)
+ *c = 0;
+
+ while (isspace(*s))
+ s++;
+
+ c = s + strlen(s);
+ while (c > s && isspace(c[-1])) {
+ c[-1] = 0;
+ c--;
+ }
+
+ cmd = strsep(&s, " \t");
+ if (!cmd || !*cmd)
+ continue;
+
+ while (isspace(*s))
+ s++;
+
+ mod = strsep(&s, " \t");
+ if (!mod || !*mod)
+ continue;
+
+ if (!strcmp(cmd, "blacklist")) {
+ kvlist_set(&options, mod, "\x01");
+ continue;
+ }
+
+ if (!strcmp(cmd, "options")) {
+ char *prev = kvlist_get(&options, mod);
+ char *val = NULL;
+
+ while (isspace(*s))
+ s++;
+
+ if (!*s)
+ continue;
+
+ if (prev && prev[0] == '\x01')
+ continue;
+
+ if (!prev) {
+ kvlist_set(&options, mod, s);
+ continue;
+ }
+
+ if (asprintf(&val, "%s %s", prev, s) < 0)
+ continue;
+
+ kvlist_set(&options, mod, val);
+ free(val);
+ continue;
+ }
+ }
+
+ fclose(f);
+}
+
int main(int argc, char **argv)
{
char *exec = basename(*argv);
if (!strcmp(exec, "modinfo"))
return main_modinfo(argc, argv);
+ load_options();
+
if (!strcmp(exec, "modprobe"))
return main_modprobe(argc, argv);