1303 files changed, 32187 insertions, 57138 deletions
diff --git a/modutils/modutils.c b/modutils/modutils.c index 6187ca7..4204f06 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c @@ -7,14 +7,64 @@ */ #include "modutils.h" -#ifdef __UCLIBC__ -extern int init_module(void *module, unsigned long len, const char *options); -extern int delete_module(const char *module, unsigned int flags); -#else -# include <sys/syscall.h> -# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) -# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) +#include <sys/syscall.h> + +#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts) +#if defined(__NR_finit_module) +# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags) #endif +#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) + +static module_entry *helper_get_module(module_db *db, const char *module, int create) +{ + char modname[MODULE_NAME_LEN]; + struct module_entry *e; + unsigned i, hash; + + filename2modname(module, modname); + + hash = 0; + for (i = 0; modname[i]; i++) + hash = ((hash << 5) + hash) + modname[i]; + hash %= MODULE_HASH_SIZE; + + for (e = db->buckets[hash]; e; e = e->next) + if (strcmp(e->modname, modname) == 0) + return e; + if (!create) + return NULL; + + e = xzalloc(sizeof(*e)); + e->modname = xstrdup(modname); + e->next = db->buckets[hash]; + db->buckets[hash] = e; + IF_DEPMOD(e->dnext = e->dprev = e;) + + return e; +} +module_entry* FAST_FUNC moddb_get(module_db *db, const char *module) +{ + return helper_get_module(db, module, 0); +} +module_entry* FAST_FUNC moddb_get_or_create(module_db *db, const char *module) +{ + return helper_get_module(db, module, 1); +} + +void FAST_FUNC moddb_free(module_db *db) +{ + module_entry *e, *n; + unsigned i; + + for (i = 0; i < MODULE_HASH_SIZE; i++) { + for (e = db->buckets[i]; e; e = n) { + n = e->next; + free(e->name); + free(e->modname); + free(e); + } + } +} void FAST_FUNC replace(char *s, char what, char with) { @@ -47,18 +97,26 @@ int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim) char* FAST_FUNC filename2modname(const char *filename, char *modname) { + char local_modname[MODULE_NAME_LEN]; int i; - char *from; + const char *from; if (filename == NULL) return NULL; if (modname == NULL) - modname = xmalloc(MODULE_NAME_LEN); - from = bb_get_last_path_component_nostrip(filename); + modname = local_modname; + // Disabled since otherwise "modprobe dir/name" would work + // as if it is "modprobe name". It is unclear why + // 'basenamization' was here in the first place. + //from = bb_get_last_path_component_nostrip(filename); + from = filename; for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++) modname[i] = (from[i] == '-') ? '_' : from[i]; modname[i] = '\0'; + if (modname == local_modname) + return xstrdup(modname); + return modname; } @@ -153,6 +211,24 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options) return bb_init_module_24(filename, options); #endif + /* + * First we try finit_module if available. Some kernels are configured + * to only allow loading of modules off of secure storage (like a read- + * only rootfs) which needs the finit_module call. If it fails, we fall + * back to normal module loading to support compressed modules. + */ +# ifdef __NR_finit_module + { + int fd = open(filename, O_RDONLY | O_CLOEXEC); + if (fd >= 0) { + rc = finit_module(fd, options, 0) != 0; + close(fd); + if (rc == 0) + return rc; + } + } +# endif + image_size = INT_MAX - 4095; mmaped = 0; image = try_to_mmap_module(filename, &image_size); @@ -182,6 +258,11 @@ int FAST_FUNC bb_delete_module(const char *module, unsigned int flags) return errno; } +/* Note: not suitable for delete_module() errnos. + * For them, probably only EWOULDBLOCK needs explaining: + * "Other modules depend on us". So far we don't do such + * translation and don't use moderror() for removal errors. + */ const char* FAST_FUNC moderror(int err) { switch (err) { |