Hi folks The attached patch inplements 2.6 support in busybox insmod. Please test them. Bastian -- Without freedom of choice there is no creativity. -- Kirk, "The return of the Archons", stardate 3157.4
Index: debian/config-udeb-linux
===================================================================
--- debian/config-udeb-linux (revision 284)
+++ debian/config-udeb-linux (working copy)
@@ -367,7 +367,6 @@
#
# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
CONFIG_FEATURE_SH_STANDALONE_SHELL=y
-# CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN is not set
CONFIG_FEATURE_COMMAND_EDITING=y
CONFIG_FEATURE_COMMAND_HISTORY=15
# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set
Index: debian/config-udeb
===================================================================
--- debian/config-udeb (revision 284)
+++ debian/config-udeb (working copy)
@@ -359,7 +359,6 @@
#
# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
CONFIG_FEATURE_SH_STANDALONE_SHELL=y
-# CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN is not set
CONFIG_FEATURE_COMMAND_EDITING=y
CONFIG_FEATURE_COMMAND_HISTORY=15
# CONFIG_FEATURE_COMMAND_SAVEHISTORY is not set
Index: debian/config-static
===================================================================
--- debian/config-static (revision 284)
+++ debian/config-static (working copy)
@@ -442,7 +442,6 @@
#
# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
CONFIG_FEATURE_SH_STANDALONE_SHELL=y
-CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN=y
CONFIG_FEATURE_COMMAND_EDITING=y
CONFIG_FEATURE_COMMAND_HISTORY=15
CONFIG_FEATURE_COMMAND_SAVEHISTORY=y
Index: modutils/lsmod.c
===================================================================
--- modutils/lsmod.c (revision 284)
+++ 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/Config.in
===================================================================
--- modutils/Config.in (revision 284)
+++ modutils/Config.in (working copy)
@@ -39,14 +39,12 @@
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
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 +92,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 284)
+++ modutils/insmod.c (working copy)
@@ -86,6 +86,8 @@
#include "obj/obj.h"
#include "obj/kallsyms.h"
+#define STRVERSIONLEN 32
+
static int flag_force_load = 0;
static int flag_autoclean = 0;
static int flag_verbose = 0;
@@ -99,9 +101,43 @@
char *m_filename;
char *m_fullName;
+struct utsname uts_info;
+
/*======================================================================*/
+/* Only use the numeric part of the version string? */
+static void use_numeric_only(int major, int minor, char *str)
+{
+ if (((major << 8) + minor) >= 0x0205) /* kernel 2.5 */
+ *str = '\0';
+}
+
+/* Get the kernel version in the canonical integer form. */
+
+static int get_kernel_version(char str[STRVERSIONLEN])
+{
+ char *p, *q;
+ int a, b, c;
+
+ 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;
+ use_numeric_only(a, b, q);
+
+ return a << 16 | b << 8 | c;
+}
+
static int check_module_name_match(const char *filename, struct stat *statbuf,
void *userdata)
{
@@ -127,10 +163,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 +194,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 +257,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 +336,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 +459,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 usefull, as the previous case
- doesn't null 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 +556,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 +850,84 @@
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;
+ use_numeric_only(a, b, q);
+
+ 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 +1002,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 +1019,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 +1045,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 +1377,76 @@
#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;
+ int k_version;
+ char k_strversion[STRVERSIONLEN];
+ uname(&uts_info);
/* 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 +1457,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 +1484,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 +1512,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 +1523,107 @@
/* 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;
+ char k_strversion[STRVERSIONLEN];
+ int k_version = 0;
+#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
+ 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;
- }
- }
+ k_version = get_kernel_version(k_strversion);
+#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
+ m_version = get_module_version(f, m_strversion);
+ if (m_version == -1) {
+ error("couldn't find the kernel version the module was compiled for");
+ return EXIT_FAILURE;
}
-
- 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) {
+ lprintf("Warning: kernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s",
+ filename, m_strversion, k_strversion);
+ ++warnings;
+ } else {
+ if (!quiet)
+ error("kernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s.",
+ filename, 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 +1634,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 +1674,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 +1701,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 +1778,4 @@
return -1;
}
+
Attachment:
signature.asc
Description: Digital signature