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

Re: busybox insmod for linux 2.6



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


Reply to: