modutils/Config.src | 2 +- modutils/insmod.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/modutils/Config.src b/modutils/Config.src index 449ac65..02fbc41 100644 --- a/modutils/Config.src +++ b/modutils/Config.src @@ -247,7 +247,7 @@ config FEATURE_MODUTILS_SYMBOLS config DEFAULT_MODULES_DIR string "Default directory containing modules" default "/lib/modules" - depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO + depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO || INSMOD help Directory that contains kernel modules. Defaults to "/lib/modules" diff --git a/modutils/insmod.c b/modutils/insmod.c index 887d9f2..fa4a4f9 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -35,11 +35,42 @@ //usage: ) //usage:#endif +#include +static char *m_filename; +static char *m_fullName; + +static int FAST_FUNC check_module_name_match(const char *filename, + struct stat *statbuf UNUSED_PARAM, + void *userdata, int depth UNUSED_PARAM) +{ + char *fullname = (char *) userdata; + char *tmp; + + if (fullname[0] == '\0') + return FALSE; + + tmp = bb_get_last_path_component_nostrip(filename); + if (strcmp(tmp, fullname) == 0) { + /* Stop searching if we find a match */ + m_filename = xstrdup(filename); + return FALSE; + } + return TRUE; +} + int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int insmod_main(int argc UNUSED_PARAM, char **argv) { char *filename; int rc; +int len; +char *tmp; +char *tmp2; +int k_version = 0; +struct stat st; +struct utsname uts; +char *m_name; +FILE *fp; /* Compat note: * 2.6 style insmod has no options and required filename @@ -58,9 +89,99 @@ int insmod_main(int argc UNUSED_PARAM, char **argv) if (!filename) bb_show_usage(); - rc = bb_init_module(filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0)); + /* Grab the module name */ + tmp = xstrdup(filename); + len = strlen(filename); + + if (uname(&uts) == 0) { + if (uts.release[0] == '2') { + k_version = uts.release[2] - '0'; + } + } + + if (k_version > 4 && len > 3 && tmp[len - 3] == '.' + && tmp[len - 2] == 'k' && tmp[len - 1] == 'o' + ) { + len -= 3; + tmp[len] = '\0'; + } else + if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { + len -= 2; + tmp[len] = '\0'; + } + + if (k_version > 4) + m_fullName = xasprintf("%s.ko", tmp); + else + m_fullName = xasprintf("%s.o", tmp); + + if (!m_name) { + m_name = tmp; + } + free(tmp); + + /* first look in /var/lib/modules */ + tmp2 = alloca(strlen(m_fullName) + sizeof("/var/lib/modules/")); + strcpy(tmp2, "/var/lib/modules/"); + strcat(tmp2, m_fullName); + if (stat(tmp2, &st) >= 0 && S_ISREG(st.st_mode) && (fp = fopen(tmp2, "r")) != NULL) { + m_filename = xstrdup(tmp2); + printf("insmod: preferring module %s\n", m_filename); + } else + /* Get a filedesc for the module. Check that we have a complete path */ + if (stat(filename, &st) < 0 || !S_ISREG(st.st_mode) + || (fp = fopen_for_read(filename)) == NULL + ) { + /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, + * but do not error out yet if we fail to find it... */ + if (k_version) { /* uname succeedd */ + char *module_dir; + char *tmdn; + + tmdn = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release); + /* Jump through hoops in case /lib/modules/`uname -r` + * is a symlink. We do not want recursive_action to + * follow symlinks, but we do want to follow the + * /lib/modules/`uname -r` dir, So resolve it ourselves + * if it is a link... */ + module_dir = xmalloc_readlink(tmdn); + if (!module_dir) + module_dir = xstrdup(tmdn); + recursive_action(module_dir, ACTION_RECURSE, + check_module_name_match, NULL, m_fullName, 0); + free(module_dir); + free(tmdn); + } + + /* Check if we have found anything yet */ + if (!m_filename || ((fp = fopen_for_read(m_filename)) == NULL)) { + int r; + char *module_dir; + + free(m_filename); + m_filename = NULL; + module_dir = xmalloc_readlink(CONFIG_DEFAULT_MODULES_DIR); + if (!module_dir) + module_dir = xstrdup(CONFIG_DEFAULT_MODULES_DIR); + /* No module found under /lib/modules/`uname -r`, this + * time cast the net a bit wider. Search /lib/modules/ */ + r = recursive_action(module_dir, ACTION_RECURSE, + check_module_name_match, NULL, m_fullName, 0); + if (r) + bb_error_msg_and_die("%s: module not found", m_fullName); + free(module_dir); + if (m_filename == NULL + || ((fp = fopen_for_read(m_filename)) == NULL) + ) { + bb_error_msg_and_die("%s: module not found", m_fullName); + } + } + } else + m_filename = xstrdup(filename); + + rc = bb_init_module(m_filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0)); if (rc) - bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); + bb_error_msg("can't insert '%s': %s", m_filename, moderror(rc)); return rc; }