diff -Naur busybox.orig/include/applets.h busybox/include/applets.h --- busybox.orig/include/applets.h 2008-06-02 19:30:56 +0000 +++ busybox/include/applets.h 2008-06-19 21:52:17 +0000 @@ -116,6 +116,7 @@ USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup)) USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) +USE_MODPROBE_NG(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, depmod)) USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) @@ -249,6 +250,7 @@ USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER)) +USE_MODPROBE_NG(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_MOUNT(APPLET(mount, _BB_DIR_BIN, USE_DESKTOP(_BB_SUID_MAYBE) SKIP_DESKTOP(_BB_SUID_NEVER))) USE_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER)) diff -Naur busybox.orig/modutils/Config.in busybox/modutils/Config.in --- busybox.orig/modutils/Config.in 2008-06-16 21:39:23 +0000 +++ busybox/modutils/Config.in 2008-06-19 21:26:49 +0000 @@ -5,9 +5,16 @@ menu "Linux Module Utilities" +config MODPROBE_NG + bool "simplified modutils" + default n + help + New format modutils. Compatible. + config DEPMOD bool "depmod" default n + depends on !MODPROBE_NG help depmod generates modules.dep (FIXME: elaborate) @@ -113,6 +120,7 @@ config MODPROBE bool "modprobe" default n + depends on !MODPROBE_NG help Handle the loading of modules, and their dependencies on a high level. diff -Naur busybox.orig/modutils/Kbuild busybox/modutils/Kbuild --- busybox.orig/modutils/Kbuild 2008-05-26 21:53:59 +0000 +++ busybox/modutils/Kbuild 2008-06-19 21:24:01 +0000 @@ -9,4 +9,5 @@ lib-$(CONFIG_INSMOD) += insmod.o lib-$(CONFIG_LSMOD) += lsmod.o lib-$(CONFIG_MODPROBE) += modprobe.o +lib-$(CONFIG_MODPROBE_NG) += modprobe-ng.o lib-$(CONFIG_RMMOD) += rmmod.o diff -Naur busybox.orig/modutils/modprobe-ng.c busybox/modutils/modprobe-ng.c --- busybox.orig/modutils/modprobe-ng.c 1970-01-01 00:00:00 +0000 +++ busybox/modutils/modprobe-ng.c 2008-06-19 21:53:25 +0000 @@ -0,0 +1,273 @@ +/* vi: set sw=4 ts=4: */ +/* + * depmod - generate modules.dep + * Copyright (c) 2008 Bernhard Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#undef _GNU_SOURCE +#define _GNU_SOURCE +#include +#include /* uname() */ +/* + * Theory of operation: + * - iterate over all modules and record their full path + * - iterate over all modules looking for "depends=" entries + * for each depends, look through our list of full paths and emit if found + */ + +static char* find_keyword(void *the_module, size_t len, const char * const word) +{ + char *ptr = the_module; + do { + /* search for the first char in word */ + ptr = memchr(ptr, *word, len - (ptr - (char*)the_module)); + if (ptr == NULL) /* no occurance left, done */ + return NULL; + if (!strncmp(ptr, word, strlen(word))) { + ptr += strlen(word); + break; + } + ++ptr; + } while (1); + return ptr; +} + +static void replace(char *s, char what, char with) +{ + while (*s) { + if (what == *s) + *s = with; + ++s; + } +} + +static int fileAction(const char *fname, struct stat *sb, + void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth) +{ + size_t len = sb->st_size; + void *module_image; + char *ptr; + int fd; + size_t pos; + + char *name; + + if (strrstr(fname, ".ko") == NULL) /* not a module */ + goto skip; + +/*XXX: FIXME: does not handle compressed modules! + * There should be a function that looks at the extension and sets up + * open_transformer for us. + */ + fd = xopen(fname, O_RDONLY); + module_image = mmap(NULL, len, PROT_READ, MAP_SHARED +#if defined MAP_POPULATE + |MAP_POPULATE +#endif + , fd, 0); + close(fd); + if (module_image == MAP_FAILED) + bb_perror_msg_and_die("mmap"); + + name = xstrdup(bb_get_last_path_component_nostrip(fname)); + ptr = strrstr(name, ".ko"); + *ptr = '\0'; + replace(name, '-', '_'); + + // module name ... + printf(" %s ", name); + + // ... and aliases + pos = 0; + do { + ptr = find_keyword(module_image + pos, len - pos, "alias="); + if (!ptr) + ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_"); + if (ptr) { + // FIXME: __ksymtab_gpl and __ksymtab_strings occur in many modules. + // What do they mean?! + printf("%s%s ", (('_' == ptr[-1]) ? "symbol:" : ""), ptr); + } else + break; + pos = (ptr - (char*)module_image); + } while (1); + printf("\n"); + + // dependencies + ptr = find_keyword(module_image, len, "depends="); + if (*ptr) { + char *depends = xstrdup(ptr); + replace(depends, ',', ' '); + replace(depends, '-', '_'); + printf("%s", depends); + free(depends); + } + // filename and options + printf(" \n%s%s\n", fname, ""); + + free(name); + + munmap(module_image, sb->st_size); + skip: + return TRUE; +} + +static int already_loaded(const char *name) +{ + int ret = 0; +#define modules bb_common_bufsiz1 + // N.B. can't use mmap or xmalloc_open_read_close()! They report wrong file length on mem-backed /proc/modules!!! + if (open_read_close("/proc/modules", modules, sizeof(modules)) >= 0) { + char *s = modules; + +//bb_error_msg("TEST [%s]", name); + while ((s = strstr(s, name))) { +//bb_error_msg("??? [%s]", s); + if (' ' == s[strlen(name)] && (s == s || '\n' == s[-1])) { +//bb_error_msg("!!! [%s]", s); + ++ret; + break; + } + s += strlen(name); + } + } + + return ret; +} + +/* + Given modules definition and module name (or alias, or symbol) + load the module respecting dependencies +*/ +static void load_module(char *modules_dep, char *name, int level) +{ + // read definitions + char *ptr = modules_dep, tab[] = " "; + if (level < 12) tab[level] = '\0'; + + replace(name, '-', '_'); + bb_error_msg("%sLOAD [%s]", tab, name); + + // iterate thru definitions + while (*ptr) { + // substring exists and is enclosed by spaces? + char *s = strstr(ptr, name), *deps; + // no -> + if (!s || s[-1] != ' ' || s[strlen(name)] != ' ') { // N.B. may be regexp?! Much more powerful... + // ... skip to next module definition + for (int i = 3; --i >= 0; ) + ptr += strlen(ptr)+1; + continue; + } + + // yes -> found module definition! replace possible aliased name with module general name + name = xstrdup(ptr+1); + *strchrnul(name, ' ') = '\0'; + + // next line contains dependencies + ptr += strlen(ptr)+1; + bb_error_msg("%s[%s] DEPENDS [%s]", tab, name, ptr); + // copy dependencies string + deps = xstrdup(ptr); + // transform it to string list + replace(deps, ' ', '\0'); + // iterate thru dependencies, trying to load them + for (s = deps; *s; s += strlen(s)+1) { + //if (strcmp(name, s)) // N.B. Do loops ever exist?! + load_module(modules_dep, s, level+1); + } + free(deps); + + // next line contains full path with options + ptr += strlen(ptr)+1; + // if module is not loaded -> + if (!already_loaded(name)) { + // load it + const char *argv[] = { "insmod", ptr, NULL }; + bb_error_msg("%sINSMOD %s", tab, ptr); + spawn_and_wait((char **)argv); + } + + // cleanup + free(name); + } +} + +int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int modprobe_main(int ATTRIBUTE_UNUSED argc, char **argv) +{ + int ret; + size_t moddir_base_len = 0; /* length of the "-b basedir" */ + char *moddir_base = NULL, *moddir, *system_map; +#define chp moddir_base +#define modules_dep moddir_base + bool is_modprobe = ('m' == argv[0][0]); + enum { + ARG_a = (1<<0), /* All modules, ignore mods in argv */ + ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */ + ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */ + ARG_e = (1<<3), /* with -F, print unresolved symbols */ + ARG_F = (1<<4), /* System.map that contains the symbols */ + ARG_n = (1<<5) /* dry-run, print to stdout only */ + }; + + getopt32(argv, "aAb:eF:n", &moddir_base, &system_map); + argv += optind; + + /* If a version is provided, then that kernel version’s module directory + * is used, rather than the current kernel version (as returned by + * "uname -r"). */ + if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) { + moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++); + } else { + struct utsname uts; + if (uname(&uts) < 0) + bb_simple_perror_msg_and_die("uname"); + moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release); + } + /* If no modules are given on the command-line, -a is on per default. */ + option_mask32 |= *argv == NULL; + + if (option_mask32 & ARG_b) { + moddir_base_len = strlen(moddir_base) + 1; + xchdir(moddir_base); + } + + chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE); + + if (!is_modprobe) { /* --dry-run */ + if (!(option_mask32 & ARG_n)) + xmove_fd(xopen(chp, O_CREAT | O_TRUNC | O_WRONLY), STDOUT_FILENO); + } else { + // read definitions + modules_dep = xmalloc_open_read_close(chp, NULL); + // convert them to string list + replace(modules_dep, '\n', '\0'); + } + + ret = EXIT_SUCCESS; + do { + if (is_modprobe) { + load_module(modules_dep, *argv, 0); + } else if (!recursive_action(option_mask32 & ARG_a ? moddir : (*argv + moddir_base_len), + ACTION_RECURSE, /* flags */ + fileAction, /* file action */ + NULL, /* dir action */ + NULL, /* user data */ + 0)) { /* depth */ + ret = EXIT_FAILURE; + } + } while (!(option_mask32 & ARG_a) && *++argv); + + if (!is_modprobe) { + // finalize definitions + printf("\n"); + } + + if (ENABLE_FEATURE_CLEAN_UP) + free(chp); + + return ret; +}