diff options
Diffstat (limited to 'mdk-stage1/insmod-modutils/insmod.c')
| -rw-r--r-- | mdk-stage1/insmod-modutils/insmod.c | 1964 | 
1 files changed, 0 insertions, 1964 deletions
| diff --git a/mdk-stage1/insmod-modutils/insmod.c b/mdk-stage1/insmod-modutils/insmod.c deleted file mode 100644 index 359b28837..000000000 --- a/mdk-stage1/insmod-modutils/insmod.c +++ /dev/null @@ -1,1964 +0,0 @@ -/* Insert a module into a running kernel. -   Copyright 1996, 1997 Linux International. - -   New implementation contributed by Richard Henderson <rth@tamu.edu> -   Based on original work by Bjorn Ekwall <bj0rn@blox.se> -   Restructured (and partly rewritten) by: -	Björn Ekwall <bj0rn@blox.se> February 1999 - -   This file is part of the Linux modutils. - -   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. -  */ - -  /* -     Fixes: - -     Adjust module size for mod_use_count in old_init_module: -     B. James Phillippe <bryan@terran.org> - -     Merged modprobe + many fixes: Björn Ekwall <bj0rn@blox.se> February 1999 -     SMP "friendliness" (and -P): Bill Zumach <zumach+@transarc.com> - -     Ksymoops support: Keith Owens <kaos@ocs.com.au> August 1999. - -     Add -r flag: Keith Owens <kaos@ocs.com.au> October 1999. - -     More flexible recognition of the way the utility was called. -     Suggested by Stepan Kasal, implemented in a different way by Keith -     Owens <kaos@ocs.com.au> December 1999. - -     Rationalize common code for 32/64 bit architectures. -       Keith Owens <kaos@ocs.com.au> December 1999. -     Add arch64(). -       Keith Owens <kaos@ocs.com.au> December 1999. -     kallsyms support -       Keith Owens <kaos@ocs.com.au> April 2000. -     archdata support -       Keith Owens <kaos@ocs.com.au> August 2000. -     Add insmod -O, move print map before sys_init_module. -       Keith Owens <kaos@ocs.com.au> October 2000. -     Add insmod -S. -       Keith Owens <kaos@ocs.com.au> November 2000. -     Add persistent data support. -       Keith Owens <kaos@ocs.com.au> November 2000. -   */ - -#ident "$Id$" - -#include "../insmod.h" -#include <sys/types.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -//#include <alloca.h>  provided by stdlib -#include <limits.h> -#include <ctype.h> -#include <errno.h> -#include <stddef.h> -#include <getopt.h> -#include <sys/stat.h> -#include <sys/file.h> - -#include "module.h" -#include "obj.h" -#include "kallsyms.h" -#include "util.h" -#include "version.h" - -#include "modstat.h" -#include "config.h" - -#define STRVERSIONLEN	32 - -/*======================================================================*/ - -static int flag_force_load = 0; -static int flag_silent_probe = 0; -static int flag_export = 1; -static int flag_load_map = 0; -static int flag_ksymoops = 1; - -static int n_ext_modules_used; -static int m_has_modinfo; - -extern int insmod_main(int argc, char **argv); -extern int insmod_main_32(int argc, char **argv); -extern int insmod_main_64(int argc, char **argv); -extern int modprobe_main(int argc, char **argv); -extern int rmmod_main(int argc, char **argv); -extern int ksyms_main(int argc, char **argv); -extern int lsmod_main(int argc, char **argv); -extern int kallsyms_main(int argc, char **argv); - -/*======================================================================*/ - -/* 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); -	p = uts_info.release; - -	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; -} - -/* String comparison for non-co-versioned kernel and module. - * prefix should be the same as used by genksyms for this kernel. - */ -static char *ncv_prefix = NULL;	/* Overridden by --prefix option */ -static int ncv_plen = 0; - -/* Only set prefix once. If set by the user, use it.  If not set by the - * user, look for a well known kernel symbol and derive the prefix from - * there.  Otherwise set the prefix depending on whether uts_info - * includes SMP or not for backwards compatibility. - */ -static void set_ncv_prefix(char *prefix) -{ -	static char derived_prefix[256]; -	static const char *well_known_symbol[] = { "get_module_symbol_R", -						   "inter_module_get_R", -						 }; -	struct module_symbol *s; -	int i, j, l, m, pl; -	const char *name; -	char *p; - -	if (ncv_prefix) -		return; - -	if (prefix) -		ncv_prefix = prefix; -	else { -		/* Extract the prefix (if any) from well known symbols */ -		for (i = 0, s = ksyms; i < nksyms; ++i, ++s) { -			name = (char *) s->name; -			l = strlen(name); -			for (j = 0; j < sizeof(well_known_symbol)/sizeof(well_known_symbol[0]); ++j) { -				m = strlen(well_known_symbol[j]); -				if (m + 8 > l || -				    strncmp(name, well_known_symbol[j], m)) -					continue; -				pl = l - m - 8; -				if (pl > sizeof(derived_prefix)-1) -					continue;	/* Prefix is wrong length */ -				/* Must end with 8 hex digits */ -				(void) strtoul(name+l-8, &p, 16); -				if (*p == 0) { -					strncpy(derived_prefix, name+m, pl); -					*(derived_prefix+pl) = '\0'; -					ncv_prefix = derived_prefix; -					break; -				} -			} -		} -	} -	if (!ncv_prefix) { -		p = strchr(uts_info.version, ' '); -		if (p && *(++p) && !strncmp(p, "SMP ", 4)) -			ncv_prefix = "smp_"; -		else -			ncv_prefix = ""; -	} -	ncv_plen = strlen(ncv_prefix); -	if (flag_verbose) -		lprintf("Symbol version prefix '%s'", ncv_prefix); -} - -static int ncv_strcmp(const char *a, const char *b) -{ -	size_t alen = strlen(a), blen = strlen(b); - -	if (blen == alen + 10 + ncv_plen && -	    b[alen] == '_' && -	    b[alen + 1] == 'R' && -	    !(ncv_plen && strncmp(b + alen + 2, ncv_prefix, ncv_plen))) { -		return strncmp(a, b, alen); -	} else if (alen == blen + 10 + ncv_plen && -		   a[blen] == '_' && a[blen + 1] == 'R' && -		   !(ncv_plen && strncmp(a + blen + 2, ncv_prefix, ncv_plen))) { -		return strncmp(a, b, blen); -	} else -		return strcmp(a, b); -} - -/* - * String hashing for non-co-versioned kernel and module. - * Here we are simply forced to drop the crc from the hash. - */ -static unsigned long ncv_symbol_hash(const char *str) -{ -	size_t len = strlen(str); - -	if (len > 10 + ncv_plen && -	    str[len - 10 - ncv_plen] == '_' && -	    str[len - 9 - ncv_plen] == 'R' && -	    !( -	      ncv_plen && -	      strncmp(str + len - (8 + ncv_plen), ncv_prefix, ncv_plen) -	     )) -		len -= 10 + ncv_plen; -	return obj_elf_hash_n(str, len); -} - -/* - * 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) -{ -	struct module_symbol *s; -	size_t i; -	int used = 0; - -	for (i = 0, s = syms; i < nsyms; ++i, ++s) { -		/* -		 * Only add symbols that are already marked external. -		 * If we override locals we may cause problems for -		 * argument initialization. -		 * We will also create a false dependency on the module. -		 */ -		struct obj_symbol *sym; - -		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), -					     idx, s->value, 0); -			/* -			 * Did our symbol just get installed? -			 * If so, mark the module as "used". -			 */ -			if (sym->secidx == idx) -				used = 1; -		} -	} - -	return used; -} - -static void add_kernel_symbols(struct obj_file *f) -{ -	struct module_stat *m; -	size_t i, nused = 0; - -	/* Add module symbols first.  */ -	for (i = 0, m = module_stat; i < n_module_stat; ++i, ++m) -		if (m->nsyms && -		    add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms)) -			m->status = 1 /* used */, ++nused; -	n_ext_modules_used = nused; - -	/* And finally the symbols from the kernel proper.  */ -	if (nksyms) -		add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); -} - -static void hide_special_symbols(struct obj_file *f) -{ -	struct obj_symbol *sym; -	const char *const *p; -	static const char *const specials[] = -	{ -		"cleanup_module", -		"init_module", -		"kernel_version", -		NULL -	}; - -	for (p = specials; *p; ++p) -		if ((sym = obj_find_symbol(f, *p)) != NULL) -			sym->info = ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); -} - -static void print_load_map(struct obj_file *f) -{ -	struct obj_symbol *sym; -	struct obj_symbol **all, **p; -	struct obj_section *sec; -	int load_map_cmp(const void *a, const void *b) { -		struct obj_symbol **as = (struct obj_symbol **) a; -		struct obj_symbol **bs = (struct obj_symbol **) b; -		unsigned long aa = obj_symbol_final_value(f, *as); -		unsigned long ba = obj_symbol_final_value(f, *bs); -		 return aa < ba ? -1 : aa > ba ? 1 : 0; -	} -	int i, nsyms, *loaded; - -	/* Report on the section layout.  */ - -	lprintf("Sections:       Size      %-*s  Align", -		(int) (2 * sizeof(void *)), "Address"); - -	for (sec = f->load_order; sec; sec = sec->load_next) { -		int a; -		unsigned long tmp; - -		for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a) -			tmp >>= 1; -		if (a == -1) -			a = 0; - -		lprintf("%-16s%08lx  %0*lx  2**%d", -			sec->name, -			(long)sec->header.sh_size, -			(int) (2 * sizeof(void *)), -			(long)sec->header.sh_addr, -			a); -	} - -	/* Quick reference which section indicies are loaded.  */ - -	loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); -	while (--i >= 0) -		loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; - -	/* Collect the symbols we'll be listing.  */ - -	for (nsyms = i = 0; i < HASH_BUCKETS; ++i) -		for (sym = f->symtab[i]; sym; sym = sym->next) -			if (sym->secidx <= SHN_HIRESERVE -			    && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])) -				++nsyms; - -	all = alloca(nsyms * sizeof(struct obj_symbol *)); - -	for (i = 0, p = all; i < HASH_BUCKETS; ++i) -		for (sym = f->symtab[i]; sym; sym = sym->next) -			if (sym->secidx <= SHN_HIRESERVE -			    && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])) -				*p++ = sym; - -	/* Sort them by final value.  */ -	qsort(all, nsyms, sizeof(struct obj_file *), load_map_cmp); - -	/* And list them.  */ -	lprintf("\nSymbols:"); -	for (p = all; p < all + nsyms; ++p) { -		char type = '?'; -		unsigned long value; - -		sym = *p; -		if (sym->secidx == SHN_ABS) { -			type = 'A'; -			value = sym->value; -		} else if (sym->secidx == SHN_UNDEF) { -			type = 'U'; -			value = 0; -		} else { -			struct obj_section *sec = f->sections[sym->secidx]; - -			if (sec->header.sh_type == SHT_NOBITS) -				type = 'B'; -			else if (sec->header.sh_flags & SHF_ALLOC) { -				if (sec->header.sh_flags & SHF_EXECINSTR) -					type = 'T'; -				else if (sec->header.sh_flags & SHF_WRITE) -					type = 'D'; -				else -					type = 'R'; -			} -			value = sym->value + sec->header.sh_addr; -		} - -		if (ELFW(ST_BIND) (sym->info) == STB_LOCAL) -			type = tolower(type); - -		lprintf("%0*lx %c %s", (int) (2 * sizeof(void *)), value, -			type, sym->name); -	} -} - -/************************************************************************/ -/* begin compat */ - -static char * get_modinfo_value(struct obj_file *f, const char *key) -{ -	struct obj_section *sec; -	char *p, *v, *n, *ep; -	size_t klen = strlen(key); - -	sec = obj_find_section(f, ".modinfo"); -	if (sec == NULL) -		return NULL; - -	p = sec->contents; -	ep = p + sec->header.sh_size; -	while (p < ep) { -		v = strchr(p, '='); -		n = strchr(p, '\0'); -		if (v) { -			if (v - p == klen && strncmp(p, key, klen) == 0) -				return v + 1; -		} else { -			if (n - p == klen && strcmp(p, key) == 0) -				return n; -		} -		p = n + 1; -	} - -	return NULL; -} - -static int create_this_module(struct obj_file *f, const char *m_name) -{ -	struct obj_section *sec; - -	sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, -					       sizeof(struct module)); -	memset(sec->contents, 0, sizeof(struct module)); - -	obj_add_symbol(f, "__this_module", -1, ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), -		       sec->idx, 0, sizeof(struct module)); - -	obj_string_patch(f, sec->idx, offsetof(struct module, name), m_name); - -	return 1; -} - -#ifdef COMPAT_2_0 -static int old_create_mod_use_count(struct obj_file *f) -{ -	struct obj_section *sec; -	struct obj_symbol  *got; - -	sec = obj_create_alloced_section_first(f, ".moduse", -					       sizeof(long), sizeof(long)); - -	obj_add_symbol(f, "mod_use_count_", -		       -1, ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), -		       sec->idx, 0, sizeof(long)); - -	/* -	 * patb: if there is a _GLOBAL_OFFSET_TABLE_, -	 * add .got section for PIC type modules; -	 * we have to do this here, because obj_* calls are not made until -	 * after obj_check_undefined -	 * is there a better place for this exception? -	 */ -	got = obj_find_symbol(f, "_GLOBAL_OFFSET_TABLE_"); -	if (got) -{ -		sec = obj_create_alloced_section(f, ".got", -						 sizeof(long), sizeof(long)); -		got->secidx = sec->idx; /* mark the symbol as defined */ -	} -	return 1; -} -#endif - -/* add an entry to the __ksymtab section, creating it if necessary */ -static void add_ksymtab(struct obj_file *f, struct obj_symbol *sym) -{ -	struct obj_section *sec; -	ElfW(Addr) ofs; - -	/* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section. -	 * If __ksymtab is defined but not marked alloc, x out the first character -	 * (no obj_delete routine) and create a new __ksymtab with the correct -	 * characteristics. -	 */ -	sec = obj_find_section(f, "__ksymtab"); -	if (sec && !(sec->header.sh_flags & SHF_ALLOC)) { -		*((char *)(sec->name)) = 'x';	/* override const */ -		sec = NULL; -	} -	if (!sec) -		sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); -	if (!sec) -		return; -	sec->header.sh_flags |= SHF_ALLOC; - -	ofs = sec->header.sh_size; -	obj_symbol_patch(f, sec->idx, ofs, sym); -	obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name); -	obj_extend_section(sec, 2 * tgt_sizeof_char_p); -} - -static int create_module_ksymtab(struct obj_file *f) -{ -	struct obj_section *sec; -	int i; - -	/* We must always add the module references.  */ - -	if (n_ext_modules_used) { -		struct module_ref *dep; -		struct obj_symbol *tm; - -		sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, -					   (sizeof(struct module_ref) -					    * n_ext_modules_used)); -		if (!sec) -			return 0; - -		tm = obj_find_symbol(f, "__this_module"); -		dep = (struct module_ref *) sec->contents; -		for (i = 0; i < n_module_stat; ++i) -			if (module_stat[i].status /* used */) { -				dep->dep = module_stat[i].addr; -				obj_symbol_patch(f, sec->idx, (char *) &dep->ref - sec->contents, tm); -				dep->next_ref = 0; -				++dep; -			} -	} -	if (flag_export && !obj_find_section(f, "__ksymtab")) { -		int *loaded; - -		/* We don't want to export symbols residing in sections that -		   aren't loaded.  There are a number of these created so that -		   we make sure certain module options don't appear twice.  */ - -		loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); -		while (--i >= 0) -			loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; - -		for (i = 0; i < HASH_BUCKETS; ++i) { -			struct obj_symbol *sym; -			for (sym = f->symtab[i]; sym; sym = sym->next) { -				if (ELFW(ST_BIND) (sym->info) != STB_LOCAL -				    && sym->secidx <= SHN_HIRESERVE -				    && (sym->secidx >= SHN_LORESERVE -					|| loaded[sym->secidx])) { -					add_ksymtab(f, sym); -				} -			} -		} -	} -	return 1; -} - -/* 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); - -	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; -} - -/* 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; -} - -/* 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 void add_ksymoops_symbols(struct obj_file *f, const char *filename, -				 const char *m_name) -{ -	struct obj_section *sec; -	struct obj_symbol *sym; -	char *name, *absolute_filename; -	char str[STRVERSIONLEN], real[PATH_MAX]; -	int i, l, lm_name, lfilename, use_ksymtab, version; -	struct stat statbuf; - -	static const char *section_names[] = { -		".text", -		".rodata", -		".data", -		".bss" -	}; - -	if (realpath(filename, real)) { -		absolute_filename = xstrdup(real); -	} -	else { -		int save_errno = errno; -		error("cannot get realpath for %s", filename); -		errno = save_errno; -		absolute_filename = xstrdup(filename); -	} - -	lm_name = strlen(m_name); -	lfilename = strlen(absolute_filename); - -	/* add to ksymtab if it already exists or there is no ksymtab and other symbols -	 * are not to be exported.  otherwise leave ksymtab alone for now, the -	 * "export all symbols" compatibility code will export these symbols later. -	 */ - -	use_ksymtab =  obj_find_section(f, "__ksymtab") || !flag_export; - -	if ((sec = obj_find_section(f, ".this"))) { -		/* tag the module header with the object name, last modified -		 * timestamp and module version.  worst case for module version -		 * is 0xffffff, decimal 16777215.  putting all three fields in -		 * one symbol is less readable but saves kernel space. -		 */ -		l = sizeof(symprefix)+			/* "__insmod_" */ -		    lm_name+				/* module name */ -		    2+					/* "_O" */ -		    lfilename+				/* object filename */ -		    2+					/* "_M" */ -		    2*sizeof(statbuf.st_mtime)+		/* mtime in hex */ -		    2+					/* "_V" */ -		    8+					/* version in dec */ -		    1;					/* nul */ -		name = xmalloc(l); -		if (stat(absolute_filename, &statbuf) != 0) -			statbuf.st_mtime = 0; -		version = get_module_version(f, str);	/* -1 if not found */ -		snprintf(name, l, "%s%s_O%s_M%0*lX_V%d", -			 symprefix, m_name, absolute_filename, -			 2*sizeof(statbuf.st_mtime), statbuf.st_mtime, -			 version); -		sym = obj_add_symbol(f, name, -1, -				     ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), -				     sec->idx, sec->header.sh_addr, 0); -		if (use_ksymtab) -			add_ksymtab(f, sym); -	} -	free(absolute_filename); - -	/* record where the persistent data is going, same address as previous symbol */ - -	if (f->persist) { -		l = sizeof(symprefix)+		/* "__insmod_" */ -			lm_name+		/* module name */ -			2+			/* "_P" */ -			strlen(f->persist)+	/* data store */ -			1;			/* nul */ -		name = xmalloc(l); -		snprintf(name, l, "%s%s_P%s", -			 symprefix, m_name, f->persist); -		sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), -				     sec->idx, sec->header.sh_addr, 0); -		if (use_ksymtab) -			add_ksymtab(f, sym); -	} - -	/* tag the desired sections if size is non-zero */ - -	for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) { -		if ((sec = obj_find_section(f, section_names[i])) && -		    sec->header.sh_size) { -			l = sizeof(symprefix)+		/* "__insmod_" */ -				lm_name+		/* module name */ -				2+			/* "_S" */ -				strlen(sec->name)+	/* section name */ -				2+			/* "_L" */ -				8+			/* length in dec */ -				1;			/* nul */ -			name = xmalloc(l); -			snprintf(name, l, "%s%s_S%s_L%ld", -				 symprefix, m_name, sec->name, -				 (long)sec->header.sh_size); -			sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), -					     sec->idx, sec->header.sh_addr, 0); -			if (use_ksymtab) -				add_ksymtab(f, sym); -		} -	} -} - -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) { -					error("invalid parameter %s", key); -					return 0; -				} -				else { -					if (flag_verbose) -						lprintf("ignoring %s", *argv); -					continue;	/* silently ignore optional parameters */ -				} -			} -			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) { -			error("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') { -							error("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))) { -						error("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) { -						error("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: -				error("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)) { -					error("too many values for %s (max %d)", key, max); -					return 0; -				} -				++input; -				/* continue with while (*input) */ -			} else { -				error("invalid argument syntax for %s: '%c'", -				      key, *input); -				return 0; -			} -		} /* end of while (*input) */ - -		if (min && (n < min)) { -			error("too few values for %s (min %d)", key, min); -			return 0; -		} -	} /* end of for (;argc > 0;) */ - -	return 1; -} - - -/* Add a kallsyms section if the kernel supports all symbols. */ -static int add_kallsyms(struct obj_file *f, -			struct obj_section **module_kallsyms, int force_kallsyms) -{ -	struct module_symbol *s; -	struct obj_file *f_kallsyms; -	struct obj_section *sec_kallsyms; -	size_t i; -	int l; -	const char *p, *pt_R; -	unsigned long start = 0, stop = 0; - -	for (i = 0, s = ksyms; i < nksyms; ++i, ++s) { -		p = (char *)s->name; -		pt_R = strstr(p, "_R"); -		if (pt_R) -			l = pt_R - p; -		else -			l = strlen(p); -		if (strncmp(p, "__start_" KALLSYMS_SEC_NAME, l) == 0) -			start = s->value; -		else if (strncmp(p, "__stop_" KALLSYMS_SEC_NAME, l) == 0) -			stop = s->value; -	} - -	if (start >= stop && !force_kallsyms) -		return(0); - -	/* The kernel contains all symbols, do the same for this module. */ - -	/* Add an empty kallsyms section to the module if necessary */ -	for (i = 0; i < f->header.e_shnum; ++i) { -		if (strcmp(f->sections[i]->name, KALLSYMS_SEC_NAME) == 0) { -			*module_kallsyms = f->sections[i]; -			break; -		} -	    } -	if (!*module_kallsyms) -		*module_kallsyms = obj_create_alloced_section(f, KALLSYMS_SEC_NAME, 0, 0); - -	/* Size and populate kallsyms */ -	if (obj_kallsyms(f, &f_kallsyms)) -		return(1); -	sec_kallsyms = f_kallsyms->sections[KALLSYMS_IDX]; -	(*module_kallsyms)->header.sh_addralign = sec_kallsyms->header.sh_addralign; -	(*module_kallsyms)->header.sh_size = sec_kallsyms->header.sh_size; -	free((*module_kallsyms)->contents); -	(*module_kallsyms)->contents = sec_kallsyms->contents; -	sec_kallsyms->contents = NULL; -	obj_free(f_kallsyms); - -	return 0; -} - - -/* Add an arch data section if the arch wants it. */ -static int add_archdata(struct obj_file *f, -			struct obj_section **sec) -{ -	size_t i; - -	*sec = NULL; -	/* Add an empty archdata section to the module if necessary */ -	for (i = 0; i < f->header.e_shnum; ++i) { -		if (strcmp(f->sections[i]->name, ARCHDATA_SEC_NAME) == 0) { -			*sec = f->sections[i]; -			break; -		} -	    } -	if (!*sec) -		*sec = obj_create_alloced_section(f, ARCHDATA_SEC_NAME, 16, 0); - -	/* Size and populate archdata */ -	if (arch_archdata(f, *sec)) -		return(1); -	return 0; -} - - -static int init_module(const char *m_name, struct obj_file *f, -		       unsigned long m_size, const char *blob_name, -		       unsigned int noload, unsigned int flag_load_map) -{ -	struct module *module; -	struct obj_section *sec; -	void *image; -	int ret = 0; -	tgt_long m_addr; - -	sec = obj_find_section(f, ".this"); -	module = (struct module *) sec->contents; -	m_addr = sec->header.sh_addr; - -	module->size_of_struct = sizeof(*module); -	module->size = m_size; -	module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; - -	sec = obj_find_section(f, "__ksymtab"); -	if (sec && sec->header.sh_size) { -		module->syms = sec->header.sh_addr; -		module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); -	} -	if (n_ext_modules_used) { -		sec = obj_find_section(f, ".kmodtab"); -		module->deps = sec->header.sh_addr; -		module->ndeps = n_ext_modules_used; -	} -	module->init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); -	module->cleanup = obj_symbol_final_value(f, -		obj_find_symbol(f, "cleanup_module")); - -	sec = obj_find_section(f, "__ex_table"); -	if (sec) { -		module->ex_table_start = sec->header.sh_addr; -		module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; -	} -	sec = obj_find_section(f, ".text.init"); -	if (sec) { -		module->runsize = sec->header.sh_addr - m_addr; -	} -	sec = obj_find_section(f, ".data.init"); -	if (sec) { -		if (!module->runsize || -		    module->runsize > sec->header.sh_addr - m_addr) -			module->runsize = sec->header.sh_addr - m_addr; -	} -	sec = obj_find_section(f, ARCHDATA_SEC_NAME); -	if (sec && sec->header.sh_size) { -		module->archdata_start = sec->header.sh_addr; -		module->archdata_end = module->archdata_start + sec->header.sh_size; -	} -	sec = obj_find_section(f, KALLSYMS_SEC_NAME); -	if (sec && sec->header.sh_size) { -		module->kallsyms_start = sec->header.sh_addr; -		module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; -	} -	if (!arch_init_module(f, module)) -		return 0; - -	/* -	 * Whew!  All of the initialization is complete. -	 * Collect the final module image and give it to the kernel. -	 */ -	image = xmalloc(m_size); -	obj_create_image(f, image); - -	if (flag_load_map) -		print_load_map(f); - -	if (blob_name) { -		int fd, l; -		fd = open(blob_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); -		if (fd < 0) { -			error("open %s failed %m", blob_name); -			ret = -1; -		} -		else { -			if ((l = write(fd, image, m_size)) != m_size) { -				error("write %s failed %m", blob_name); -				ret = -1; -			} -			close(fd); -		} -	} - -	if (ret == 0 && !noload) { -		fflush(stdout);		/* Flush any debugging output */ -		ret = sys_init_module(m_name, (struct module *) image); -		if (ret) { -			error("init_module: %m"); -			lprintf("Hint: insmod errors can be caused by incorrect module parameters, " -				"including invalid IO or IRQ parameters"); -		} -	} - -	free(image); - -	return ret == 0; -} - -#ifdef COMPAT_2_0 -static int old_init_module(const char *m_name, struct obj_file *f, -			   unsigned long m_size) -{ -	char *image; -	struct old_mod_routines routines; -	struct old_symbol_table *symtab; -	int ret; -	int nsyms = 0, strsize = 0, total; - -	/* Create the symbol table */ -	/* Size things first... */ -	if (flag_export) { -		int i; -		for (i = 0; i < HASH_BUCKETS; ++i) { -			struct obj_symbol *sym; - -			for (sym = f->symtab[i]; sym; sym = sym->next) -				if (ELFW(ST_BIND) (sym->info) != STB_LOCAL && -				    sym->secidx <= SHN_HIRESERVE) { -					sym->ksymidx = nsyms++; -					strsize += strlen(sym->name) + 1; -				} -		} -	} -	total = (sizeof(struct old_symbol_table) + -		 nsyms * sizeof(struct old_module_symbol) + -		 n_ext_modules_used * sizeof(struct old_module_ref) + -		 strsize); -	symtab = xmalloc(total); -	symtab->size = total; -	symtab->n_symbols = nsyms; -	symtab->n_refs = n_ext_modules_used; - -	if (flag_export && nsyms) { -		struct old_module_symbol *ksym; -		char *str; -		int i; - -		ksym = symtab->symbol; -		str = ((char *) ksym + -		       nsyms * sizeof(struct old_module_symbol) + -		       n_ext_modules_used * sizeof(struct old_module_ref)); - -		for (i = 0; i < HASH_BUCKETS; ++i) { -			struct obj_symbol *sym; -			for (sym = f->symtab[i]; sym; sym = sym->next) -				if (sym->ksymidx >= 0) { -					ksym->addr = obj_symbol_final_value(f, sym); -					ksym->name = (unsigned long) str - (unsigned long) symtab; - -					str = stpcpy(str, sym->name) + 1; -					ksym++; -				} -		} -	} - -	if (n_ext_modules_used) { -		struct old_module_ref *ref; -		int i; - -		ref = (struct old_module_ref *) -		    ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol)); - -		for (i = 0; i < n_module_stat; ++i) { -			if (module_stat[i].status /* used */) { -				ref++->module = module_stat[i].modstruct; -			} -		} -	} - -	/* Fill in routines.  */ - -	routines.init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); -	routines.cleanup = obj_symbol_final_value(f, -		obj_find_symbol(f, "cleanup_module")); - -	/* -	 * Whew!  All of the initialization is complete. -	 * Collect the final module image and give it to the kernel. -	 */ -	image = xmalloc(m_size); -	obj_create_image(f, image); - -	/* -	 * image holds the complete relocated module, -	 * accounting correctly for mod_use_count. -	 * However the old module kernel support assume that it -	 * is receiving something which does not contain mod_use_count. -	 */ -	ret = old_sys_init_module(m_name, image + sizeof(long), -				  (m_size - sizeof(long)) | -				  (flag_autoclean ? OLD_MOD_AUTOCLEAN : 0), -				  &routines, -				  symtab); -	if (ret) -		error("init_module: %m"); - -	free(image); -	free(symtab); - -	return ret == 0; -} -#endif -/* end compat */ -/************************************************************************/ - -/* Check that a module parameter has a reasonable definition */ -static int check_module_parameter(struct obj_file *f, char *key, char *value, int *persist_flag) -{ -	struct obj_symbol *sym; -	int min, max; -	char *p = value; - -	sym = obj_find_symbol(f, key); -	if (sym == NULL) { -		/* FIXME: For 2.2 kernel compatibility, only issue warnings for -		 *        most error conditions.  Make these all errors in 2.5. -		 */ -		lprintf("Warning: %s symbol for parameter %s not found", error_file, key); -		return(1); -	} - -	if (isdigit(*p)) { -		min = strtoul(p, &p, 10); -		if (*p == '-') -			max = strtoul(p + 1, &p, 10); -		else -			max = min; -	} else -		min = max = 1; - -	if (max < min) { -		lprintf("Warning: %s parameter %s has max < min!", error_file, key); -		return(1); -	} - -	switch (*p) { -	case 'c': -		if (!isdigit(p[1])) { -			lprintf("%s parameter %s has no size after 'c'!", error_file, key); -			return(1); -		} -		while (isdigit(p[1])) -			++p;	/* swallow c array size */ -		break; -	case 'b':	/* drop through */ -	case 'h':	/* drop through */ -	case 'i':	/* drop through */ -	case 'l':	/* drop through */ -	case 's': -		break; -	case '\0': -		lprintf("%s parameter %s has no format character!", error_file, key); -		return(1); -	default: -		lprintf("%s parameter %s has unknown format character '%c'", error_file, key, *p); -		return(1); -	} -	switch (*++p) { -	case 'p': -		if (*(p-1) == 's') { -			error("parameter %s is invalid persistent string", key); -			return(1); -		} -		*persist_flag = 1; -		break; -	case '\0': -		break; -	default: -		lprintf("%s parameter %s has unknown format modifier '%c'", error_file, key, *p); -		return(1); -	} -	return(0); -} - -/* Check that all module parameters have reasonable definitions */ -static void check_module_parameters(struct obj_file *f, int *persist_flag) -{ -	struct obj_section *sec; -	char *ptr, *value, *n, *endptr; -	int namelen, err = 0; - -	sec = obj_find_section(f, ".modinfo"); -	if (sec == NULL) { -		/* module does not support typed parameters */ -		return; -	} - -	ptr = sec->contents; -	endptr = ptr + sec->header.sh_size; -	while (ptr < endptr && !err) { -		value = strchr(ptr, '='); -		n = strchr(ptr, '\0'); -		if (value) { -			namelen = value - ptr; -			if (namelen >= 5 && strncmp(ptr, "parm_", 5) == 0 -			    && !(namelen > 10 && strncmp(ptr, "parm_desc_", 10) == 0)) { -				char *pname = xmalloc(namelen + 1); -				strncpy(pname, ptr + 5, namelen - 5); -				pname[namelen - 5] = '\0'; -				err = check_module_parameter(f, pname, value+1, persist_flag); -				free(pname); -			} -		} else { -			if (n - ptr >= 5 && strncmp(ptr, "parm_", 5) == 0) { -				error("parameter %s found with no value", ptr); -				err = 1; -			} -		} -		ptr = n + 1; -	} - -	if (err) -		*persist_flag = 0; -	return; -} - - -/* For common 3264 code, only compile the usage message once, in the 64 bit version */ -#if defined(COMMON_3264) && defined(ONLY_32) -extern void insmod_usage(void);		/* Use the copy in the 64 bit version */ -#else	/* Common 64 bit version or any non common code - compile usage routine */ -void insmod_usage(void) -{ -	fputs("Usage:\n" -	      "insmod [-fhkLmnpqrsSvVxXyY] [-e persist_name] [-o module_name] [-O blob_name] [-P prefix] module [ symbol=value ... ]\n" -	      "\n" -	      "  module                Name of a loadable kernel module ('.o' can be omitted)\n" -	      "  -f, --force           Force loading under wrong kernel version\n" -	      "  -h, --help            Print this message\n" -	      "  -k, --autoclean       Make module autoclean-able\n" -	      "  -L, --lock            Prevent simultaneous loads of the same module\n" -	      "  -m, --map             Generate load map (so crashes can be traced)\n" -	      "  -n, --noload          Don't load, just show\n" -	      "  -p, --probe           Probe mode; check if the module matches the kernel\n" -	      "  -q, --quiet           Don't print unresolved symbols\n" -	      "  -r, --root            Allow root to load modules not owned by root\n" -	      "  -s, --syslog          Report errors via syslog\n" -	      "  -S, --kallsyms        Force kallsyms on module\n" -	      "  -v, --verbose         Verbose output\n" -	      "  -V, --version         Show version\n" -	      "  -x, --noexport        Do not export externs\n" -	      "  -X, --export          Do export externs (default)\n" -	      "  -y, --noksymoops      Do not add ksymoops symbols\n" -	      "  -Y, --ksymoops        Do add ksymoops symbols (default)\n" -	      "  -e persist_name\n" -	      "      --persist=persist_name Filename to hold any persistent data from the module\n" -	      "  -o NAME, --name=NAME  Set internal module name to NAME\n" -	      "  -O NAME, --blob=NAME  Save the object as a binary blob in NAME\n" -	      "  -P PREFIX\n" -	      "      --prefix=PREFIX   Prefix for kernel or module symbols\n" -	      ,stderr); -	exit(1); -} -#endif	/* defined(COMMON_3264) && defined(ONLY_32) */ - -#if defined(COMMON_3264) && defined(ONLY_32) -#define INSMOD_MAIN insmod_main_32	/* 32 bit version */ -#elif defined(COMMON_3264) && defined(ONLY_64) -#define INSMOD_MAIN insmod_main_64	/* 64 bit version */ -#else -#define INSMOD_MAIN insmod_main		/* Not common code */ -#endif - -int INSMOD_MAIN(int argc, char **argv) -{ -	int k_version; -	int k_crcs; -	char k_strversion[STRVERSIONLEN]; -	struct option long_opts[] = { -		{"force", 0, 0, 'f'}, -		{"help", 0, 0, 'h'}, -		{"autoclean", 0, 0, 'k'}, -		{"lock", 0, 0, 'L'}, -		{"map", 0, 0, 'm'}, -		{"noload", 0, 0, 'n'}, -		{"probe", 0, 0, 'p'}, -		{"poll", 0, 0, 'p'},	/* poll is deprecated, remove in 2.5 */ -		{"quiet", 0, 0, 'q'}, -		{"root", 0, 0, 'r'}, -		{"syslog", 0, 0, 's'}, -		{"kallsyms", 0, 0, 'S'}, -		{"verbose", 0, 0, 'v'}, -		{"version", 0, 0, 'V'}, -		{"noexport", 0, 0, 'x'}, -		{"export", 0, 0, 'X'}, -		{"noksymoops", 0, 0, 'y'}, -		{"ksymoops", 0, 0, 'Y'}, - -		{"persist", 1, 0, 'e'}, -		{"name", 1, 0, 'o'}, -		{"blob", 1, 0, 'O'}, -		{"prefix", 1, 0, 'P'}, -		{0, 0, 0, 0} -	}; -	char *m_name = NULL; -	char *blob_name = NULL;		/* Save object as binary blob */ -	int m_version; -	ElfW(Addr) m_addr; -	unsigned long m_size; -	int m_crcs; -	char m_strversion[STRVERSIONLEN]; -	char *filename; -	char *persist_name = NULL;	/* filename to hold any persistent data */ -	int fp; -	struct obj_file *f; -	struct obj_section *kallsyms = NULL, *archdata = NULL; -	int o; -	int noload = 0; -	int dolock = 1; /*Note: was: 0; */ -	int quiet = 0; -	int exit_status = 1; -	int force_kallsyms = 0; -	int persist_parms = 0;	/* does module have persistent parms? */ -	int i; - -	error_file = "insmod"; - -	/* To handle repeated calls from combined modprobe */ -	errors = optind = 0; - -	/* Process the command line.  */ -	while ((o = getopt_long(argc, argv, "fhkLmnpqrsSvVxXyYe:o:O:P:R:", -				&long_opts[0], NULL)) != EOF) -		switch (o) { -		case 'f':	/* force loading */ -			flag_force_load = 1; -			break; -		case 'h':       /* Print the usage message. */ -			insmod_usage(); -			break; -		case 'k':	/* module loaded by kerneld, auto-cleanable */ -			flag_autoclean = 1; -			break; -		case 'L':	/* protect against recursion.  */ -			dolock = 1; -			break; -		case 'm':	/* generate load map */ -			flag_load_map = 1; -			break; -		case 'n':	/* don't load, just check */ -			noload = 1; -			break; -		case 'p':	/* silent probe mode */ -			flag_silent_probe = 1; -			break; -		case 'q':	/* Don't print unresolved symbols */ -			quiet = 1; -			break; -		case 'r':	/* allow root to load non-root modules */ -			root_check_off = !root_check_off; -			break; -		case 's':	/* start syslog */ -			setsyslog("insmod"); -			break; -		case 'S':	/* Force kallsyms */ -			force_kallsyms = 1; -			break; -		case 'v':	/* verbose output */ -			flag_verbose = 1; -			break; -		case 'V': -			fputs("insmod version " MODUTILS_VERSION "\n", stderr); -			break; -		case 'x':	/* do not export externs */ -			flag_export = 0; -			break; -		case 'X':	/* do export externs */ -			flag_export = 1; -			break; -		case 'y':	/* do not define ksymoops symbols */ -			flag_ksymoops = 0; -			break; -		case 'Y':	/* do define ksymoops symbols */ -			flag_ksymoops = 1; -			break; - -		case 'e':	/* persistent data filename */ -			free(persist_name); -			persist_name = xstrdup(optarg); -			break; -		case 'o':	/* name the output module */ -			m_name = optarg; -			break; -		case 'O':	/* save the output module object */ -			blob_name = optarg; -			break; -		case 'P':	/* use prefix on crc */ -			set_ncv_prefix(optarg); -			break; - -		default: -			insmod_usage(); -			break; -		} - -	if (optind >= argc) { -		insmod_usage(); -	} -	filename = argv[optind++]; - -	if (config_read(0, NULL, "", NULL) < 0) { -		error("Failed handle configuration"); -	} - -	if (persist_name && !*persist_name && -	    (!persistdir || !*persistdir)) { -		free(persist_name); -		persist_name = NULL; -		if (flag_verbose) -			lprintf("insmod: -e \"\" ignored, no persistdir"); -	} - -	if (m_name == NULL) { -		size_t len; -		char *p; - -		if ((p = strrchr(filename, '/')) != NULL) -			p++; -		else -			p = filename; -		len = strlen(p); -		if (len > 2 && p[len - 2] == '.' && p[len - 1] == 'o') -			len -= 2; -		else if (len > 4 && p[len - 4] == '.' && p[len - 3] == 'm' -			 && p[len - 2] == 'o' && p[len - 1] == 'd') -			len -= 4; -#ifdef CONFIG_USE_ZLIB -		else if (len > 5 && !strcmp(p + len - 5, ".o.gz")) -			len -= 5; -#endif - -		m_name = xmalloc(len + 1); -		memcpy(m_name, p, len); -		m_name[len] = '\0'; -	} - -	/* Locate the file to be loaded.  */ -	if (!strchr(filename, '/') && !strchr(filename, '.')) { -		char *tmp = search_module_path(filename); -		if (tmp == NULL) { -			error("%s: no module by that name found", filename); -			return 1; -		} -		filename = tmp; -		lprintf("Using %s", filename); -	} else if (flag_verbose) -		lprintf("Using %s", filename); - -	/* And open it.  */ -	if ((fp = gzf_open(filename, O_RDONLY)) == -1) { -		error("%s: %m", filename); -		return 1; -	} -	/* Try to prevent multiple simultaneous loads.  */ -	if (dolock) -		flock(fp, LOCK_EX); - -	if (!get_kernel_info(K_SYMBOLS)) -		goto out; - -	/* -	 * Set the genksyms prefix if this is a versioned kernel -	 * and it's not already set. -	 */ -	set_ncv_prefix(NULL); - -	for (i = 0; i < n_module_stat; ++i) { -		if (strcmp(module_stat[i].name, m_name) == 0) { -			error("a module named %s already exists", m_name); -			goto out; -		} -	} - -	error_file = filename; -	if ((f = obj_load(fp, ET_REL, filename)) == NULL) -		goto out; - -	/* Version correspondence?  */ -	k_version = get_kernel_version(k_strversion); -	m_version = get_module_version(f, m_strversion); -	if (m_version == -1) { -		error("couldn't find the kernel version the module was compiled for"); -		goto out; -	} - -	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); -		} 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); -			goto out; -		} -	} -	if (m_crcs != k_crcs) -		obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); - -	/* Let the module know about the kernel symbols.  */ -	add_kernel_symbols(f); - -	/* Allocate common symbols, symbol tables, and string tables. -	 * -	 * The calls marked DEPMOD indicate the bits of code that depmod -	 * uses to do a pseudo relocation, ignoring undefined symbols. -	 * Any changes made to the relocation sequence here should be -	 * checked against depmod. -	 */ -#ifdef COMPAT_2_0 -	if (k_new_syscalls -	    ? !create_this_module(f, m_name) -	    : !old_create_mod_use_count(f)) -		goto out; -#else -	if (!create_this_module(f, m_name)) -		goto out; -#endif - -	if (!obj_check_undefineds(f, quiet))	/* DEPMOD, obj_clear_undefineds */ -		goto out; -	obj_allocate_commons(f);	/* DEPMOD */ - -	check_module_parameters(f, &persist_parms); - -	if (optind < argc) { -		if (!process_module_arguments(f, argc - optind, argv + optind, 1)) -			goto out; -	} -	arch_create_got(f);	/* DEPMOD */ -	hide_special_symbols(f); - -	if (persist_parms && persist_name && *persist_name) { -		f->persist = persist_name; -		persist_name = NULL; -	} - -	if (persist_parms && -	    persist_name && !*persist_name) { -		/* -e "".  This is ugly.  Take the filename, compare it against -		 * each of the module paths until we find a match on the start -		 * of the filename, assume the rest is the relative path.  Have -		 * to do it this way because modprobe uses absolute filenames -		 * for module names in modules.dep and the format of modules.dep -		 * does not allow for any backwards compatible changes, so there -		 * is nowhere to store the relative filename.  The only way this -		 * should fail to calculate a relative path is "insmod ./xxx", for -		 * that case the user has to specify -e filename. -		 */ -		int j, l = strlen(filename); -		char *relative = NULL; -		char *p; -		for (i = 0; i < nmodpath; ++i) { -			p = modpath[i].path; -			j = strlen(p); -			while (j && p[j] == '/') -				--j; -			if (j < l && strncmp(filename, p, j) == 0 && filename[j] == '/') { -				while (filename[j] == '/') -					++j; -				relative = xstrdup(filename+j); -				break; -			} -		} -		if (relative) { -			i = strlen(relative); -			if (i > 3 && strcmp(relative+i-3, ".gz") == 0) -				relative[i -= 3] = '\0'; -			if (i > 2 && strcmp(relative+i-2, ".o") == 0) -				relative[i -= 2] = '\0'; -			else if (i > 4 && strcmp(relative+i-4, ".mod") == 0) -				relative[i -= 4] = '\0'; -			f->persist = xmalloc(strlen(persistdir) + 1 + i + 1); -			strcpy(f->persist, persistdir);	/* safe, xmalloc */ -			strcat(f->persist, "/");	/* safe, xmalloc */ -			strcat(f->persist, relative);	/* safe, xmalloc */ -			free(relative); -		} -		else -			error("Cannot calculate persistent filename"); -	} - -	if (f->persist && *(f->persist) != '/') { -		error("Persistent filenames must be absolute, ignoring '%s'", -			f->persist); -		free(f->persist); -		f->persist = NULL; -	} - -	if (f->persist && !flag_ksymoops) { -		error("has persistent data but ksymoops symbols are not available"); -		free(f->persist); -		f->persist = NULL; -	} - -	if (f->persist && !k_new_syscalls) { -		error("has persistent data but the kernel is too old to support it"); -		free(f->persist); -		f->persist = NULL; -	} - -	if (persist_parms && flag_verbose) { -		if (f->persist) -			lprintf("Persist filename '%s'", f->persist); -		else -			lprintf("No persistent filename available"); -	} - -	if (f->persist) { -		FILE *fp = fopen(f->persist, "r"); -		if (!fp) { -			if (flag_verbose) -				lprintf("Cannot open persist file '%s' %m", f->persist); -		} -		else { -			int pargc = 0; -			char *pargv[1000];	/* hard coded but big enough */ -			char line[3000];	/* hard coded but big enough */ -			char *p; -			while (fgets(line, sizeof(line), fp)) { -				p = strchr(line, '\n'); -				if (!p) { -					error("Persistent data line is too long\n%s", line); -					break; -				} -				*p = '\0'; -				p = line; -				while (isspace(*p)) -					++p; -				if (!*p || *p == '#') -					continue; -				if (pargc == sizeof(pargv)/sizeof(pargv[0])) { -					error("More than %d persistent parameters", pargc); -					break; -				} -				pargv[pargc++] = xstrdup(p); -			} -			fclose(fp); -			if (!process_module_arguments(f, pargc, pargv, 0)) -				goto out; -			while (pargc--) -				free(pargv[pargc]); -		} -	} - -	if (flag_ksymoops) -		add_ksymoops_symbols(f, filename, m_name); - -	if (k_new_syscalls) -		create_module_ksymtab(f); - -	/* archdata based on relocatable addresses */ -	if (add_archdata(f, &archdata)) -		goto out; - -	/* kallsyms based on relocatable addresses */ -	if (add_kallsyms(f, &kallsyms, force_kallsyms)) -		goto out; -	/**** No symbols or sections to be changed after kallsyms above ***/ - -	if (errors) -		goto out; - -	/* If we were just checking, we made it.  */ -	if (flag_silent_probe) { -		exit_status = 0; -		goto out; -	} -	/* Module has now finished growing; find its size and install it.  */ -	m_size = obj_load_size(f);	/* DEPMOD */ - -	if (noload) { -		/* Don't bother actually touching the kernel.  */ -		m_addr = 0x12340000; -	} else { -		errno = 0; -		m_addr = create_module(m_name, m_size); -		switch (errno) { -		case 0: -			break; -		case EEXIST: -			if (dolock) { -				/* -				 * Assume that we were just invoked -				 * simultaneous with another insmod -				 * and return success. -				 */ -				exit_status = 0; -				goto out; -			} -			error("a module named %s already exists", m_name); -			goto out; -		case ENOMEM: -			error("can't allocate kernel memory for module; needed %lu bytes", -			      m_size); -			goto out; -		default: -			error("create_module: %m"); -			goto out; -		} -	} - -	/* module is already built, complete with ksymoops symbols for the -	 * persistent filename.  If the kernel does not support persistent data -	 * then give an error but continue.  It is too difficult to clean up at -	 * this stage and this error will only occur on backported modules. -	 * rmmod will also get an error so warn the user now. -	 */ -	if (f->persist && !noload) { -		struct { -			struct module m; -			int data; -		} test_read; -		memset(&test_read, 0, sizeof(test_read)); -		test_read.m.size_of_struct = -sizeof(test_read.m);      /* -ve size => read, not write */ -		test_read.m.read_start = m_addr + sizeof(struct module); -		test_read.m.read_end = test_read.m.read_start + sizeof(test_read.data); -		if (sys_init_module(m_name, (struct module *) &test_read)) { -			int old_errors = errors; -			error("has persistent data but the kernel is too old to support it." -				"  Expect errors during rmmod as well"); -			errors = old_errors; -		} -	} - -	if (!obj_relocate(f, m_addr)) {	/* DEPMOD */ -		if (!noload) -			delete_module(m_name); -		goto out; -	} - -	/* Do archdata again, this time we have the final addresses */ -	if (add_archdata(f, &archdata)) -		goto out; - -	/* Do kallsyms again, this time we have the final addresses */ -	if (add_kallsyms(f, &kallsyms, force_kallsyms)) -		goto out; - -#ifdef COMPAT_2_0 -	if (k_new_syscalls) -		init_module(m_name, f, m_size, blob_name, noload, flag_load_map); -	else if (!noload) -		old_init_module(m_name, f, m_size); -#else -	init_module(m_name, f, m_size, blob_name, noload, flag_load_map); -#endif -	if (errors) { -		if (!noload) -			delete_module(m_name); -		goto out; -	} -	exit_status = 0; - -      out: -	if (dolock) -		flock(fp, LOCK_UN); -	close(fp); -	if (!noload) -		snap_shot(NULL, 0); - -	return exit_status; -} - -/* For common 3264 code, add an overall insmod_main, in the 64 bit version. */ -#if defined(COMMON_3264) && defined(ONLY_64) -int insmod_main(int argc, char **argv) -{ -	if (arch64()) -		return insmod_main_64(argc, argv); -	else -		return insmod_main_32(argc, argv); -} -#endif	/* defined(COMMON_3264) && defined(ONLY_64) */ - - - -int insmod_call(char * full_filename, char * params) -{ -	int argc = 2; -	char *argv[50]; -	char * ptr = params; -	argv[0] = "stage1"; -	argv[1] = full_filename; - -	while (ptr != NULL) { -		argv[argc] = ptr; -		argc++; -		ptr = strchr(ptr, ' '); -		if (ptr) { -			ptr[0] = '\0'; -			ptr++; -		} -	} - -	return insmod_main(argc, argv); -} | 
