On Tue, Apr 13, 2004 at 06:12:56PM +0200, Bastian Blank wrote: > The attached patch inplements 2.6 support in busybox insmod. Please test > them. I merged depmod. Bastian -- I object to intellect without discipline; I object to power without constructive purpose. -- Spock, "The Squire of Gothos", stardate 2124.5
Index: modutils/lsmod.c =================================================================== --- modutils/lsmod.c (revision 290) +++ modutils/lsmod.c (working copy) @@ -38,16 +38,10 @@ #include <sys/file.h> #include "busybox.h" +#include "obj/module.h" -#ifndef CONFIG_FEATURE_CHECK_TAINTED_MODULE -static inline void check_tainted(void) { printf("\n"); } -#else -#define TAINT_FILENAME "/proc/sys/kernel/tainted" -#define TAINT_PROPRIETORY_MODULE (1<<0) -#define TAINT_FORCED_MODULE (1<<1) -#define TAINT_UNSAFE_SMP (1<<2) - -static void check_tainted(void) +#ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE +static inline void check_tainted(void) { int tainted; FILE *f; @@ -67,108 +61,84 @@ printf(" Not tainted\n"); } } +#else +static inline void check_tainted(void) +{ + printf("\n"); +} #endif -#ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE - -struct module_info +static inline int lsmod_query(void) { - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; + struct module_info info; + char *module_names, *mn, *deps, *dn; + size_t bufsize, depsize, nmod, count, i, j; + module_names = xmalloc(bufsize = 256); + if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, &nmod)) { + bb_perror_msg_and_die("QM_MODULES"); + } -int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); + deps = xmalloc(depsize = 256); -/* Values for query_module's which. */ -static const int QM_MODULES = 1; -static const int QM_DEPS = 2; -static const int QM_REFS = 3; -static const int QM_SYMBOLS = 4; -static const int QM_INFO = 5; + for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { + if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + /* else choke */ + bb_perror_msg_and_die("module %s: QM_INFO", mn); + } + if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + bb_perror_msg_and_die("module %s: QM_REFS", mn); + } + printf("%-20s%8lu%4ld", mn, info.size, info.usecount); + if (info.flags & NEW_MOD_DELETED) + printf(" (deleted)"); + else if (info.flags & NEW_MOD_INITIALIZING) + printf(" (initializing)"); + else if (!(info.flags & NEW_MOD_RUNNING)) + printf(" (uninitialized)"); + else { + if (info.flags & NEW_MOD_AUTOCLEAN) + printf(" (autoclean) "); + if (!(info.flags & NEW_MOD_USED_ONCE)) + printf(" (unused)"); + } + if (count) printf(" ["); + for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { + printf("%s%s", dn, (j==count-1)? "":" "); + } + if (count) printf("]"); -/* Bits of module.flags. */ -static const int NEW_MOD_RUNNING = 1; -static const int NEW_MOD_DELETED = 2; -static const int NEW_MOD_AUTOCLEAN = 4; -static const int NEW_MOD_VISITED = 8; -static const int NEW_MOD_USED_ONCE = 16; -static const int NEW_MOD_INITIALIZING = 64; + printf("\n"); + } -extern int lsmod_main(int argc, char **argv) -{ - struct module_info info; - char *module_names, *mn, *deps, *dn; - size_t bufsize, depsize, nmod, count, i, j; - - module_names = xmalloc(bufsize = 256); - if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, - &nmod)) { - bb_perror_msg_and_die("QM_MODULES"); - } - - deps = xmalloc(depsize = 256); - printf("Module Size Used by"); - check_tainted(); - - for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { - if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - /* else choke */ - bb_perror_msg_and_die("module %s: QM_INFO", mn); - } - if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - bb_perror_msg_and_die("module %s: QM_REFS", mn); - } - printf("%-20s%8lu%4ld", mn, info.size, info.usecount); - if (info.flags & NEW_MOD_DELETED) - printf(" (deleted)"); - else if (info.flags & NEW_MOD_INITIALIZING) - printf(" (initializing)"); - else if (!(info.flags & NEW_MOD_RUNNING)) - printf(" (uninitialized)"); - else { - if (info.flags & NEW_MOD_AUTOCLEAN) - printf(" (autoclean) "); - if (!(info.flags & NEW_MOD_USED_ONCE)) - printf(" (unused)"); - } - if (count) printf(" ["); - for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { - printf("%s%s", dn, (j==count-1)? "":" "); - } - if (count) printf("]"); - - printf("\n"); - } - -#ifdef CONFIG_FEATURE_CLEAN_UP - free(module_names); -#endif - - return( 0); + return( 0); } -#else /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */ - extern int lsmod_main(int argc, char **argv) { printf("Module Size Used by"); check_tainted(); +#ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE + if (getuid() != 0) + { +#endif if (bb_xprint_file_by_name("/proc/modules") < 0) { return 0; } return 1; +#ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE + } + return lsmod_query(); +#endif } -#endif /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */ + Index: modutils/modutils.c =================================================================== --- modutils/modutils.c (revision 0) +++ modutils/modutils.c (revision 0) @@ -0,0 +1,33 @@ +#include <stdlib.h> +#include <string.h> +#include <sys/utsname.h> +#include "modutils.h" + +/* Get the kernel version in the canonical integer form. */ + +int get_kernel_version(char str[STRVERSIONLEN]) +{ + char *p, *q; + int a, b, c; + struct utsname uts_info; + + if (uname (&uts_info)) + return -1; + + strncpy(str, uts_info.release, STRVERSIONLEN-1); + str[STRVERSIONLEN-1] = '\0'; + p = str; + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + + return a << 16 | b << 8 | c; +} + Index: modutils/Makefile.in =================================================================== --- modutils/Makefile.in (revision 290) +++ modutils/Makefile.in (working copy) @@ -26,7 +26,7 @@ CFLAGS_MODUTILS += -DELF_MACHINE_H='"elf_$(host_cpu_modutils).h"' CFLAGS_MODUTILS += -DELF_MACHINE_H_BIARCH='"elf_$(host_cpu_modutils_biarch).h"' -MODUTILS-y:= +MODUTILS-y := modutils.o MODUTILS-$(CONFIG_INSMOD) += insmod.o MODUTILS-$(CONFIG_LSMOD) += lsmod.o MODUTILS-$(CONFIG_MODPROBE) += modprobe.o Index: modutils/modutils.h =================================================================== --- modutils/modutils.h (revision 290) +++ modutils/modutils.h (working copy) @@ -1,3 +1,6 @@ -#define _PATH_MODULES "/lib/modules" +#define _PATH_MODULES "/lib/modules" +#define MODULE_DIR "/lib/modules" +#define STRVERSIONLEN 32 int check_module (const char *mod); +int get_kernel_version(char str[STRVERSIONLEN]); Index: modutils/modprobe.c =================================================================== --- modutils/modprobe.c (revision 290) +++ modutils/modprobe.c (working copy) @@ -21,7 +21,6 @@ * */ -#include <sys/utsname.h> #include <getopt.h> #include <stdlib.h> #include <unistd.h> @@ -31,8 +30,8 @@ #include <fcntl.h> #include "busybox.h" +#include "modutils.h" - struct dep_t { char * m_module; char * m_options; @@ -58,6 +57,7 @@ static struct dep_t *depend; static int autoclean, show_only, quiet, do_syslog, verbose; static int k_version; +char k_strversion[STRVERSIONLEN]; int parse_tag_value ( char *buffer, char **ptag, char **pvalue ) { @@ -112,33 +112,22 @@ static struct dep_t *build_dep ( void ) { int fd; - struct utsname un; struct dep_t *first = 0; struct dep_t *current = 0; char buffer[256]; char *filename = buffer; int continuation_line = 0; - k_version = 0; - if ( uname ( &un )) - return 0; + k_version = get_kernel_version(k_strversion); - // check for buffer overflow in following code - if ( bb_strlen ( un.release ) > ( sizeof( buffer ) - 64 )) { - return 0; - } - if (un.release[0] == '2') { - k_version = un.release[2] - '0'; - } - - strcpy ( filename, "/lib/modules/" ); - strcat ( filename, un.release ); + strcpy ( filename, _PATH_MODULES ); + strcat ( filename, k_strversion ); strcat ( filename, "/modules.dep" ); if (( fd = open ( filename, O_RDONLY )) < 0 ) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ - if (( fd = open ( "/lib/modules/modules.dep", O_RDONLY )) < 0 ) { + if (( fd = open ( _PATH_MODULES "/modules.dep", O_RDONLY )) < 0 ) { return 0; } } Index: modutils/depmod.c =================================================================== --- modutils/depmod.c (revision 290) +++ modutils/depmod.c (working copy) @@ -37,27 +37,22 @@ #include <syslog.h> #include <limits.h> #include <elf.h> -#include <sys/utsname.h> #include "busybox.h" #include "obj/module.h" #include "obj/obj.h" #include "obj/modstat.h" +#include "modutils.h" +static int k_version = 0; +static char k_strversion[STRVERSIONLEN]; + +#if defined(CONFIG_FEATURE_2_2_MODULES) || defined(CONFIG_FEATURE_2_4_MODULES) + #define ALLOC_MODULE 5000 /* Number of modules we can handle... */ #define ALLOC_SYM 10000 /* Number of symbols allocated per chunk */ #define MAX_MAP_SYM 100000 /* Maximum number of symbols in map */ -#ifndef __u32 -#define __u32 u_int32_t -#endif -#ifndef __u16 -#define __u16 u_int16_t -#endif -#ifndef __u8 -#define __u8 u_int8_t -#endif - typedef struct SYMBOL{ struct SYMBOL *next; /* List connected via hashing */ struct MODULE *module; /* Module declaring this symbol */ @@ -781,6 +776,12 @@ return (FALSE); } +#endif /* CONFIG_FEATURE_2_2_MODULES || CONFIG_FEATURE_2_4_MODULES */ + +#ifdef CONFIG_FEATURE_2_6_MODULES +int depmod_main_2_6(int argc, char *argv[], int all, int verbose, int doing_stdout, const char *system_map, const char *base_dir, const char *module_dir); +#endif /* CONFIG_FEATURE_2_6_MODULES */ + extern int depmod_main(int argc, char **argv) { int ret = -1; @@ -793,7 +794,6 @@ char *base_dir = ""; char *module_dir = NULL; int ignore_suffix = 0; /* Ignore genksyms suffix on resolve? */ - struct utsname myuname; while ((o = getopt(argc, argv, "aAb:C:eF:hnqsvVru")) != EOF) { switch (o) { @@ -803,27 +803,26 @@ stdmode = 1; /* Probe standard directory */ break; /* using the config file */ - case 'e': - showerror = 1; - break; - case 'b': base_dir = optarg; break; - case '?': - case 'h': - return 0; - break; - case 'C': conf_file = optarg; break; + case 'e': + showerror = 1; + break; + case 'F': file_syms = optarg; break; + case 'h': + return 0; + break; + case 'n': nflag = 1; break; @@ -844,19 +843,20 @@ if (err) { bb_error_msg("Aborting"); - return -1; + return EXIT_FAILURE; } - /* else */ argc -= optind; argv += optind; ignore_suffix = file_syms != NULL; - if (uname(&myuname) == 0) { + k_version = get_kernel_version(k_strversion); + + if (k_version != -1) { char tmdn[FILENAME_MAX]; char real_module_dir[FILENAME_MAX]; - snprintf(tmdn, FILENAME_MAX, "%s/lib/modules/%s/", base_dir, myuname.release); + snprintf(tmdn, FILENAME_MAX, "%s" _PATH_MODULES "/%s/", base_dir, k_strversion); if (realpath (tmdn, real_module_dir) == NULL) module_dir = tmdn; else @@ -865,22 +865,36 @@ else return EXIT_FAILURE; - if (stdmode || argc == 0) { - if ((ret = addksyms(file_syms)) != -1) { - recursive_action(module_dir, TRUE, FALSE, FALSE, - add_module, 0, NULL); - - resolve(); - ret = prtdepend(base_dir, module_dir, nflag) || ret; - } - } else { - /* not stdmode */ - if ((ret = addksyms(file_syms)) != -1) { - for (; argc > 0 && ret != -1; ++argv, --argc) - loadobj(*argv, ignore_suffix); - resolve(); - ret = prtdepend(base_dir, module_dir, 1) || ret; - } + if (k_version > 0x20500) +#ifdef CONFIG_FEATURE_2_6_MODULES + ret = depmod_main_2_6(argc, argv, stdmode || argc == 0, !quiet, nflag, file_syms, base_dir, module_dir); +#else + return EXIT_FAILURE; +#endif + else + { +#if defined(CONFIG_FEATURE_2_2_MODULES) || defined(CONFIG_FEATURE_2_4_MODULES) + if (stdmode || argc == 0) + { + if ((ret = addksyms(file_syms)) != -1) { + recursive_action(module_dir, TRUE, FALSE, FALSE, add_module, 0, NULL); + resolve(); + ret = prtdepend(base_dir, module_dir, nflag) || ret; + } + } + else + { + /* not stdmode */ + if ((ret = addksyms(file_syms)) != -1) { + for (; argc > 0 && ret != -1; ++argv, --argc) + loadobj(*argv, ignore_suffix); + resolve(); + ret = prtdepend(base_dir, module_dir, 1) || ret; + } + } +#else + return EXIT_FAILURE; +#endif /* CONFIG_FEATURE_2_2_MODULES || CONFIG_FEATURE_2_4_MODULES */ } return ret; Index: modutils/Config.in =================================================================== --- modutils/Config.in (revision 290) +++ modutils/Config.in (working copy) @@ -6,22 +6,28 @@ menu "Linux Module Utilities" if 0 +config CONFIG_MODUTILS + bool "modutils" + default n config CONFIG_MODUTILS_OBJ bool "modutils" default n + select CONFIG_MODUTILS +config CONFIG_MODUTILS_OBJ_2_6 + bool "modutils" + default n + select CONFIG_MODUTILS endif config CONFIG_DEPMOD bool "depmod" default n - select CONFIG_MODUTILS_OBJ help Please submit a patch to add help text for this item. config CONFIG_INSMOD bool "insmod" default n - select CONFIG_MODUTILS_OBJ help insmod is used to load specified modules in the running kernel. @@ -29,6 +35,7 @@ bool " Support older (pre 2.1) Linux kernels" default n depends on CONFIG_INSMOD + select CONFIG_MODUTILS_OBJ help Provide insmod support for older (pre 2.1) Linux kernels. @@ -36,17 +43,17 @@ bool " Support version 2.1.x to 2.4.x Linux kernels" default y depends on CONFIG_INSMOD + select CONFIG_MODUTILS_OBJ help Support module loading for newer (post 2.1) Linux kernels. -if 0 config CONFIG_FEATURE_2_6_MODULES bool " Support version 2.6.x Linux kernels" default n depends on CONFIG_INSMOD + select CONFIG_MODUTILS_OBJ_2_6 help - Support module loading for newer (post 2.1) Linux kernels. -endif + Support module loading for post 2.6 Linux kernels. config CONFIG_FEATURE_INSMOD_VERSION_CHECKING bool " Module version checking" @@ -94,7 +101,7 @@ lsmod is used to display a list of loaded modules. config CONFIG_FEATURE_QUERY_MODULE_INTERFACE - bool " Support lsmod query_module interface (add 638 bytes)" + bool " Support lsmod query_module interface" default y depends on CONFIG_LSMOD && ( CONFIG_FEATURE_2_4_MODULES || CONFIG_FEATURE_2_6_MODULES ) help Index: modutils/insmod.c =================================================================== --- modutils/insmod.c (revision 291) +++ modutils/insmod.c (working copy) @@ -77,7 +77,6 @@ #include <string.h> #include <getopt.h> #include <fcntl.h> -#include <sys/utsname.h> #include "busybox.h" #include "modutils.h" @@ -92,16 +91,18 @@ static int flag_quiet = 0; static int flag_export = 1; +static int k_version = 0; +static char k_strversion[STRVERSIONLEN]; + static int n_ext_modules_used; static int m_has_modinfo; static int gplonly_seen; -char *m_filename; -char *m_fullName; +static char *m_filename; +static char *m_fullName; /*======================================================================*/ - static int check_module_name_match(const char *filename, struct stat *statbuf, void *userdata) { @@ -127,10 +128,8 @@ /* Conditionally add the symbols from the given symbol set to the new module. */ -static int -add_symbols_from( - struct obj_file *f, - int idx, struct module_symbol *syms, size_t nsyms, int gpl) +static int add_symbols_from(struct obj_file *f, int idx, + struct module_symbol *syms, size_t nsyms, int gpl) { struct module_symbol *s; size_t i; @@ -160,6 +159,7 @@ } sym = obj_find_symbol(f, (char *) s->name); + if (sym && ELFW(ST_BIND) (sym->info) != STB_LOCAL) { sym = obj_add_symbol(f, (char *) s->name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), @@ -222,159 +222,11 @@ } +#ifdef CONFIG_FEATURE_2_2_MODULES + /*======================================================================*/ /* Functions relating to module loading in pre 2.1 kernels. */ - static int -old_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q; - struct obj_symbol *sym; - int *loc; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - *q++ = '\0'; - - sym = obj_find_symbol(f, p); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - bb_error_msg("symbol for parameter %s not found", p); - return 0; - } - - loc = (int *) (f->sections[sym->secidx]->contents + sym->value); - - /* Do C quoting if we begin with a ". */ - if (*q == '"') { - char *r, *str; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - bb_error_msg("improperly terminated string argument for %s", p); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - obj_string_patch(f, sym->secidx, sym->value, str); - } else if (*q >= '0' && *q <= '9') { - do - *loc++ = strtoul(q, &q, 0); - while (*q++ == ','); - } else { - char *contents = f->sections[sym->secidx]->contents; - char *myloc = contents + sym->value; - char *r; /* To search for commas */ - - /* Break the string with comas */ - while ((r = strchr(q, ',')) != (char *) NULL) { - *r++ = '\0'; - obj_string_patch(f, sym->secidx, myloc - contents, q); - myloc += sizeof(char *); - q = r; - } - - /* last part */ - obj_string_patch(f, sym->secidx, myloc - contents, q); - } - - argc--, argv++; - } - - return 1; -} - -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING -static int old_is_module_checksummed(struct obj_file *f) -{ - return obj_find_symbol(f, "Using_Versions") != NULL; -} -/* Get the module's kernel version in the canonical integer form. */ - - static int -old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - struct obj_symbol *sym; - char *p, *q; - int a, b, c; - - sym = obj_find_symbol(f, "kernel_version"); - if (sym == NULL) - return -1; - - p = f->sections[sym->secidx]->contents + sym->value; - safe_strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - -#ifdef CONFIG_FEATURE_2_2_MODULES - /* Fetch all the symbols and divvy them up as appropriate for the modules. */ static int old_get_kernel_symbols(const char *m_name) @@ -449,19 +301,6 @@ return 1; } -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int old_is_kernel_checksummed(void) -{ - /* Using_Versions is the first symbol. */ - if (nksyms > 0 - && strcmp((char *) ksyms[0].name, - "Using_Versions") == 0) return ksyms[0].value; - else - return 0; -} - - static int old_create_mod_use_count(struct obj_file *f) { struct obj_section *sec; @@ -585,292 +424,11 @@ #endif /* CONFIG_FEATURE_2_2_MODULES */ +#ifdef CONFIG_FEATURE_2_4_MODULES - /*======================================================================*/ /* Functions relating to module loading after 2.1.18. */ - static int -new_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q, *key, *sym_name; - struct obj_symbol *sym; - char *contents, *loc; - int min, max, n; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - - key = alloca(q - p + 6); - memcpy(key, "parm_", 5); - memcpy(key + 5, p, q - p); - key[q - p + 5] = 0; - - p = get_modinfo_value(f, key); - key += 5; - if (p == NULL) { - bb_error_msg("invalid parameter %s", key); - return 0; - } - -#ifdef SYMBOL_PREFIX - sym_name = alloca (strlen (key) + sizeof SYMBOL_PREFIX); - strcpy (sym_name, SYMBOL_PREFIX); - strcat (sym_name, key); -#else - sym_name = key; -#endif - sym = obj_find_symbol(f, sym_name); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - bb_error_msg("symbol for parameter %s not found", key); - return 0; - } - - if (isdigit(*p)) { - min = strtoul(p, &p, 10); - if (*p == '-') - max = strtoul(p + 1, &p, 10); - else - max = min; - } else - min = max = 1; - - contents = f->sections[sym->secidx]->contents; - loc = contents + sym->value; - n = (*++q != '\0'); - - while (1) { - if ((*p == 's') || (*p == 'c')) { - char *str; - - /* Do C quoting if we begin with a ", else slurp the lot. */ - if (*q == '"') { - char *r; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - bb_error_msg("improperly terminated string argument for %s", - key); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - ++q; - } else { - char *r; - - /* In this case, the string is not quoted. We will break - it using the coma (like for ints). If the user wants to - include comas in a string, he just has to quote it */ - - /* Search the next coma */ - r = strchr(q, ','); - - /* Found ? */ - if (r != (char *) NULL) { - /* Recopy the current field */ - str = alloca(r - q + 1); - memcpy(str, q, r - q); - - /* I don't know if it is useful, as the previous case - doesn't nul terminate the string ??? */ - str[r - q] = '\0'; - - /* Keep next fields */ - q = r; - } else { - /* last string */ - str = q; - q = ""; - } - } - - if (*p == 's') { - /* Normal string */ - obj_string_patch(f, sym->secidx, loc - contents, str); - loc += tgt_sizeof_char_p; - } else { - /* Array of chars (in fact, matrix !) */ - unsigned long charssize; /* size of each member */ - - /* Get the size of each member */ - /* Probably we should do that outside the loop ? */ - if (!isdigit(*(p + 1))) { - bb_error_msg("parameter type 'c' for %s must be followed by" - " the maximum size", key); - return 0; - } - charssize = strtoul(p + 1, (char **) NULL, 10); - - /* Check length */ - if (strlen(str) >= charssize) { - bb_error_msg("string too long for %s (max %ld)", key, - charssize - 1); - return 0; - } - - /* Copy to location */ - strcpy((char *) loc, str); - loc += charssize; - } - } else { - long v = strtoul(q, &q, 0); - switch (*p) { - case 'b': - *loc++ = v; - break; - case 'h': - *(short *) loc = v; - loc += tgt_sizeof_short; - break; - case 'i': - *(int *) loc = v; - loc += tgt_sizeof_int; - break; - case 'l': - *(long *) loc = v; - loc += tgt_sizeof_long; - break; - - default: - bb_error_msg("unknown parameter type '%c' for %s", *p, key); - return 0; - } - } - -retry_end_of_value: - switch (*q) { - case '\0': - goto end_of_arg; - - case ' ': - case '\t': - case '\n': - case '\r': - ++q; - goto retry_end_of_value; - - case ',': - if (++n > max) { - bb_error_msg("too many values for %s (max %d)", key, max); - return 0; - } - ++q; - break; - - default: - bb_error_msg("invalid argument syntax for %s", key); - return 0; - } - } - -end_of_arg: - if (n < min) { - bb_error_msg("too few values for %s (min %d)", key, min); - return 0; - } - - argc--, argv++; - } - - return 1; -} - -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING -static int new_is_module_checksummed(struct obj_file *f) -{ - const char *p = get_modinfo_value(f, "using_checksums"); - if (p) - return atoi(p); - else - return 0; -} - -/* Get the module's kernel version in the canonical integer form. */ - - static int -new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - char *p, *q; - int a, b, c; - - p = get_modinfo_value(f, "kernel_version"); - if (p == NULL) - return -1; - safe_strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - - -#ifdef CONFIG_FEATURE_2_4_MODULES - /* Fetch the loaded modules, and all currently exported symbols. */ static int new_get_kernel_symbols(void) @@ -963,23 +521,6 @@ } -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int new_is_kernel_checksummed(void) -{ - struct module_symbol *s; - size_t i; - - /* Using_Versions is not the first symbol, but it should be in there. */ - - for (i = 0, s = ksyms; i < nksyms; ++i, ++s) - if (strcmp((char *) s->name, "Using_Versions") == 0) - return s->value; - - return 0; -} - - static int new_create_this_module(struct obj_file *f, const char *m_name) { struct obj_section *sec; @@ -1274,29 +815,83 @@ if (fd >= 0) close(fd); } -#else /* CONFIG_FEATURE_CHECK_TAINTED_MODULE */ -#define check_tainted_module(x, y) do { } while(0); #endif /* CONFIG_FEATURE_CHECK_TAINTED_MODULE */ -#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS -/* add module source, timestamp, kernel version and a symbol for the - * start of some sections. this info is used by ksymoops to do better - * debugging. - */ - static int -get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ #ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING - if (get_modinfo_value(f, "kernel_version") == NULL) - return old_get_module_version(f, str); - else - return new_get_module_version(f, str); -#else /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - strncpy(str, "???", sizeof(str)); +/* Get the module's kernel version in the canonical integer form. */ +static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ + int a, b, c; + char *p, *q; + + if ((p = get_modinfo_value(f, "kernel_version")) == NULL) { + struct obj_symbol *sym; + + m_has_modinfo = 0; + if ((sym = obj_find_symbol(f, "kernel_version")) == NULL) + sym = obj_find_symbol(f, "__module_kernel_version"); + if (sym == NULL) + return -1; + p = f->sections[sym->secidx]->contents + sym->value; + } else + m_has_modinfo = 1; + + strncpy(str, p, STRVERSIONLEN-1); + str[STRVERSIONLEN-1] = '\0'; + p = str; + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + + return a << 16 | b << 8 | c; +} +#else +static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) __attribute__((unused)); +static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ return -1; +} #endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ + +#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING +/* Return the kernel symbol checksum version, or zero if not used. */ +static int is_kernel_checksummed(void) +{ + struct module_symbol *s; + size_t i; + + /* + * Using_Versions might not be the first symbol, + * but it should be in there. + */ + for (i = 0, s = ksyms; i < nksyms; ++i, ++s) + if (strcmp((char *) s->name, "Using_Versions") == 0) + return s->value; + + return 0; } +static int is_module_checksummed(struct obj_file *f) +{ + if (m_has_modinfo) { + const char *p = get_modinfo_value(f, "using_checksums"); + if (p) + return atoi(p); + else + return 0; + } else + return obj_find_symbol(f, "Using_Versions") != NULL; +} +#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ + +#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS /* add module source, timestamp, kernel version and a symbol for the * start of some sections. this info is used by ksymoops to do better * debugging. @@ -1371,7 +966,7 @@ new_add_ksymtab(f, sym); } free(absolute_filename); -#ifdef _NOT_SUPPORTED_ + /* record where the persistent data is going, same address as previous symbol */ if (f->persist) { @@ -1388,7 +983,7 @@ if (use_ksymtab) new_add_ksymtab(f, sym); } -#endif /* _NOT_SUPPORTED_ */ + /* tag the desired sections if size is non-zero */ for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) { @@ -1414,6 +1009,246 @@ } #endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ +static int process_module_arguments(struct obj_file *f, int argc, char **argv, int required) +{ + for (; argc > 0; ++argv, --argc) { + struct obj_symbol *sym; + int c; + int min, max; + int n; + char *contents; + char *input; + char *fmt; + char *key; + char *loc; + + if ((input = strchr(*argv, '=')) == NULL) + continue; + + n = input - *argv; + input += 1; /* skip '=' */ + + key = alloca(n + 6); + + if (m_has_modinfo) { + memcpy(key, "parm_", 5); + memcpy(key + 5, *argv, n); + key[n + 5] = '\0'; + if ((fmt = get_modinfo_value(f, key)) == NULL) { + if (required || flag_verbose) { + bb_error_msg("Warning: ignoring %s, no such parameter in this module", *argv); + continue; + } + } + key += 5; + + if (isdigit(*fmt)) { + min = strtoul(fmt, &fmt, 10); + if (*fmt == '-') + max = strtoul(fmt + 1, &fmt, 10); + else + max = min; + } else + min = max = 1; + } else { /* not m_has_modinfo */ + memcpy(key, *argv, n); + key[n] = '\0'; + + if (isdigit(*input)) + fmt = "i"; + else + fmt = "s"; + min = max = 0; + } + + sym = obj_find_symbol(f, key); + + /* + * Also check that the parameter was not + * resolved from the kernel. + */ + if (sym == NULL || sym->secidx > SHN_HIRESERVE) { + bb_error_msg("symbol for parameter %s not found", key); + return 0; + } + + contents = f->sections[sym->secidx]->contents; + loc = contents + sym->value; + n = 1; + + while (*input) { + char *str; + + switch (*fmt) { + case 's': + case 'c': + /* + * Do C quoting if we begin with a ", + * else slurp the lot. + */ + if (*input == '"') { + char *r; + + str = alloca(strlen(input)); + for (r = str, input++; *input != '"'; ++input, ++r) { + if (*input == '\0') { + bb_error_msg("improperly terminated string argument for %s", key); + return 0; + } + /* else */ + if (*input != '\\') { + *r = *input; + continue; + } + /* else handle \ */ + switch (*++input) { + case 'a': *r = '\a'; break; + case 'b': *r = '\b'; break; + case 'e': *r = '\033'; break; + case 'f': *r = '\f'; break; + case 'n': *r = '\n'; break; + case 'r': *r = '\r'; break; + case 't': *r = '\t'; break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + c = *input - '0'; + if ('0' <= input[1] && input[1] <= '7') { + c = (c * 8) + *++input - '0'; + if ('0' <= input[1] && input[1] <= '7') + c = (c * 8) + *++input - '0'; + } + *r = c; + break; + + default: *r = *input; break; + } + } + *r = '\0'; + ++input; + } else { + /* + * The string is not quoted. + * We will break it using the comma + * (like for ints). + * If the user wants to include commas + * in a string, he just has to quote it + */ + char *r; + + /* Search the next comma */ + if ((r = strchr(input, ',')) != NULL) { + /* + * Found a comma + * Recopy the current field + */ + str = alloca(r - input + 1); + memcpy(str, input, r - input); + str[r - input] = '\0'; + /* Keep next fields */ + input = r; + } else { + /* last string */ + str = input; + input = ""; + } + } + + if (*fmt == 's') { + /* Normal string */ + obj_string_patch(f, sym->secidx, loc - contents, str); + loc += tgt_sizeof_char_p; + } else { + /* Array of chars (in fact, matrix !) */ + long charssize; /* size of each member */ + + /* Get the size of each member */ + /* Probably we should do that outside the loop ? */ + if (!isdigit(*(fmt + 1))) { + bb_error_msg("parameter type 'c' for %s must be followed by" + " the maximum size", key); + return 0; + } + charssize = strtoul(fmt + 1, (char **) NULL, 10); + + /* Check length */ + if (strlen(str) >= charssize-1) { + bb_error_msg("string too long for %s (max %ld)", + key, charssize - 1); + return 0; + } + /* Copy to location */ + strcpy((char *) loc, str); /* safe, see check above */ + loc += charssize; + } + /* + * End of 's' and 'c' + */ + break; + + case 'b': + *loc++ = strtoul(input, &input, 0); + break; + + case 'h': + *(short *) loc = strtoul(input, &input, 0); + loc += tgt_sizeof_short; + break; + + case 'i': + *(int *) loc = strtoul(input, &input, 0); + loc += tgt_sizeof_int; + break; + + case 'l': + *(long *) loc = strtoul(input, &input, 0); + loc += tgt_sizeof_long; + break; + + default: + bb_error_msg("unknown parameter type '%c' for %s", + *fmt, key); + return 0; + } + /* + * end of switch (*fmt) + */ + + while (*input && isspace(*input)) + ++input; + if (*input == '\0') + break; /* while (*input) */ + /* else */ + + if (*input == ',') { + if (max && (++n > max)) { + bb_error_msg("too many values for %s (max %d)", key, max); + return 0; + } + ++input; + /* continue with while (*input) */ + } else { + bb_error_msg("invalid argument syntax for %s: '%c'", + key, *input); + return 0; + } + } /* end of while (*input) */ + + if (min && (n < min)) { + bb_error_msg("too few values for %s (min %d)", key, min); + return 0; + } + } /* end of for (;argc > 0;) */ + + return 1; +} + #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP static void print_load_map(struct obj_file *f) { @@ -1506,77 +1341,73 @@ #endif +#if defined(CONFIG_FEATURE_2_2_MODULES) || defined (CONFIG_FEATURE_2_4_MODULES) +static int do_2_0_and_2_4(int fp, int argc, char **argv, char *m_name); +#endif +#ifdef CONFIG_FEATURE_2_6_MODULES +static int do_2_6(int fp, int argc, char **argv); +#endif + extern int insmod_main( int argc, char **argv) { int opt; - int k_crcs; int len; char *tmp, *tmp1; - unsigned long m_size; - ElfW(Addr) m_addr; - struct obj_file *f; struct stat st; char *m_name = 0; - int exit_status = EXIT_FAILURE; -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING - struct utsname uts_info; - char m_strversion[STRVERSIONLEN]; - int m_version; - int m_crcs; -#endif - int fp = 0; + int fp; #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP int flag_print_load_map = 0; #endif - int gpl; /* Parse any options */ #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP - while ((opt = getopt(argc, argv, "fkqsvxmLo:")) > 0) { + while ((opt = getopt(argc, argv, "fkqsvxmLo:")) > 0) #else - while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) { + while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) #endif - switch (opt) { - case 'f': /* force loading */ - flag_force_load = 1; - break; - case 'k': /* module loaded by kerneld, auto-cleanable */ - flag_autoclean = 1; - break; - case 's': /* log to syslog */ - /* log to syslog -- not supported */ - /* but kernel needs this for request_module(), */ - /* as this calls: modprobe -k -s -- <module> */ - /* so silently ignore this flag */ - break; - case 'v': /* verbose output */ - flag_verbose = 1; - break; - case 'q': /* silent */ - flag_quiet = 1; - break; - case 'x': /* do not export externs */ - flag_export = 0; - break; - case 'o': /* name the output module */ - free(m_name); - m_name = bb_xstrdup(optarg); - break; - case 'L': /* Stub warning */ - /* This is needed for compatibility with modprobe. - * In theory, this does locking, but we don't do - * that. So be careful and plan your life around not - * loading the same module 50 times concurrently. */ - break; + { + switch (opt) { + case 'f': /* force loading */ + flag_force_load = 1; + break; + case 'k': /* module loaded by kerneld, auto-cleanable */ + flag_autoclean = 1; + break; + case 's': /* log to syslog */ + /* log to syslog -- not supported */ + /* but kernel needs this for request_module(), */ + /* as this calls: modprobe -k -s -- <module> */ + /* so silently ignore this flag */ + break; + case 'v': /* verbose output */ + flag_verbose = 1; + break; + case 'q': /* silent */ + flag_quiet = 1; + break; + case 'x': /* do not export externs */ + flag_export = 0; + break; + case 'o': /* name the output module */ + free(m_name); + m_name = bb_xstrdup(optarg); + break; + case 'L': /* Stub warning */ + /* This is needed for compatibility with modprobe. + * In theory, this does locking, but we don't do + * that. So be careful and plan your life around not + * loading the same module 50 times concurrently. */ + break; #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP - case 'm': /* print module load map */ - flag_print_load_map = 1; - break; + case 'm': /* print module load map */ + flag_print_load_map = 1; + break; #endif - default: - bb_show_usage(); + default: + bb_show_usage(); + } } - } if (argv[optind] == NULL) { bb_show_usage(); @@ -1587,15 +1418,24 @@ tmp = basename(tmp1); len = strlen(tmp); - if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { - len-=2; + k_version = get_kernel_version(k_strversion); + +#if defined(CONFIG_FEATURE_2_6_MODULES) + if (k_version > 0x20500 && len > 3 && tmp[len - 3] == '.' && + tmp[len - 2] == 'k' && tmp[len - 1] == 'o') { + len-=3; tmp[len] = '\0'; } + else +#endif + if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { + len-=2; + tmp[len] = '\0'; + } - bb_xasprintf(&m_fullName, "%s.o", tmp); #if defined(CONFIG_FEATURE_2_6_MODULES) - if (k_version > 4) + if (k_version > 0x20500) bb_xasprintf(&m_fullName, "%s.ko", tmp); else #endif @@ -1605,22 +1445,19 @@ m_name = tmp; } else { free(tmp1); - tmp1 = 0; /* flag for free(m_name) before exit() */ } /* Get a filedesc for the module. Check we we have a complete path */ if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) || - (fp = open(argv[optind], O_RDONLY)) == 0) { - struct utsname myuname; - + (fp = open(argv[optind], O_RDONLY)) < 0) { /* 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 (uname(&myuname) == 0) { + if (k_version) { /* uname succeedd */ char *module_dir; char *tmdn; char real_module_dir[FILENAME_MAX]; - tmdn = concat_path_file(_PATH_MODULES, myuname.release); + tmdn = concat_path_file(_PATH_MODULES, k_strversion); /* 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 @@ -1636,7 +1473,7 @@ } /* Check if we have found anything yet */ - if (m_filename == 0 || ((fp = open(m_filename, O_RDONLY)) == 0)) + if (m_filename == 0 || ((fp = open(m_filename, O_RDONLY)) < 0)) { char module_dir[FILENAME_MAX]; @@ -1647,94 +1484,103 @@ /* No module found under /lib/modules/`uname -r`, this * time cast the net a bit wider. Search /lib/modules/ */ if (! recursive_action(module_dir, TRUE, FALSE, FALSE, - check_module_name_match, 0, m_fullName)) + check_module_name_match, 0, m_fullName)) { if (m_filename == 0 - || ((fp = open(m_filename, O_RDONLY)) == 0)) + || ((fp = open(m_filename, O_RDONLY)) < 0)) { bb_error_msg("%s: no module by that name found", m_fullName); - goto out; + return EXIT_FAILURE; } } else bb_error_msg_and_die("%s: no module by that name found", m_fullName); } - } else + } else m_filename = bb_xstrdup(argv[optind]); if (!flag_quiet) printf("Using %s\n", m_filename); + if (k_version > 0x20500) + { +#ifdef CONFIG_FEATURE_2_6_MODULES + return do_2_6(fp, argc - optind, argv + optind); +#endif + } + else if (k_version > 0x20100) + { +#ifdef CONFIG_FEATURE_2_4_MODULES + return do_2_0_and_2_4(fp, argc - optind, argv + optind, m_name); +#endif + } + else if (k_version > 0x20000) + { +#ifdef CONFIG_FEATURE_2_2_MODULES + return do_2_0_and_2_4(fp, argc - optind, argv + optind, m_name); +#endif + } + return EXIT_FAILURE; +} + +#if defined(CONFIG_FEATURE_2_2_MODULES) || defined (CONFIG_FEATURE_2_4_MODULES) +static int do_2_0_and_2_4(int fp, int argc, char **argv, char *m_name) +{ + struct obj_file *f; +#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING + int k_crcs; + char m_strversion[STRVERSIONLEN]; + int m_version; + int m_crcs; +#endif + unsigned long m_size; + ElfW(Addr) m_addr; + int gpl; + if ((f = obj_load(fp, ET_REL, m_filename)) == NULL) bb_perror_msg_and_die("Could not load the module"); - if (get_modinfo_value(f, "kernel_version") == NULL) - m_has_modinfo = 0; - else - m_has_modinfo = 1; - -#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING /* Version correspondence? */ - if (!flag_quiet) { - if (uname(&uts_info) < 0) - uts_info.release[0] = '\0'; - if (m_has_modinfo) { - m_version = new_get_module_version(f, m_strversion); - } else { - m_version = old_get_module_version(f, m_strversion); - if (m_version == -1) { - bb_error_msg("couldn't find the kernel version the module was " - "compiled for"); - goto out; - } - } - - if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { - if (flag_force_load) { - bb_error_msg("Warning: kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s", - m_filename, m_strversion, uts_info.release); - } else { - bb_error_msg("kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s.", - m_filename, m_strversion, uts_info.release); - goto out; - } - } +#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING + m_version = get_module_version(f, m_strversion); + if (m_version == -1) { + bb_error_msg_and_die("couldn't find the kernel version the module was compiled for"); } - - k_crcs = 0; #endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ - k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); - - if (k_new_syscalls) { + if (k_version > 0x20100) + { #ifdef CONFIG_FEATURE_2_4_MODULES if (!new_get_kernel_symbols()) - goto out; - k_crcs = new_is_kernel_checksummed(); -#else - bb_error_msg("Not configured to support new kernels"); - goto out; + return EXIT_FAILURE; #endif - } else { + } + else + { #ifdef CONFIG_FEATURE_2_2_MODULES - if (!old_get_kernel_symbols(m_name)) - goto out; - k_crcs = old_is_kernel_checksummed(); -#else - bb_error_msg("Not configured to support old kernels"); - goto out; + if (!old_get_kernel_symbols()) + return EXIT_FAILURE; #endif } #ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING - if (m_has_modinfo) - m_crcs = new_is_module_checksummed(f); - else - m_crcs = old_is_module_checksummed(f); - + k_crcs = is_kernel_checksummed(); + m_crcs = is_module_checksummed(f); + if ((m_crcs == 0 || k_crcs == 0) && + strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) { + if (flag_force_load) { + bb_error_msg("Warning: kernel-module version mismatch\n" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s", + m_name, m_strversion, k_strversion); + } else { + if (!flag_quiet) + bb_error_msg("kernel-module version mismatch\n" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s.", + m_name, m_strversion, k_strversion); + return EXIT_FAILURE; + } + } if (m_crcs != k_crcs) obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); #endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */ @@ -1745,29 +1591,27 @@ /* Allocate common symbols, symbol tables, and string tables. */ - if (k_new_syscalls + if (k_new_syscalls ? !new_create_this_module(f, m_name) - : !old_create_mod_use_count(f)) + : !old_create_mod_use_count(f)) { - goto out; + return EXIT_FAILURE; } if (!obj_check_undefineds(f, 0)) { - goto out; + return EXIT_FAILURE; } obj_allocate_commons(f); +#ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE check_tainted_module(f, m_name); +#endif /* done with the module name, on to the optional var=value arguments */ ++optind; if (optind < argc) { - if (m_has_modinfo - ? !new_process_module_arguments(f, argc - optind, argv + optind) - : !old_process_module_arguments(f, argc - optind, argv + optind)) - { - goto out; - } + if (!process_module_arguments(f, argc - optind, argv + optind, 1)) + return EXIT_FAILURE; } arch_create_got(f); @@ -1787,26 +1631,26 @@ if (m_addr == -1) switch (errno) { case EEXIST: bb_error_msg("A module named %s already exists", m_name); - goto out; + return EXIT_FAILURE; case ENOMEM: bb_error_msg("Can't allocate kernel memory for module; needed %lu bytes", m_size); - goto out; + return EXIT_FAILURE; default: bb_perror_msg("create_module: %s", m_name); - goto out; + return EXIT_FAILURE; } if (!obj_relocate(f, m_addr)) { delete_module(m_name); - goto out; + return EXIT_FAILURE; } - if (k_new_syscalls + if (k_new_syscalls ? !new_init_module(m_name, f, m_size) - : !old_init_module(m_name, f, m_size)) + : !old_init_module(m_name, f, m_size)) { delete_module(m_name); - goto out; + return EXIT_FAILURE; } #ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP @@ -1814,22 +1658,71 @@ print_load_map(f); #endif - exit_status = EXIT_SUCCESS; + return EXIT_SUCCESS; +} +#endif /* CONFIG_FEATURE_2_2_MODULES || CONFIG_FEATURE_2_4_MODULES */ -out: -#ifdef CONFIG_FEATURE_CLEAN_UP - if(fp) - fclose(fp); - if(tmp1) { - free(tmp1); - } else { - free(m_name); +#ifdef CONFIG_FEATURE_2_6_MODULES +#include <sys/mman.h> +#include <sys/syscall.h> + +/* We use error numbers in a loose translation... */ +static const char *moderror(int err) +{ + switch (err) { + case ENOEXEC: + return "Invalid module format"; + case ENOENT: + return "Unknown symbol in module"; + case ESRCH: + return "Module has wrong symbol version"; + case EINVAL: + return "Invalid parameters"; + default: + return strerror(err); } - free(m_filename); -#endif - return(exit_status); } +static int do_2_6(int fd, int argc, char **argv) +{ + int i; + long int ret; + struct stat st; + unsigned long len; + void *map; + char *options = bb_xstrdup(""); + + /* Rest is options */ + for (i = 2; i < argc; i++) { + options = xrealloc(options, strlen(options) + 2 + strlen(argv[i]) + 2); + /* Spaces handled by "" pairs, but no way of escaping quotes */ + if (strchr(argv[i], ' ')) { + strcat(options, "\""); + strcat(options, argv[i]); + strcat(options, "\""); + } else { + strcat(options, argv[i]); + } + strcat(options, " "); + } + + fstat(fd, &st); + len = st.st_size; + map = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) { + bb_perror_msg_and_die("cannot mmap `%s'", m_filename); + } + + ret = syscall(__NR_init_module, map, len, options); + if (ret != 0) { + bb_perror_msg_and_die("cannot insert `%s': %s (%li)", + m_filename, moderror(errno), ret); + } + + return 0; +} +#endif /* CONFIG_FEATURE_2_6_MODULES */ + int check_module (const char *mod) { k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); @@ -1842,3 +1735,4 @@ return -1; } + Index: modutils/obj-2.6/moduleops_core.c =================================================================== --- modutils/obj-2.6/moduleops_core.c (revision 0) +++ modutils/obj-2.6/moduleops_core.c (revision 0) @@ -0,0 +1,169 @@ +/* Load the given section: NULL on error. */ +static void *PERBIT(load_section)(ElfPERBIT(Ehdr) *hdr, + const char *secname, + unsigned long *size) +{ + ElfPERBIT(Shdr) *sechdrs; + unsigned int i; + char *secnames; + + /* Grab section headers and strings so we can tell who is who */ + sechdrs = (void *)hdr + hdr->e_shoff; + secnames = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + /* Find the section they want */ + for (i = 1; i < hdr->e_shnum; i++) { + if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) { + *size = sechdrs[i].sh_size; + return (void *)hdr + sechdrs[i].sh_offset; + } + } + *size = 0; + return NULL; +} + +static void PERBIT(load_symbols)(struct module *module) +{ + struct PERBIT(kernel_symbol) *ksyms; + char *ksymstrings; + unsigned long i, size; + + /* New-style: strings are in this section. */ + ksymstrings = PERBIT(load_section)(module->data, "__ksymtab_strings", + &size); + if (ksymstrings) { + unsigned int i = 0; + for (;;) { + /* Skip any zero padding. */ + while (!ksymstrings[i]) + if (++i >= size) + return; + add_symbol(ksymstrings+i, module); + i += strlen(ksymstrings+i); + } + /* GPL symbols too */ + ksymstrings = PERBIT(load_section)(module->data, + "__ksymtab_strings_gpl", + &size); + for (;;) { + /* Skip any zero padding. */ + while (!ksymstrings[i]) + if (++i >= size) + return; + add_symbol(ksymstrings+i, module); + i += strlen(ksymstrings+i); + } + return; + } + + /* Old-style. */ + ksyms = PERBIT(load_section)(module->data, "__ksymtab", &size); + for (i = 0; i < size / sizeof(struct PERBIT(kernel_symbol)); i++) + add_symbol(ksyms[i].name, module); + ksyms = PERBIT(load_section)(module->data, "__gpl_ksymtab", &size); + for (i = 0; i < size / sizeof(struct PERBIT(kernel_symbol)); i++) + add_symbol(ksyms[i].name, module); +} + +static char *PERBIT(get_aliases)(struct module *module, unsigned long *size) +{ + return PERBIT(load_section)(module->data, ".modalias", size); +} + +static char *PERBIT(get_modinfo)(struct module *module, unsigned long *size) +{ + return PERBIT(load_section)(module->data, ".modinfo", size); +} + +#ifndef STT_REGISTER +#define STT_REGISTER 13 /* Global register reserved to app. */ +#endif + +/* Calculate the dependencies for this module */ +static void PERBIT(calculate_deps)(struct module *module, int verbose) +{ + unsigned int i; + unsigned long size; + char *strings; + ElfPERBIT(Sym) *syms; + ElfPERBIT(Ehdr) *hdr; + int handle_register_symbols; + + strings = PERBIT(load_section)(module->data, ".strtab", &size); + syms = PERBIT(load_section)(module->data, ".symtab", &size); + + if (!strings || !syms) { + warn("Couldn't find symtab and strtab in module %s\n", + module->pathname); + return; + } + + hdr = module->data; + handle_register_symbols = 0; + if (hdr->e_machine == EM_SPARC || + hdr->e_machine == EM_SPARCV9) + handle_register_symbols = 1; + + module->num_deps = 0; + module->deps = NULL; + for (i = 1; i < size / sizeof(syms[0]); i++) { + if (syms[i].st_shndx == SHN_UNDEF) { + /* Look for symbol */ + const char *name = strings + syms[i].st_name; + struct module *owner; + int weak; + + /* Not really undefined: sparc gcc 3.3 creates + U references when you have global asm + variables, to avoid anyone else mising + them. */ + if (handle_register_symbols + && (ELFPERBIT(ST_TYPE)(syms[i].st_info) + == STT_REGISTER)) + continue; + + weak = ELFPERBIT(ST_BIND)(syms[i].st_info) == STB_WEAK; + owner = find_symbol(name, module->pathname, weak); + if (owner) { + if (verbose) + printf("%s needs \"%s\": %s\n", + module->pathname, name, + owner->pathname); + add_dep(module, owner); + } + } + } +} + +static void *PERBIT(deref_sym)(ElfPERBIT(Ehdr) *hdr, const char *name) +{ + unsigned int i; + unsigned long size; + char *strings; + ElfPERBIT(Sym) *syms; + ElfPERBIT(Shdr) *sechdrs; + + sechdrs = (void *)hdr + hdr->e_shoff; + strings = PERBIT(load_section)(hdr, ".strtab", &size); + syms = PERBIT(load_section)(hdr, ".symtab", &size); + + /* Don't warn again: we already have above */ + if (!strings || !syms) + return NULL; + + for (i = 0; i < size / sizeof(syms[0]); i++) { + if (strcmp(strings + syms[i].st_name, name) == 0) { + return (void *)hdr + + sechdrs[syms[i].st_shndx].sh_offset + + syms[i].st_value; + } + } + return NULL; +} + +struct module_ops PERBIT(mod_ops) = { + .load_symbols = PERBIT(load_symbols), + .calculate_deps = PERBIT(calculate_deps), + .get_aliases = PERBIT(get_aliases), + .get_modinfo = PERBIT(get_modinfo), +}; Index: modutils/obj-2.6/list.h =================================================================== --- modutils/obj-2.6/list.h (revision 0) +++ modutils/obj-2.6/list.h (revision 0) @@ -0,0 +1,238 @@ +/* Stolen from Linux Kernel Source's list.h -- GPL. */ +#ifndef _MODINITTOOLS_LIST_H +#define _MODINITTOOLS_LIST_H + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#endif Index: modutils/obj-2.6/Makefile.in =================================================================== --- modutils/obj-2.6/Makefile.in (revision 0) +++ modutils/obj-2.6/Makefile.in (revision 0) @@ -0,0 +1,34 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2002 by Erik Andersen <andersee@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +MODUTILS_OBJ_2_6_AR:=obj-2.6.a +ifndef $(MODUTILS_OBJ_2_6_DIR) +MODUTILS_OBJ_2_6_DIR:=$(TOPDIR)modutils/obj-2.6/ +endif + +MODUTILS_OBJ_2_6-$(CONFIG_MODUTILS_OBJ_2_6) += \ + depmod.o \ + moduleops.o \ + zlibsupport.o + +libraries-y+=$(MODUTILS_OBJ_2_6_DIR)$(MODUTILS_OBJ_2_6_AR) + +$(MODUTILS_OBJ_2_6_DIR)$(MODUTILS_OBJ_2_6_AR): $(patsubst %,$(MODUTILS_OBJ_2_6_DIR)%, $(MODUTILS_OBJ_2_6-y)) + $(AR) -ro $@ $(patsubst %,$(MODUTILS_OBJ_2_6_DIR)%, $(MODUTILS_OBJ_2_6-y)) + Index: modutils/obj-2.6/zlibsupport.h =================================================================== --- modutils/obj-2.6/zlibsupport.h (revision 0) +++ modutils/obj-2.6/zlibsupport.h (revision 0) @@ -0,0 +1,10 @@ +#ifndef _ZLIB_SUPPORT_H +#define _ZLIB_SUPPORT_H + +/* Grab file. Decompresses if that is supported. Returns NULL on error. */ +extern void *grab_file(const char *filename, unsigned long *size); + +/* Free it up. */ +extern void release_file(void *data, unsigned long size); + +#endif /* _ZLIB_SUPPORT_H */ Index: modutils/obj-2.6/moduleops.c =================================================================== --- modutils/obj-2.6/moduleops.c (revision 0) +++ modutils/obj-2.6/moduleops.c (revision 0) @@ -0,0 +1,22 @@ +/* The nasty work of reading 32 and 64-bit modules is in here. */ +#include <elf.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "depmod.h" +#include "moduleops.h" + +#define PERBIT(x) x##32 +#define ElfPERBIT(x) Elf32_##x +#define ELFPERBIT(x) ELF32_##x +#include "moduleops_core.c" + +#undef PERBIT +#undef ElfPERBIT +#undef ELFPERBIT +#define PERBIT(x) x##64 +#define ElfPERBIT(x) Elf64_##x +#define ELFPERBIT(x) ELF64_##x +#include "moduleops_core.c" Index: modutils/obj-2.6/depmod.c =================================================================== --- modutils/obj-2.6/depmod.c (revision 0) +++ modutils/obj-2.6/depmod.c (revision 0) @@ -0,0 +1,628 @@ +/* New simplified depmod without backwards compat stuff and not + requiring ksyms. + + (C) 2002 Rusty Russell IBM Corporation + */ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <elf.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <sys/mman.h> + +#include "busybox.h" + +#include "depmod.h" +#include "moduleops.h" +#include "zlibsupport.h" + +/* I hate strcmp. */ +#define streq(a,b) (strcmp((a),(b)) == 0) + +#ifndef MODULE_DIR +#define MODULE_DIR "/lib/modules/" +#endif + +static int verbose; +static unsigned int skipchars; + +void *do_nofail(void *ptr, const char *file, int line, const char *expr) +{ + if (!ptr) { + bb_error_msg_and_die("Memory allocation failure %s line %d: %s.\n", + file, line, expr); + } + return ptr; +} + +#define SYMBOL_HASH_SIZE 1024 +struct symbol +{ + struct symbol *next; + struct module *owner; + char name[0]; +}; + +static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; + +/* This is based on the hash agorithm from gdbm, via tdb */ +static inline unsigned int tdb_hash(const char *name) +{ + unsigned value; /* Used to compute the hash value. */ + unsigned i; /* Used to cycle through random values. */ + + /* Set the initial value from the key size. */ + for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++) + value = (value + (((unsigned char *)name)[i] << (i*5 % 24))); + + return (1103515243 * value + 12345); +} + +void add_symbol(const char *name, struct module *owner) +{ + unsigned int hash; + struct symbol *new = NOFAIL(malloc(sizeof *new + strlen(name) + 1)); + + new->owner = owner; + strcpy(new->name, name); + + hash = tdb_hash(name) % SYMBOL_HASH_SIZE; + new->next = symbolhash[hash]; + symbolhash[hash] = new; +} + +static int print_unknown; + +struct module *find_symbol(const char *name, const char *modname, int weak) +{ + struct symbol *s; + + /* For our purposes, .foo matches foo. PPC64 needs this. */ + if (name[0] == '.') + name++; + + for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s=s->next) { + if (streq(s->name, name)) + return s->owner; + } + + if (print_unknown && !weak) + bb_error_msg("%s needs unknown symbol %s\n", modname, name); + + return NULL; +} + +void add_dep(struct module *mod, struct module *depends_on) +{ + unsigned int i; + + for (i = 0; i < mod->num_deps; i++) + if (mod->deps[i] == depends_on) + return; + + mod->deps = realloc(mod->deps, sizeof(mod->deps[0])*(mod->num_deps+1)); + mod->deps[mod->num_deps++] = depends_on; +} + +static void load_system_map(const char *filename) +{ + FILE *system_map; + char line[10240]; + + system_map = fopen(filename, "r"); + if (!system_map) + bb_error_msg_and_die("Could not open '%s': %s\n", filename, strerror(errno)); + + /* eg. c0294200 R __ksymtab_devfs_alloc_devnum */ + while (fgets(line, sizeof(line)-1, system_map)) { + char *ptr; + + /* Snip \n */ + ptr = strchr(line, '\n'); + *ptr = '\0'; + + ptr = strchr(line, ' '); + if (!ptr || !(ptr = strchr(ptr + 1, ' '))) + continue; + + /* Covers gpl-only and normal symbols. */ + if (strncmp(ptr+1, "__ksymtab_", strlen("__ksymtab_")) == 0) + add_symbol(ptr+1+strlen("__ksymtab_"), NULL); + } + + /* __this_module is magic inserted by kernel loader. */ + add_symbol("__this_module", NULL); + /* On S390, this is faked up too */ + add_symbol("_GLOBAL_OFFSET_TABLE_", NULL); +} + +static struct option options[] = { { "all", 0, NULL, 'a' }, + { "quick", 0, NULL, 'A' }, + { "basedir", 1, NULL, 'b' }, + { "errsyms", 0, NULL, 'e' }, + { "filesyms", 1, NULL, 'F' }, + { "help", 0, NULL, 'h' }, + { "show", 0, NULL, 'n' }, + { "dry-run", 0, NULL, 'n' }, + { "quiet", 0, NULL, 'q' }, + { "root", 0, NULL, 'r' }, + { "unresolved-error", 0, NULL, 'u' }, + { "verbose", 0, NULL, 'v' }, + { "version", 0, NULL, 'V' }, + /* Obsolete, but we need to parse it. */ + { "config", 1, NULL, 'C' }, + { NULL, 0, NULL, 0 } }; + +/* Version number or module name? Don't assume extension. */ +static int is_version_number(const char *version) +{ + unsigned int dummy; + + return (sscanf(version, "%u.%u.%u", &dummy, &dummy, &dummy) == 3); +} + +static int old_module_version(const char *version) +{ + /* Expect three part version. */ + unsigned int major, sub, minor; + + sscanf(version, "%u.%u.%u", &major, &sub, &minor); + + if (major > 2) return 0; + if (major < 2) return 1; + + /* 2.x */ + if (sub > 5) return 0; + if (sub < 5) return 1; + + /* 2.5.x */ + if (minor >= 48) return 0; + return 1; +} + +static void exec_old_depmod(char *argv[]) +{ + char *sep; + char pathname[strlen(argv[0])+1]; + char oldname[strlen("depmod") + strlen(argv[0]) + sizeof(".modutils")]; + + memset(pathname, 0, strlen(argv[0])+1); + sep = strrchr(argv[0], '/'); + if (sep) + memcpy(pathname, argv[0], sep - argv[0]+1); + sprintf(oldname, "%s%s.modutils", pathname, "depmod"); + + /* Recursion detection: we need an env var since we can't + change argv[0] (as older modutils uses it to determine + behavior). */ + if (getenv("MODULE_RECURSE")) + return; + setenv("MODULE_RECURSE", "y", 0); + + execvp(oldname, argv); + fprintf(stderr, + "Version requires old depmod, but couldn't run %s: %s\n", + oldname, strerror(errno)); + exit(2); +} + +static int ends_in(const char *name, const char *ext) +{ + unsigned int namelen, extlen; + + /* Grab lengths */ + namelen = strlen(name); + extlen = strlen(ext); + + if (namelen < extlen) return 0; + + if (streq(name + namelen - extlen, ext)) + return 1; + return 0; +} + +static struct module *grab_module(const char *_dirname, + const char *filename, + struct module *next) +{ + struct module *new; + + new = NOFAIL(malloc(sizeof(*new) + + strlen(_dirname) + 1 + strlen(filename) + 1)); + sprintf(new->pathname, "%s/%s", _dirname, filename); + INIT_LIST_HEAD(&new->dep_list); + + new->data = grab_file(new->pathname, &new->len); + if (!new->data) { + bb_error_msg("Can't read module %s: %s\n", + new->pathname, strerror(errno)); + goto fail_data; + } + + /* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */ + if (memcmp(new->data, ELFMAG, SELFMAG) != 0) { + bb_error_msg("Module %s is not an elf object\n", new->pathname); + goto fail; + } + + switch (((char *)new->data)[EI_CLASS]) { + case ELFCLASS32: + new->ops = &mod_ops32; + break; + case ELFCLASS64: + new->ops = &mod_ops64; + break; + default: + bb_error_msg("Module %s has elf unknown identifier %i\n", + new->pathname, ((char *)new->data)[EI_CLASS]); + goto fail; + } + new->ops->load_symbols(new); + + new->next = next; + return new; + +fail: + release_file(new->data, new->len); +fail_data: + free(new); + return next; +} + +struct module_traverse +{ + struct module_traverse *prev; + struct module *mod; +}; + +static int in_loop(struct module *mod, const struct module_traverse *traverse) +{ + const struct module_traverse *i; + + for (i = traverse; i; i = i->prev) { + if (i->mod == mod) + return 1; + } + return 0; +} + +/* Assume we are doing all the modules, so only report each loop once. */ +static void report_loop(const struct module *mod, + const struct module_traverse *traverse) +{ + const struct module_traverse *i; + + /* Check that start is least alphabetically. eg. a depends + on b depends on a will get reported for a, not b. */ + for (i = traverse->prev; i->prev; i = i->prev) { + if (strcmp(mod->pathname, i->mod->pathname) > 0) + return; + } + + /* Is start in the loop? If not, don't report now. eg. a + depends on b which depends on c which depends on b. Don't + report when generating depends for a. */ + if (mod != i->mod) + return; + + bb_error_msg("Loop detected: %s ", mod->pathname); + for (i = traverse->prev; i->prev; i = i->prev) + fprintf(stderr, "needs %s ", basename(i->mod->pathname)); + fprintf(stderr, "which needs %s again!\n", basename(mod->pathname)); +} + +/* This is damn slow, but loops actually happen, and we don't want to + just exit() and leave the user without any modules. */ +static int has_dep_loop(struct module *module, struct module_traverse *prev) +{ + unsigned int i; + struct module_traverse traverse = { .prev = prev, .mod = module }; + + if (in_loop(module, prev)) { + report_loop(module, &traverse); + return 1; + } + + for (i = 0; i < module->num_deps; i++) + if (has_dep_loop(module->deps[i], &traverse)) + return 1; + return 0; +} + +/* Uniquifies and orders a dependency list. */ +static void order_dep_list(struct module *start, struct module *mod) +{ + unsigned int i; + + for (i = 0; i < mod->num_deps; i++) { + /* If it was previously depended on, move it to the + tail. ie. if a needs b and c, and c needs b, we + must order b after c. */ + list_del(&mod->deps[i]->dep_list); + list_add_tail(&mod->deps[i]->dep_list, &start->dep_list); + order_dep_list(start, mod->deps[i]); + } +} + +static void del_module(struct module **modules, struct module *delme) +{ + struct module **i; + + /* Find pointer to it. */ + for (i = modules; *i != delme; i = &(*i)->next); + + *i = delme->next; +} + +static void output_deps(struct module *modules, + FILE *out) +{ + struct module *i; + + for (i = modules; i; i = i->next) + i->ops->calculate_deps(i, verbose); + + /* Strip out loops. */ + again: + for (i = modules; i; i = i->next) { + if (has_dep_loop(i, NULL)) { + bb_error_msg("Module %s ignored, due to loop\n", + i->pathname + skipchars); + del_module(&modules, i); + goto again; + } + } + + /* Now dump them out. */ + for (i = modules; i; i = i->next) { + struct list_head *j, *tmp; + order_dep_list(i, i); + + fprintf(out, "%s:", i->pathname + skipchars); + list_for_each_safe(j, tmp, &i->dep_list) { + struct module *dep + = list_entry(j, struct module, dep_list); + fprintf(out, " %s", dep->pathname + skipchars); + list_del_init(j); + } + fprintf(out, "\n"); + } +} + +static int smells_like_module(const char *name) +{ + return ends_in(name,".ko") || ends_in(name, ".ko.gz"); +} + +static struct module *grab_dir(const char *_dirname, struct module *next) +{ + DIR *dir; + struct dirent *dirent; + + dir = opendir(_dirname); + if (!dir) { + bb_error_msg("Couldn't open directory %s: %s\n", + _dirname, strerror(errno)); + return next; + } + + while ((dirent = readdir(dir)) != NULL) { + if (smells_like_module(dirent->d_name)) + next = grab_module(_dirname, dirent->d_name, next); + else if (!streq(dirent->d_name, ".") + && !streq(dirent->d_name, "..")) { + struct stat st; + + char subdir[strlen(_dirname) + 1 + + strlen(dirent->d_name) + 1]; + sprintf(subdir, "%s/%s", _dirname, dirent->d_name); + if (lstat(subdir, &st) != 0) + bb_error_msg("Couldn't stat %s: %s\n", subdir, + strerror(errno)); + else if (S_ISDIR(st.st_mode)) + next = grab_dir(subdir, next); + } + } + closedir(dir); + return next; +} + +/* Convert filename to the module name. Works if filename == modname, too. */ +static void filename2modname(char *modname, const char *filename) +{ + const char *afterslash; + unsigned int i; + + afterslash = strrchr(filename, '/'); + if (!afterslash) + afterslash = filename; + else + afterslash++; + + /* Convert to underscores, stop at first . */ + for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) { + if (afterslash[i] == '-') + modname[i] = '_'; + else + modname[i] = afterslash[i]; + } + modname[i] = '\0'; +} + +/* Simply dump hash table. */ +static void output_symbols(struct module *unused, FILE *out) +{ + unsigned int i; + + fprintf(out, "# Aliases for symbols, used by symbol_request().\n"); + for (i = 0; i < SYMBOL_HASH_SIZE; i++) { + struct symbol *s; + + for (s = symbolhash[i]; s; s = s->next) { + if (s->owner) { + char modname[strlen(s->owner->pathname)+1]; + filename2modname(modname, s->owner->pathname); + fprintf(out, "alias symbol:%s %s\n", + s->name, modname); + } + } + } +} + +static const char *next_string(const char *string, unsigned long *secsize) +{ + /* Skip non-zero chars */ + while (string[0]) { + string++; + if ((*secsize)-- <= 1) + return NULL; + } + + /* Skip any zero padding. */ + while (!string[0]) { + string++; + if ((*secsize)-- <= 1) + return NULL; + } + return string; +} + +static void output_aliases(struct module *modules, FILE *out) +{ + struct module *i; + const char *p; + long size; + + fprintf(out, "# Aliases extracted from modules themselves.\n"); + for (i = modules; i; i = i->next) { + char modname[strlen(i->pathname)+1]; + + filename2modname(modname, i->pathname); + + /* Grab from old-style .modalias section. */ + for (p = i->ops->get_aliases(i, &size); + p; + p = next_string(p, &size)) + fprintf(out, "alias %s %s\n", p, modname); + + /* Grab form new-style .modinfo section. */ + for (p = i->ops->get_modinfo(i, &size); + p; + p = next_string(p, &size)) { + if (strncmp(p, "alias=", strlen("alias=")) == 0) + fprintf(out, "alias %s %s\n", + p + strlen("alias="), modname); + } + } +} + +struct depfile { + char *name; + void (*func)(struct module *, FILE *); +}; + +static struct depfile depfiles[] = { + { "modules.dep", output_deps }, /* This is what we check for '-A'. */ +}; + +/* If we can't figure it out, it's safe to say "true". */ +static int any_modules_newer(const char *_dirname, time_t mtime) +{ + DIR *dir; + struct dirent *dirent; + + dir = opendir(_dirname); + if (!dir) + return 1; + + while ((dirent = readdir(dir)) != NULL) { + struct stat st; + char file[strlen(_dirname) + 1 + strlen(dirent->d_name) + 1]; + + if (streq(dirent->d_name, ".") || streq(dirent->d_name, "..")) + continue; + + sprintf(file, "%s/%s", _dirname, dirent->d_name); + if (lstat(file, &st) != 0) + return 1; + + if (smells_like_module(dirent->d_name)) { + if (st.st_mtime > mtime) + return 1; + } else if (S_ISDIR(st.st_mode)) { + if (any_modules_newer(file, mtime)) + return 1; + } + } + closedir(dir); + return 0; +} + +static int depfile_out_of_date(const char *_dirname) +{ + struct stat st; + char depfile[strlen(_dirname) + 1 + strlen(depfiles[0].name) + 1]; + + sprintf(depfile, "%s/%s", _dirname, depfiles[0].name); + + if (stat(depfile, &st) != 0) + return 1; + + return any_modules_newer(_dirname, st.st_mtime); +} + +int depmod_main_2_6(int argc, char *argv[], int all, int _verbose, int doing_stdout, const char *system_map, const char *base_dir, const char *_dirname) +{ + struct module *list = NULL; + int i; + + verbose = _verbose; + + /* We can't print unknowns without a System.map */ + if (!system_map) + print_unknown = 0; + else + load_system_map(system_map); + + if (!all) { + /* Do command line args. */ + for (; argc; ++argv, --argc) + list = grab_module("", *argv, list); + } else { + list = grab_dir(_dirname, list); + } + + for (i = 0; i < sizeof(depfiles)/sizeof(depfiles[0]); i++) { + FILE *out; + struct depfile *d = &depfiles[i]; + char depname[strlen(_dirname) + 1 + strlen(d->name) + 1]; + char tmpname[strlen(_dirname) + 1 + strlen(d->name) + + strlen(".temp") + 1]; + + sprintf(depname, "%s/%s", _dirname, d->name); + sprintf(tmpname, "%s/%s.temp", _dirname, d->name); + if (!doing_stdout) { + out = fopen(tmpname, "w"); + if (!out) + bb_error_msg_and_die("Could not open %s for writing: %s\n", + tmpname, strerror(errno)); + } else + out = stdout; + d->func(list, out); + if (!doing_stdout) { + fclose(out); + if (rename(tmpname, depname) < 0) + bb_error_msg_and_die("Could not rename %s into %s: %s\n", + tmpname, depname, strerror(errno)); + } + } + + return 0; +} Index: modutils/obj-2.6/moduleops.h =================================================================== --- modutils/obj-2.6/moduleops.h (revision 0) +++ modutils/obj-2.6/moduleops.h (revision 0) @@ -0,0 +1,27 @@ +#ifndef MODINITTOOLS_MODULEOPS_H +#define MODINITTOOLS_MODULEOPS_H +#include <stdio.h> + +/* All the icky stuff to do with manipulating 64 and 32-bit modules + belongs here. */ +struct kernel_symbol32 { + char value[4]; + char name[64 - 4]; +}; + +struct kernel_symbol64 { + char value[8]; + char name[64 - 8]; +}; + +struct module_ops +{ + void (*load_symbols)(struct module *module); + void (*calculate_deps)(struct module *module, int verbose); + char *(*get_aliases)(struct module *module, unsigned long *size); + char *(*get_modinfo)(struct module *module, unsigned long *size); +}; + +extern struct module_ops mod_ops32, mod_ops64; + +#endif /* MODINITTOOLS_MODULEOPS_H */ Index: modutils/obj-2.6/Makefile =================================================================== --- modutils/obj-2.6/Makefile (revision 0) +++ modutils/obj-2.6/Makefile (revision 0) @@ -0,0 +1,30 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +TOPDIR:= ../../ +MODUTILS_OBJ_2_6_DIR:=./ +include $(TOPDIR).config +include $(TOPDIR)Rules.mak +include Makefile.in +all: $(libraries-y) +-include $(TOPDIR).depend + +clean: + rm -f *.o *.a $(AR_TARGET) + Index: modutils/obj-2.6/zlibsupport.c =================================================================== --- modutils/obj-2.6/zlibsupport.c (revision 0) +++ modutils/obj-2.6/zlibsupport.c (revision 0) @@ -0,0 +1,40 @@ +/* Support for compressed modules. Willy Tarreau <willy@meta-x.org> + * did the support for modutils, Andrey Borzenkov <arvidjaar@mail.ru> + * ported it to module-init-tools, and I said it was too ugly to live + * and rewrote it 8). + * + * (C) 2003 Rusty Russell, IBM Corporation. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> + +#include "zlibsupport.h" + +void *grab_file(const char *filename, unsigned long *size) +{ + int fd; + struct stat st; + void *map; + + fd = open(filename, O_RDONLY, 0); + if (fd < 0) + return NULL; + + fstat(fd, &st); + *size = st.st_size; + map = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) + map = NULL; + + close(fd); + return map; +} + +void release_file(void *data, unsigned long size) +{ + munmap(data, size); +} Index: modutils/obj-2.6/depmod.h =================================================================== --- modutils/obj-2.6/depmod.h (revision 0) +++ modutils/obj-2.6/depmod.h (revision 0) @@ -0,0 +1,58 @@ +#ifndef MODINITTOOLS_DEPMOD_H +#define MODINITTOOLS_DEPMOD_H +#include "list.h" + +struct module; + +/* Functions provided by depmod.c */ +void fatal(const char *fmt, ...) __attribute__ ((noreturn, + format (printf, 1, 2))); +void warn(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void *do_nofail(void *ptr, const char *file, int line, const char *expr); +#define NOFAIL(ptr) do_nofail((ptr), __FILE__, __LINE__, #ptr) + +void add_symbol(const char *name, struct module *owner); +struct module *find_symbol(const char *name, const char *modname, int weak); +void add_dep(struct module *mod, struct module *depends_on); + +struct module +{ + /* Next module in list of all modules */ + struct module *next; + + /* 64 or 32 bit? */ + struct module_ops *ops; + + /* Dependencies: filled in by ops->calculate_deps() */ + unsigned int num_deps; + struct module **deps; + + /* Set while we are traversing dependencies */ + struct list_head dep_list; + + /* Tables extracted from module by ops->fetch_tables(). */ + /* FIXME: Do other tables too --RR */ + unsigned int pci_size; + void *pci_table; + unsigned int usb_size; + void *usb_table; + unsigned int ieee1394_size; + void *ieee1394_table; + unsigned int ccw_size; + void *ccw_table; + unsigned int pnp_size; + void *pnp_table; + unsigned int pnp_card_size; + unsigned int pnp_card_offset; + void *pnp_card_table; + unsigned int input_size; + void *input_table; + + /* File contents and length. */ + void *data; + unsigned long len; + + char pathname[0]; +}; + +#endif /* MODINITTOOLS_DEPMOD_H */ Index: Makefile =================================================================== --- Makefile (revision 290) +++ Makefile (working copy) @@ -28,7 +28,7 @@ include Rules.mak DIRS:=applets archival archival/libunarchive coreutils console-tools \ - debianutils editors findutils init miscutils modutils modutils/obj networking \ + debianutils editors findutils init miscutils modutils modutils/obj modutils/obj-2.6 networking \ networking/libiproute networking/udhcp procps loginutils shell \ sysklogd util-linux libpwdgrp coreutils/libcoreutils libbb
Attachment:
signature.asc
Description: Digital signature