[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

busybox insmod for linux 2.6



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


Reply to: