Sophie

Sophie

distrib > * > 2008.0 > x86_64 > by-pkgid > 8cf4bc2b9427388589d216415e7b8f0e > files > 16

module-init-tools-3.3-pre11.30mdv2008.0.src.rpm

--- ./modprobe.c.lib	2007-03-22 08:36:02.000000000 +0100
+++ ./modprobe.c	2007-08-13 17:54:42.000000000 +0200
@@ -19,1349 +19,10 @@
 #define _GNU_SOURCE /* asprintf */
 
 #include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <limits.h>
-#include <elf.h>
-#include <getopt.h>
-#include <fnmatch.h>
-#include <asm/unistd.h>
-#include <sys/wait.h>
-#include <syslog.h>
-
-#define streq(a,b) (strcmp((a),(b)) == 0)
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
 #include "zlibsupport.h"
-#include "list.h"
 #include "backwards_compat.c"
+#include "modprobe.h"
 
-extern long init_module(void *, unsigned long, const char *);
-extern long delete_module(const char *, unsigned int);
-
-struct module {
-	struct list_head list;
-	char *modname;
-	char filename[0];
-};
-
-#ifndef MODULE_DIR
-#define MODULE_DIR "/lib/modules"
-#endif
-
-typedef void (*errfn_t)(const char *fmt, ...);
-
-/* Do we use syslog or stderr for messages? */
-static int log;
-
-static void message(const char *prefix, const char *fmt, va_list *arglist)
-{
-	char *buf, *buf2;
-
-	vasprintf(&buf, fmt, *arglist);
-	asprintf(&buf2, "%s%s", prefix, buf);
-
-	if (log)
-		syslog(LOG_NOTICE, "%s", buf2);
-	else
-		fprintf(stderr, "%s", buf2);
-	free(buf2);
-	free(buf);
-}
-
-static int warned = 0;
-static void warn(const char *fmt, ...)
-{
-	va_list arglist;
-	warned++;
-	va_start(arglist, fmt);
-	message("WARNING: ", fmt, &arglist);
-	va_end(arglist);
-}
-
-static void fatal(const char *fmt, ...)
-{
-	va_list arglist;
-	va_start(arglist, fmt);
-	message("FATAL: ", fmt, &arglist);
-	va_end(arglist);
-	exit(1);
-}
-
-
-static void grammar(const char *cmd, const char *filename, unsigned int line)
-{
-	warn("%s line %u: ignoring bad line starting with '%s'\n",
-	     filename, line, cmd);
-}
-
-static void *do_nofail(void *ptr, const char *file, int line, const char *expr)
-{
-	if (!ptr) {
-		fatal("Memory allocation failure %s line %d: %s.\n",
-		      file, line, expr);
-	}
-	return ptr;
-}
-
-#define NOFAIL(ptr)	do_nofail((ptr), __FILE__, __LINE__, #ptr)
-
-static void print_usage(const char *progname)
-{
-	fprintf(stderr,
-		"Usage: %s [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b] [-o <modname>] [ --dump-modversions ] <modname> [parameters...]\n"
-		"%s -r [-n] [-i] [-v] <modulename> ...\n"
-		"%s -l -t <dirname> [ -a <modulename> ...]\n",
-		progname, progname, progname);
-	exit(1);
-}
-
-static int fgetc_wrapped(FILE *file, unsigned int *linenum)
-{
-	for (;;) {
-	  	int ch = fgetc(file);
-		if (ch != '\\')
-			return ch;
-		ch = fgetc(file);
-		if (ch != '\n')
-			return ch;
-		if (linenum)
-			(*linenum)++;
-	}
-}
-
-static char *getline_wrapped(FILE *file, unsigned int *linenum)
-{
-	int size = 1024;
-	int i = 0;
-	char *buf = NOFAIL(malloc(size));
-	for(;;) {
-		int ch = fgetc_wrapped(file, linenum);
-		if (i == size) {
-			size *= 2;
-			buf = NOFAIL(realloc(buf, size));
-		}
-		if (ch < 0 && i == 0) {
-			free(buf);
-			return NULL;
-		}
-		if (ch < 0 || ch == '\n') {
-			if (linenum)
-				(*linenum)++;
-			buf[i] = '\0';
-			return NOFAIL(realloc(buf, i+1));
-		}
-		buf[i++] = ch;
-	}
-}
-
-static struct module *find_module(const char *filename, struct list_head *list)
-{
-	struct module *i;
-
-	list_for_each_entry(i, list, list) {
-		if (strcmp(i->filename, filename) == 0)
-			return i;
-	}
-	return NULL;
-}
-
-/* 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';
-}
-
-static int lock_file(const char *filename)
-{
-	int fd = open(filename, O_RDWR, 0);
-
-	if (fd >= 0) {
-		struct flock lock;
-		lock.l_type = F_WRLCK;
-		lock.l_whence = SEEK_SET;
-		lock.l_start = 0;
-		lock.l_len = 1;
-		fcntl(fd, F_SETLKW, &lock);
-	} else
-		/* Read-only filesystem?  There goes locking... */
-		fd = open(filename, O_RDONLY, 0);
-	return fd;
-}
-
-static void unlock_file(int fd)
-{
-	/* Valgrind is picky... */
-	close(fd);
-}
-
-static void add_module(char *filename, int namelen, struct list_head *list)
-{
-	struct module *mod;
-
-	/* If it's a duplicate: move it to the end, so it gets
-	   inserted where it is *first* required. */
-	mod = find_module(filename, list);
-	if (mod)
-		list_del(&mod->list);
-	else {
-		/* No match.  Create a new module. */
-		mod = NOFAIL(malloc(sizeof(struct module) + namelen + 1));
-		memcpy(mod->filename, filename, namelen);
-		mod->filename[namelen] = '\0';
-		mod->modname = NOFAIL(malloc(namelen + 1));
-		filename2modname(mod->modname, mod->filename);
-	}
-
-	list_add_tail(&mod->list, list);
-}
-
-/* Compare len chars of a to b, with _ and - equivalent. */
-static int modname_equal(const char *a, const char *b, unsigned int len)
-{
-	unsigned int i;
-
-	if (strlen(b) != len)
-		return 0;
-
-	for (i = 0; i < len; i++) {
-		if ((a[i] == '_' || a[i] == '-')
-		    && (b[i] == '_' || b[i] == '-'))
-			continue;
-		if (a[i] != b[i])
-			return 0;
-	}
-	return 1;
-}
-
-/* Fills in list of modules if this is the line we want. */
-static int add_modules_dep_line(char *line,
-				const char *name,
-				struct list_head *list)
-{
-	char *ptr;
-	int len;
-	char *modname;
-
-	/* Ignore lines without : or which start with a # */
-	ptr = strchr(line, ':');
-	if (ptr == NULL || line[strspn(line, "\t ")] == '#')
-		return 0;
-
-	/* Is this the module we are looking for? */
-	*ptr = '\0';
-	if (strrchr(line, '/'))
-		modname = strrchr(line, '/') + 1;
-	else
-		modname = line;
-
-	len = strlen(modname);
-	if (strchr(modname, '.'))
-		len = strchr(modname, '.') - modname;
-	if (!modname_equal(modname, name, len))
-		return 0;
-
-	/* Create the list. */
-	add_module(line, ptr - line, list);
-
-	ptr++;
-	for(;;) {
-		char *dep_start;
-		ptr += strspn(ptr, " \t");
-		if (*ptr == '\0')
-			break;
-		dep_start = ptr;
-		ptr += strcspn(ptr, " \t");
-		add_module(dep_start, ptr - dep_start, list);
-	}
-	return 1;
-}
-
-static void read_depends(const char *dirname,
-			 const char *start_name,
-			 struct list_head *list)
-{
-	char *modules_dep_name;
-	char *line;
-	FILE *modules_dep;
-	int done = 0;
-
-	asprintf(&modules_dep_name, "%s/%s", dirname, "modules.dep");
-	modules_dep = fopen(modules_dep_name, "r");
-	if (!modules_dep)
-		fatal("Could not load %s: %s\n",
-		      modules_dep_name, strerror(errno));
-
-	/* Stop at first line, as we can have duplicates (eg. symlinks
-           from boot/ */
-	while (!done && (line = getline_wrapped(modules_dep, NULL)) != NULL) {
-		done = add_modules_dep_line(line, start_name, list);
-		free(line);
-	}
-	fclose(modules_dep);
-	free(modules_dep_name);
-}
-
-/* We use error numbers in a loose translation... */
-static const char *insert_moderror(int err)
-{
-	switch (err) {
-	case ENOEXEC:
-		return "Invalid module format";
-	case ENOENT:
-		return "Unknown symbol in module, or unknown parameter (see dmesg)";
-	case ENOSYS:
-		return "Kernel does not have module support";
-	default:
-		return strerror(err);
-	}
-}
-
-static const char *remove_moderror(int err)
-{
-	switch (err) {
-	case ENOENT:
-		return "No such module";
-	case ENOSYS:
-		return "Kernel does not have module unloading support";
-	default:
-		return strerror(err);
-	}
-}
-
-/* Is module in /proc/modules?  If so, fill in usecount if not NULL. 
-   0 means no, 1 means yes, -1 means unknown.
- */
-static int module_in_kernel(const char *modname, unsigned int *usecount)
-{
-	FILE *proc_modules;
-	char *line;
-
-again:
-	/* Might not be mounted yet.  Don't fail. */
-	proc_modules = fopen("/proc/modules", "r");
-	if (!proc_modules)
-		return -1;
-
-	while ((line = getline_wrapped(proc_modules, NULL)) != NULL) {
-		char *entry = strtok(line, " \n");
-
-		if (entry && streq(entry, modname)) {
-			/* If it exists, usecount is the third entry. */
-			if (!strtok(NULL, " \n"))
-				goto out;
-
-			if (!(entry = strtok(NULL, " \n"))) /* usecount */
-				goto out;
-			else
-				if (usecount)
-					*usecount = atoi(entry);
-
-			/* Followed by - then status. */
-			if (strtok(NULL, " \n")
-			    && (entry = strtok(NULL, " \n")) != NULL) {
-				/* Locking will fail on ro fs, we might hit
-				 * cases where module is in flux.  Spin. */
-				if (streq(entry, "Loading")
-				    || streq(entry, "Unloading")) {
-					usleep(100000);
-					free(line);
-					fclose(proc_modules);
-					goto again;
-				}
-			}
-
-		out:
-			free(line);
-			fclose(proc_modules);
-			return 1;
-		}
-		free(line);
-	}
-	fclose(proc_modules);
-	return 0;
-}
-
-static void replace_modname(struct module *module,
-			    void *mem, unsigned long len,
-			    const char *oldname, const char *newname)
-{
-	char *p;
-
-	/* 64 - sizeof(unsigned long) - 1 */
-	if (strlen(newname) > 55)
-		fatal("New name %s is too long\n", newname);
-
-	/* Find where it is in the module structure.  Don't assume layout! */
-	for (p = mem; p < (char *)mem + len - strlen(oldname); p++) {
-		if (memcmp(p, oldname, strlen(oldname)) == 0) {
-			strcpy(p, newname);
-			return;
-		}
-	}
-
-	warn("Could not find old name in %s to replace!\n", module->filename);
-}
-
-static void *get_section32(void *file,
-			   unsigned long size,
-			   const char *name,
-			   unsigned long *secsize)
-{
-	Elf32_Ehdr *hdr = file;
-	Elf32_Shdr *sechdrs = file + hdr->e_shoff;
-	const char *secnames;
-	unsigned int i;
-
-	/* Too short? */
-	if (size < sizeof(*hdr))
-		return NULL;
-	if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0]))
-		return NULL;
-	if (size < sechdrs[hdr->e_shstrndx].sh_offset)
-		return NULL;
-		
-	secnames = file + sechdrs[hdr->e_shstrndx].sh_offset;
-	for (i = 1; i < hdr->e_shnum; i++)
-		if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
-			*secsize = sechdrs[i].sh_size;
-			return file + sechdrs[i].sh_offset;
-		}
-	return NULL;
-}
-
-static void *get_section64(void *file,
-			   unsigned long size,
-			   const char *name,
-			   unsigned long *secsize)
-{
-	Elf64_Ehdr *hdr = file;
-	Elf64_Shdr *sechdrs = file + hdr->e_shoff;
-	const char *secnames;
-	unsigned int i;
-
-	/* Too short? */
-	if (size < sizeof(*hdr))
-		return NULL;
-	if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0]))
-		return NULL;
-	if (size < sechdrs[hdr->e_shstrndx].sh_offset)
-		return NULL;
-		
-	secnames = file + sechdrs[hdr->e_shstrndx].sh_offset;
-	for (i = 1; i < hdr->e_shnum; i++)
-		if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
-			*secsize = sechdrs[i].sh_size;
-			return file + sechdrs[i].sh_offset;
-		}
-	return NULL;
-}
-
-static int elf_ident(void *mod, unsigned long size)
-{
-	/* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */
-	char *ident = mod;
-
-	if (size < EI_CLASS || memcmp(mod, ELFMAG, SELFMAG) != 0)
-		return ELFCLASSNONE;
-	return ident[EI_CLASS];
-}
-
-static void *get_section(void *file,
-			 unsigned long size,
-			 const char *name,
-			 unsigned long *secsize)
-{
-	switch (elf_ident(file, size)) {
-	case ELFCLASS32:
-		return get_section32(file, size, name, secsize);
-	case ELFCLASS64:
-		return get_section64(file, size, name, secsize);
-	default:
-		return NULL;
-	}
-}
-
-static void rename_module(struct module *module,
-			  void *mod,
-			  unsigned long len,
-			  const char *newname)
-{
-	void *modstruct;
-	unsigned long modstruct_len;
-
-	/* Old-style */
-	modstruct = get_section(mod, len, ".gnu.linkonce.this_module",
-				&modstruct_len);
-	/* New-style */
-	if (!modstruct)
-		modstruct = get_section(mod, len, "__module", &modstruct_len);
-	if (!modstruct)
-		warn("Could not find module name to change in %s\n",
-		     module->filename);
-	else
-		replace_modname(module, modstruct, modstruct_len,
-				module->modname, newname);
-}
-
-/* Kernel told to ignore these sections if SHF_ALLOC not set. */
-static void invalidate_section32(void *mod, const char *secname)
-{
-	Elf32_Ehdr *hdr = mod;
-	Elf32_Shdr *sechdrs = mod + hdr->e_shoff;
-	const char *secnames = mod + sechdrs[hdr->e_shstrndx].sh_offset;
-	unsigned int i;
-
-	for (i = 1; i < hdr->e_shnum; i++)
-		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0)
-			sechdrs[i].sh_flags &= ~SHF_ALLOC;
-}
-
-static void invalidate_section64(void *mod, const char *secname)
-{
-	Elf64_Ehdr *hdr = mod;
-	Elf64_Shdr *sechdrs = mod + hdr->e_shoff;
-	const char *secnames = mod + sechdrs[hdr->e_shstrndx].sh_offset;
-	unsigned int i;
-
-	for (i = 1; i < hdr->e_shnum; i++)
-		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0)
-			sechdrs[i].sh_flags &= ~(unsigned long long)SHF_ALLOC;
-}
-
-static void strip_section(struct module *module,
-			  void *mod,
-			  unsigned long len,
-			  const char *secname)
-{
-	switch (elf_ident(mod, len)) {
-	case ELFCLASS32:
-		invalidate_section32(mod, secname);
-		break;
-	case ELFCLASS64:
-		invalidate_section64(mod, secname);
-		break;
-	default:
-		warn("Unknown module format in %s: not forcing version\n",
-		     module->filename);
-	}
-}
-
-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 clear_magic(struct module *module, void *mod, unsigned long len)
-{
-	const char *p;
-	unsigned long modlen;
-
-	/* Old-style: __vermagic section */
-	strip_section(module, mod, len, "__vermagic");
-
-	/* New-style: in .modinfo section */
-	for (p = get_section(mod, len, ".modinfo", &modlen);
-	     p;
-	     p = next_string(p, &modlen)) {
-		if (strncmp(p, "vermagic=", strlen("vermagic=")) == 0) {
-			memset((char *)p, 0, strlen(p));
-			return;
-		}
-	}
-}
-
-struct module_options
-{
-	struct module_options *next;
-	char *modulename;
-	char *options;
-};
-
-struct module_command
-{
-	struct module_command *next;
-	char *modulename;
-	char *command;
-};
-
-struct module_alias
-{
-	struct module_alias *next;
-	char *module;
-};
-
-struct module_blacklist
-{
-	struct module_blacklist *next;
-	char *modulename;
-};
-
-/* Link in a new option line from the config file. */
-static struct module_options *
-add_options(const char *modname,
-	    const char *option,
-	    struct module_options *options)
-{
-	struct module_options *new;
-	char *tab; 
-
-	new = NOFAIL(malloc(sizeof(*new)));
-	new->modulename = NOFAIL(strdup(modname));
-	new->options = NOFAIL(strdup(option));
-	/* We can handle tabs, kernel can't. */
-	for (tab = strchr(new->options, '\t'); tab; tab = strchr(tab, '\t'))
-		*tab = ' ';
-	new->next = options;
-	return new;
-}
-
-/* Link in a new install line from the config file. */
-static struct module_command *
-add_command(const char *modname,
-	       const char *command,
-	       struct module_command *commands)
-{
-	struct module_command *new;
-
-	new = NOFAIL(malloc(sizeof(*new)));
-	new->modulename = NOFAIL(strdup(modname));
-	new->command = NOFAIL(strdup(command));
-	new->next = commands;
-	return new;
-}
-
-/* Link in a new alias line from the config file. */
-static struct module_alias *
-add_alias(const char *modname, struct module_alias *aliases)
-{
-	struct module_alias *new;
-
-	new = NOFAIL(malloc(sizeof(*new)));
-	new->module = NOFAIL(strdup(modname));
-	new->next = aliases;
-	return new;
-}
-
-/* Link in a new blacklist line from the config file. */
-static struct module_blacklist *
-add_blacklist(const char *modname, struct module_blacklist *blacklist)
-{
-	struct module_blacklist *new;
-
-	new = NOFAIL(malloc(sizeof(*new)));
-	new->modulename = NOFAIL(strdup(modname));
-	new->next = blacklist;
-	return new;
-}
-
-/* Find blacklist commands if any. */
-static  int
-find_blacklist(const char *modname, const struct module_blacklist *blacklist)
-{
-	while (blacklist) {
-		if (strcmp(blacklist->modulename, modname) == 0)
-			return 1;
-		blacklist = blacklist->next;
-	}
-	return 0;
-}
-
-/* return a new alias list, with backlisted elems filtered out */
-static struct module_alias *
-apply_blacklist(const struct module_alias *aliases,
-		const struct module_blacklist *blacklist)
-{
-	struct module_alias *result = NULL;
-	while (aliases) {
-		char *modname = aliases->module;
-		if (!find_blacklist(modname, blacklist))
-			result = add_alias(modname, result);
-		aliases = aliases->next;
-	}
-	return result;
-}
-
-/* Find install commands if any. */
-static const char *find_command(const char *modname,
-				const struct module_command *commands)
-{
-	while (commands) {
-		if (fnmatch(commands->modulename, modname, 0) == 0)
-			return commands->command;
-		commands = commands->next;
-	}
-	return NULL;
-}
-
-static char *append_option(char *options, const char *newoption)
-{
-	options = NOFAIL(realloc(options, strlen(options) + 1
-				 + strlen(newoption) + 1));
-	if (strlen(options)) strcat(options, " ");
-	strcat(options, newoption);
-	return options;
-}
-
-/* Add to options */
-static char *add_extra_options(const char *modname,
-			       char *optstring,
-			       const struct module_options *options)
-{
-	while (options) {
-		if (strcmp(options->modulename, modname) == 0)
-			optstring = append_option(optstring, options->options);
-		options = options->next;
-	}
-	return optstring;
-}
-
-/* If we don't flush, then child processes print before we do */
-static void verbose_printf(int verbose, const char *fmt, ...)
-{
-	va_list arglist;
-
-	if (verbose) {
-		va_start(arglist, fmt);
-		vprintf(fmt, arglist);
-		fflush(stdout);
-		va_end(arglist);
-	}
-}
-
-/* Do an install/remove command: replace $CMDLINE_OPTS if it's specified. */
-static void do_command(const char *modname,
-		       const char *command,
-		       int verbose, int dry_run,
-		       errfn_t error,
-		       const char *type,
-		       const char *cmdline_opts)
-{
-	int ret;
-	char *p, *replaced_cmd = NOFAIL(strdup(command));
-
-	while ((p = strstr(replaced_cmd, "$CMDLINE_OPTS")) != NULL) {
-		char *new;
-		asprintf(&new, "%.*s%s%s",
-			 (int)(p - replaced_cmd), replaced_cmd, cmdline_opts,
-			 p + strlen("$CMDLINE_OPTS"));
-		NOFAIL(new);
-		free(replaced_cmd);
-		replaced_cmd = new;
-	}
-
-	verbose_printf(verbose, "%s %s\n", type, replaced_cmd);
-	if (dry_run)
-		return;
-
-	setenv("MODPROBE_MODULE", modname, 1);
-	ret = system(replaced_cmd);
-	if (ret == -1 || WEXITSTATUS(ret))
-		error("Error running %s command for %s\n", type, modname);
-	free(replaced_cmd);
-}
-
-/* Actually do the insert.  Frees second arg. */
-static void insmod(struct list_head *list,
-		   char *optstring,
-		   const char *newname,
-		   int first_time,
-		   errfn_t error,
-		   int dry_run,
-		   int verbose,
-		   const struct module_options *options,
-		   const struct module_command *commands,
-		   int ignore_commands,
-		   int ignore_proc,
-		   int strip_vermagic,
-		   int strip_modversion,
-		   const char *cmdline_opts)
-{
-	int ret, fd;
-	unsigned long len;
-	void *map;
-	const char *command;
-	struct module *mod = list_entry(list->next, struct module, list);
-
-	/* Take us off the list. */
-	list_del(&mod->list);
-
-	/* Do things we (or parent) depend on first, but don't die if
-	 * they fail. */
-	if (!list_empty(list)) {
-		insmod(list, NOFAIL(strdup("")), NULL, 0, warn,
-		       dry_run, verbose, options, commands, 0, ignore_proc,
-		       strip_vermagic, strip_modversion, "");
-	}
-
-	/* Lock before we look, in case it's initializing. */
-	fd = lock_file(mod->filename);
-	if (fd < 0) {
-		error("Could not open '%s': %s\n",
-		      mod->filename, strerror(errno));
-		goto out_optstring;
-	}
-
-	/* Don't do ANYTHING if already in kernel. */
-	if (!ignore_proc
-	    && module_in_kernel(newname ?: mod->modname, NULL) == 1) {
-		if (first_time)
-			error("Module %s already in kernel.\n",
-			      newname ?: mod->modname);
-		goto out_unlock;
-	}
-
-	command = find_command(mod->modname, commands);
-	if (command && !ignore_commands) {
-		/* It might recurse: unlock. */
-		unlock_file(fd);
-		do_command(mod->modname, command, verbose, dry_run, error,
-			   "install", cmdline_opts);
-		goto out_optstring;
-	}
-
-	map = grab_fd(fd, &len);
-	if (!map) {
-		error("Could not read '%s': %s\n",
-		      mod->filename, strerror(errno));
-		goto out_unlock;
-	}
-
-	/* Rename it? */
-	if (newname)
-		rename_module(mod, map, len, newname);
-
-	if (strip_modversion)
-		strip_section(mod, map, len, "__versions");
-	if (strip_vermagic)
-		clear_magic(mod, map, len);
-
-	/* Config file might have given more options */
-	optstring = add_extra_options(mod->modname, optstring, options);
-
-	verbose_printf(verbose, "insmod %s %s\n", mod->filename, optstring);
-
-	if (dry_run)
-		goto out;
-
-	ret = init_module(map, len, optstring);
-	if (ret != 0) {
-		if (errno == EEXIST) {
-			if (first_time)
-				error("Module %s already in kernel.\n",
-				      newname ?: mod->modname);
-			goto out_unlock;
-		}
-		error("Error inserting %s (%s): %s\n",
-		      mod->modname, mod->filename, insert_moderror(errno));
-	}
- out:
-	release_file(map, len);
- out_unlock:
-	unlock_file(fd);
- out_optstring:
-	free(optstring);
-	return;
-}
-
-/* Do recursive removal. */
-static void rmmod(struct list_head *list,
-		  const char *name,
-		  int first_time,
-		  errfn_t error,
-		  int dry_run,
-		  int verbose,
-		  struct module_command *commands,
-		  int ignore_commands,
-		  int ignore_inuse,
-		  const char *cmdline_opts)
-{
-	const char *command;
-	unsigned int usecount = 0;
-	int lock;
-	struct module *mod = list_entry(list->next, struct module, list);
-
-	/* Take first one off the list. */
-	list_del(&mod->list);
-
-	/* Ignore failure; it's best effort here. */
-	lock = lock_file(mod->filename);
-
-	if (!name)
-		name = mod->modname;
-
-	/* Even if renamed, find commands to orig. name. */
-	command = find_command(mod->modname, commands);
-	if (command && !ignore_commands) {
-		/* It might recurse: unlock. */
-		unlock_file(lock);
-		do_command(mod->modname, command, verbose, dry_run, error,
-			   "remove", cmdline_opts);
-		goto remove_rest_no_unlock;
-	}
-
-	if (module_in_kernel(name, &usecount) == 0)
-		goto nonexistent_module;
-
-	if (usecount != 0) {
-		if (!ignore_inuse)
-			error("Module %s is in use.\n", name);
-		goto remove_rest;
-	}
-
-	verbose_printf(verbose, "rmmod %s\n", mod->filename);
-
-	if (dry_run)
-		goto remove_rest;
-
-	if (delete_module(name, O_EXCL) != 0) {
-		if (errno == ENOENT)
-			goto nonexistent_module;
-		error("Error removing %s (%s): %s\n",
-		      name, mod->filename,
-		      remove_moderror(errno));
-	}
-
- remove_rest:
-	unlock_file(lock);
- remove_rest_no_unlock:
-	/* Now do things we depend. */
-	if (!list_empty(list))
-		rmmod(list, NULL, 0, warn, dry_run, verbose, commands,
-		      0, 1, "");
-	return;
-
-nonexistent_module:
-	if (first_time)
-		fatal("Module %s is not in kernel.\n", mod->modname);
-	goto remove_rest;
-}
-
-/* Does path contain directory(s) subpath? */
-static int type_matches(const char *path, const char *subpath)
-{
-	char *subpath_with_slashes;
-	int ret;
-
-	asprintf(&subpath_with_slashes, "/%s/", subpath);
-	NOFAIL(subpath_with_slashes);
-
-	ret = (strstr(path, subpath_with_slashes) != NULL);
-	free(subpath_with_slashes);
-	return ret;
-}
-
-/* Careful!  Don't munge - in [ ] as per Debian Bug#350915 */
-static char *underscores(char *string)
-{
-	if (string) {
-		unsigned int i;
-		int inbracket = 0;
-		for (i = 0; string[i]; i++) {
-			switch (string[i]) {
-			case '[':
-				inbracket++;
-				break;
-			case ']':
-				inbracket--;
-				break;
-			case '-':
-				if (!inbracket)
-					string[i] = '_';
-			}
-		}
-		if (inbracket)
-			warn("Unmatched bracket in %s\n", string);
-	}
-	return string;
-}
-
-static int do_wildcard(const char *dirname,
-		       const char *type,
-		       const char *wildcard)
-{
-	char modules_dep_name[strlen(dirname) + sizeof("modules.dep") + 1];
-	char *line, *wcard;
-	FILE *modules_dep;
-
-	/* Canonicalize wildcard */
-	wcard = strdup(wildcard);
-	underscores(wcard);
-
-	sprintf(modules_dep_name, "%s/%s", dirname, "modules.dep");
-	modules_dep = fopen(modules_dep_name, "r");
-	if (!modules_dep)
-		fatal("Could not load %s: %s\n",
-		      modules_dep_name, strerror(errno));
-
-	while ((line = getline_wrapped(modules_dep, NULL)) != NULL) {
-		char *ptr;
-
-		/* Ignore lines without : or which start with a # */
-		ptr = strchr(line, ':');
-		if (ptr == NULL || line[strspn(line, "\t ")] == '#')
-			goto next;
-		*ptr = '\0';
-
-		/* "type" must match complete directory component(s). */
-		if (!type || type_matches(line, type)) {
-			char modname[strlen(line)+1];
-
-			filename2modname(modname, line);
-			if (fnmatch(wcard, modname, 0) == 0)
-				printf("%s\n", line);
-		}
-	next:
-		free(line);
-	}
-
-	free(wcard);
-	return 0;
-}
-
-static char *strsep_skipspace(char **string, char *delim)
-{
-	if (!*string)
-		return NULL;
-	*string += strspn(*string, delim);
-	return strsep(string, delim);
-}
-
-/* Recursion */
-static int read_config(const char *filename,
-		       const char *name,
-		       int dump_only,
-		       int removing,
-		       struct module_options **options,
-		       struct module_command **commands,
-		       struct module_alias **alias,
-		       struct module_blacklist **blacklist);
-
-/* FIXME: Maybe should be extended to "alias a b [and|or c]...". --RR */
-static int read_config_file(const char *filename,
-			    const char *name,
-			    int dump_only,
-			    int removing,
-			    struct module_options **options,
-			    struct module_command **commands,
-			    struct module_alias **aliases,
-			    struct module_blacklist **blacklist)
-{
-	char *line;
-	unsigned int linenum = 0;
-	FILE *cfile;
-
-	cfile = fopen(filename, "r");
-	if (!cfile)
-		return 0;
-
-	while ((line = getline_wrapped(cfile, &linenum)) != NULL) {
-		char *ptr = line;
-		char *cmd, *modname;
-
-		if (dump_only)
-			printf("%s\n", line);
-
-		cmd = strsep_skipspace(&ptr, "\t ");
-		if (cmd == NULL || cmd[0] == '#' || cmd[0] == '\0')
-			continue;
-
-		if (strcmp(cmd, "alias") == 0) {
-			char *wildcard
-				= underscores(strsep_skipspace(&ptr, "\t "));
-			char *realname
-				= underscores(strsep_skipspace(&ptr, "\t "));
-
-			if (!wildcard || !realname)
-				grammar(cmd, filename, linenum);
-			else if (fnmatch(wildcard,name,0) == 0)
-				*aliases = add_alias(realname, *aliases);
-		} else if (strcmp(cmd, "include") == 0) {
-			struct module_alias *newalias = NULL;
-			char *newfilename;
-
-			newfilename = strsep_skipspace(&ptr, "\t ");
-			if (!newfilename)
-				grammar(cmd, filename, linenum);
-			else {
-				if (!read_config(newfilename, name,
-						 dump_only, removing,
-						 options, commands, &newalias,
-						 blacklist))
-					warn("Failed to open included"
-					      " config file %s: %s\n",
-					      newfilename, strerror(errno));
-
-				/* Files included override aliases,
-				   etc that was already set ... */
-				if (newalias)
-					*aliases = newalias;
-			}
-		} else if (strcmp(cmd, "options") == 0) {
-			modname = strsep_skipspace(&ptr, "\t ");
-			if (!modname || !ptr)
-				grammar(cmd, filename, linenum);
-			else {
-				ptr += strspn(ptr, "\t ");
-				*options = add_options(underscores(modname),
-						       ptr, *options);
-			}
-		} else if (strcmp(cmd, "install") == 0) {
-			modname = strsep_skipspace(&ptr, "\t ");
-			if (!modname || !ptr)
-				grammar(cmd, filename, linenum);
-			else if (!removing) {
-				ptr += strspn(ptr, "\t ");
-				*commands = add_command(underscores(modname),
-							ptr, *commands);
-			}
-		} else if (strcmp(cmd, "blacklist") == 0) {
-			modname = strsep_skipspace(&ptr, "\t ");
-			if (!modname)
-				grammar(cmd, filename, linenum);
-			else if (!removing) {
-				*blacklist = add_blacklist(underscores(modname),
-							*blacklist);
-			}
-		} else if (strcmp(cmd, "remove") == 0) {
-			modname = strsep_skipspace(&ptr, "\t ");
-			if (!modname || !ptr)
-				grammar(cmd, filename, linenum);
-			else if (removing) {
-				ptr += strspn(ptr, "\t ");
-				*commands = add_command(underscores(modname),
-							ptr, *commands);
-			}
-		} else
-			grammar(cmd, filename, linenum);
-
-		free(line);
-	}
-	fclose(cfile);
-	return 1;
-}
-
-/* Simple format, ignore lines starting with #, one command per line.
-   Returns true or false. */
-static int read_config(const char *filename,
-		       const char *name,
-		       int dump_only,
-		       int removing,
-		       struct module_options **options,
-		       struct module_command **commands,
-		       struct module_alias **aliases,
-		       struct module_blacklist **blacklist)
-{
-	DIR *dir;
-	int ret = 0;
-
-	/* Reiser4 has file/directory duality: treat it as both. */
-	dir = opendir(filename);
-	if (dir) {
-		struct dirent *i;
-		while ((i = readdir(dir)) != NULL) {
-			if (!streq(i->d_name,".") && !streq(i->d_name,"..")) {
-				char sub[strlen(filename) + 1
-					 + strlen(i->d_name) + 1];
-
-				sprintf(sub, "%s/%s", filename, i->d_name);
-				if (!read_config(sub, name,
-						 dump_only, removing, options,
-						 commands, aliases, blacklist))
-					warn("Failed to open"
-					     " config file %s: %s\n",
-					     sub, strerror(errno));
-			}
-		}
-		closedir(dir);
-		ret = 1;
-	}
-
-	if (read_config_file(filename, name, dump_only, removing,
-			     options, commands, aliases, blacklist))
-		ret = 1;
-
-	return ret;
-}
-
-static const char *default_configs[] = 
-{
-	"/etc/modprobe.conf",
-	"/etc/modprobe.d",
-};
-
-static void read_toplevel_config(const char *filename,
-				 const char *name,
-				 int dump_only,
-				 int removing,
-				 struct module_options **options,
-				 struct module_command **commands,
-				 struct module_alias **aliases,
-				 struct module_blacklist **blacklist)
-{
-	unsigned int i;
-
-	if (filename) {
-		if (!read_config(filename, name, dump_only, removing,
-				 options, commands, aliases, blacklist))
-			fatal("Failed to open config file %s: %s\n",
-			      filename, strerror(errno));
-		return;
-	}
-
-	/* Try defaults. */
-	for (i = 0; i < ARRAY_SIZE(default_configs); i++) {
-		if (read_config(default_configs[i], name, dump_only, removing,
-				options, commands, aliases, blacklist))
-			return;
-	}
-}
-
-static void add_to_env_var(const char *option)
-{
-	const char *oldenv;
-
-	if ((oldenv = getenv("MODPROBE_OPTIONS")) != NULL) {
-		char *newenv;
-		asprintf(&newenv, "%s %s", oldenv, option);
-		setenv("MODPROBE_OPTIONS", newenv, 1);
-	} else
-		setenv("MODPROBE_OPTIONS", option, 1);
-}
-
-/* Prepend options from environment. */
-static char **merge_args(char *args, char *argv[], int *argc)
-{
-	char *arg, *argstring;
-	char **newargs = NULL;
-	unsigned int i, num_env = 0;
-
-	if (!args)
-		return argv;
-
-	argstring = NOFAIL(strdup(args));
-	for (arg = strtok(argstring, " "); arg; arg = strtok(NULL, " ")) {
-		num_env++;
-		newargs = NOFAIL(realloc(newargs,
-					 sizeof(newargs[0])
-					 * (num_env + *argc + 1)));
-		newargs[num_env] = arg;
-	}
-
-	/* Append commandline args */
-	newargs[0] = argv[0];
-	for (i = 1; i <= *argc; i++)
-		newargs[num_env+i] = argv[i];
-
-	*argc += num_env;
-	return newargs;
-}
-
-static char *gather_options(char *argv[])
-{
-	char *optstring = NOFAIL(strdup(""));
-
-	/* Rest is module options */
-	while (*argv) {
-		/* Quote value if it contains spaces. */
-		unsigned int eq = strcspn(*argv, "=");
-
-		if (strchr(*argv+eq, ' ') && !strchr(*argv, '"')) {
-			char quoted[strlen(*argv) + 3];
-			(*argv)[eq] = '\0';
-			sprintf(quoted, "%s=\"%s\"", *argv, *argv+eq+1);
-			optstring = append_option(optstring, quoted);
-		} else
-			optstring = append_option(optstring, *argv);
-		argv++;
-	}
-	return optstring;
-}
-
-static void handle_module(const char *modname,
-			  struct list_head *todo_list,
-			  const char *newname,
-			  int remove,
-			  char *options,
-			  int first_time,
-			  errfn_t error,
-			  int dry_run,
-			  int verbose,
-			  struct module_options *modoptions,
-			  struct module_command *commands,
-			  int ignore_commands,
-			  int ignore_proc,
-			  int strip_vermagic,
-			  int strip_modversion,
-			  int unknown_silent,
-			  const char *cmdline_opts)
-{
-	if (list_empty(todo_list)) {
-		const char *command;
-
-		/* The dependencies have to be real modules, but
-		   handle case where the first is completely bogus. */
-		command = find_command(modname, commands);
-		if (command && !ignore_commands) {
-			do_command(modname, command, verbose, dry_run, error,
-				   remove ? "remove":"install", cmdline_opts);
-			return;
-		}
-
-		if (unknown_silent)
-			exit(1);
-		error("Module %s not found.\n", modname);
-		return;
-	}
-
-	if (remove)
-		rmmod(todo_list, newname, first_time, error, dry_run, verbose,
-		      commands, ignore_commands, 0, cmdline_opts);
-	else
-		insmod(todo_list, NOFAIL(strdup(options)), newname,
-		       first_time, error, dry_run, verbose, modoptions,
-		       commands, ignore_commands, ignore_proc, strip_vermagic,
-		       strip_modversion, cmdline_opts);
-}
 
 static struct option options[] = { { "verbose", 0, NULL, 'v' },
 				   { "version", 0, NULL, 'V' },
@@ -1388,23 +49,6 @@ static struct option options[] = { { "ve
 				   { "use-blacklist", 0, NULL, 'b' },
 				   { NULL, 0, NULL, 0 } };
 
-#define MODPROBE_DEVFSD_CONF "/etc/modprobe.devfs"
-
-/* This is a horrible hack to allow devfsd, which calls modprobe with
-   -C /etc/modules.conf or /etc/modules.devfs, to work.  FIXME. */
-/* Modern devfsd or variants should use -q explicitly in 2.6. */
-static int is_devfs_call(char *argv[])
-{
-	unsigned int i;
-
-	/* Look for "/dev" arg */
-	for (i = 1; argv[i]; i++) {
-		if (strncmp(argv[i], "/dev/", 5) == 0)
-			return 1;
-	}
-	return 0;
-}
-
 int main(int argc, char *argv[])
 {
 	struct utsname buf;
--- ./modprobe.h.lib	2007-08-13 17:54:42.000000000 +0200
+++ ./modprobe.h	2007-08-13 17:54:42.000000000 +0200
@@ -0,0 +1,332 @@
+/* modprobe.h: add or remove a module from the kernel, intelligently.
+    Copyright (C) 2001  Rusty Russell.
+    Copyright (C) 2002, 2003  Rusty Russell, IBM Corporation.
+
+    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
+*/
+#define _GNU_SOURCE /* asprintf */
+
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <elf.h>
+#include <getopt.h>
+#include <fnmatch.h>
+#include <asm/unistd.h>
+#include <sys/wait.h>
+#include <syslog.h>
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#include "list.h"
+
+extern long init_module(void *, unsigned long, const char *);
+extern long delete_module(const char *, unsigned int);
+
+struct module {
+	struct list_head list;
+	char *modname;
+	char filename[0];
+};
+
+#ifndef MODULE_DIR
+#define MODULE_DIR "/lib/modules"
+#endif
+
+typedef void (*errfn_t)(const char *fmt, ...);
+
+extern int log;
+
+void message(const char *prefix, const char *fmt, va_list *arglist);
+
+void warn(const char *fmt, ...);
+
+void fatal(const char *fmt, ...);
+
+void grammar(const char *cmd, const char *filename, unsigned int line);
+
+void *do_nofail(void *ptr, const char *file, int line, const char *expr);
+
+#define NOFAIL(ptr)	do_nofail((ptr), __FILE__, __LINE__, #ptr)
+
+void print_usage(const char *progname);
+
+int fgetc_wrapped(FILE *file, unsigned int *linenum);
+
+char *getline_wrapped(FILE *file, unsigned int *linenum);
+
+struct module *find_module(const char *filename, struct list_head *list);
+
+/* Convert filename to the module name.  Works if filename == modname, too. */
+void filename2modname(char *modname, const char *filename);
+
+int lock_file(const char *filename);
+
+void unlock_file(int fd);
+
+void add_module(char *filename, int namelen, struct list_head *list);
+
+/* Compare len chars of a to b, with _ and - equivalent. */
+int modname_equal(const char *a, const char *b, unsigned int len);
+
+/* Fills in list of modules if this is the line we want. */
+int add_modules_dep_line(char *line,
+				const char *name,
+				struct list_head *list);
+
+void read_depends(const char *dirname,
+			 const char *start_name,
+			 struct list_head *list);
+
+/* We use error numbers in a loose translation... */
+const char *insert_moderror(int err);
+
+const char *remove_moderror(int err);
+
+/* Is module in /proc/modules?  If so, fill in usecount if not NULL. 
+   0 means no, 1 means yes, -1 means unknown.
+ */
+int module_in_kernel(const char *modname, unsigned int *usecount);
+
+void replace_modname(struct module *module,
+			    void *mem, unsigned long len,
+			    const char *oldname, const char *newname);
+
+void *get_section32(void *file,
+			   unsigned long size,
+			   const char *name,
+			   unsigned long *secsize);
+
+void *get_section64(void *file,
+			   unsigned long size,
+			   const char *name,
+			   unsigned long *secsize);
+
+int elf_ident(void *mod, unsigned long size);
+
+void *get_section(void *file,
+			 unsigned long size,
+			 const char *name,
+			 unsigned long *secsize);
+
+void rename_module(struct module *module,
+			  void *mod,
+			  unsigned long len,
+			  const char *newname);
+
+/* Kernel told to ignore these sections if SHF_ALLOC not set. */
+void invalidate_section32(void *mod, const char *secname);
+
+void invalidate_section64(void *mod, const char *secname);
+
+void strip_section(struct module *module,
+			  void *mod,
+			  unsigned long len,
+			  const char *secname);
+
+const char *next_string(const char *string, unsigned long *secsize);
+
+void clear_magic(struct module *module, void *mod, unsigned long len);
+
+struct module_options
+{
+	struct module_options *next;
+	char *modulename;
+	char *options;
+};
+
+struct module_command
+{
+	struct module_command *next;
+	char *modulename;
+	char *command;
+};
+
+struct module_alias
+{
+	struct module_alias *next;
+	char *module;
+};
+
+struct module_blacklist
+{
+	struct module_blacklist *next;
+	char *modulename;
+};
+
+struct module_options *
+add_options(const char *modname,
+	    const char *option,
+	    struct module_options *options);
+/* Link in a new install line from the config file. */
+struct module_command *
+add_command(const char *modname,
+	       const char *command,
+	    struct module_command *commands);
+
+/* Link in a new alias line from the config file. */
+struct module_alias *
+add_alias(const char *modname, struct module_alias *aliases);
+
+/* Link in a new blacklist line from the config file. */
+struct module_blacklist *
+add_blacklist(const char *modname, struct module_blacklist *blacklist);
+
+/* Find blacklist commands if any. */
+ int
+find_blacklist(const char *modname, const struct module_blacklist *blacklist);
+
+/* return a new alias list, with backlisted elems filtered out */
+struct module_alias *
+apply_blacklist(const struct module_alias *aliases,
+		const struct module_blacklist *blacklist);
+
+/* Find install commands if any. */
+const char *find_command(const char *modname,
+				const struct module_command *commands);
+
+char *append_option(char *options, const char *newoption);
+
+/* Add to options */
+char *add_extra_options(const char *modname,
+			       char *optstring,
+			       const struct module_options *options);
+
+/* If we don't flush, then child processes print before we do */
+void verbose_printf(int verbose, const char *fmt, ...);
+void do_command(const char *modname,
+		       const char *command,
+		       int verbose, int dry_run,
+		       errfn_t error,
+		       const char *type,
+		       const char *cmdline_opts);
+
+void insmod(struct list_head *list,
+		   char *optstring,
+		   const char *newname,
+		   int first_time,
+		   errfn_t error,
+		   int dry_run,
+		   int verbose,
+		   const struct module_options *options,
+		   const struct module_command *commands,
+		   int ignore_commands,
+		   int ignore_proc,
+		   int strip_vermagic,
+		   int strip_modversion,
+		   const char *cmdline_opts);
+
+void rmmod(struct list_head *list,
+		  const char *name,
+		  int first_time,
+		  errfn_t error,
+		  int dry_run,
+		  int verbose,
+		  struct module_command *commands,
+		  int ignore_commands,
+		  int ignore_inuse,
+		  const char *cmdline_opts);
+
+/* Does path contain directory(s) subpath? */
+int type_matches(const char *path, const char *subpath);
+
+/* Careful!  Don't munge - in [ ] as per Debian Bug#350915 */
+char *underscores(char *string);
+
+int do_wildcard(const char *dirname,
+		       const char *type,
+		       const char *wildcard);
+
+char *strsep_skipspace(char **string, char *delim);
+int read_config(const char *filename,
+		       const char *name,
+		       int dump_only,
+		       int removing,
+			    struct module_options **options,
+			    struct module_command **commands,
+			    struct module_alias **aliases,
+		       struct module_blacklist **blacklist);
+
+int read_config_file(const char *filename,
+			    const char *name,
+			    int dump_only,
+		       int removing,
+		       struct module_options **options,
+		       struct module_command **commands,
+		       struct module_alias **aliases,
+			    struct module_blacklist **blacklist);
+
+int read_config(const char *filename,
+		       const char *name,
+		       int dump_only,
+		       int removing,
+				 struct module_options **options,
+				 struct module_command **commands,
+				 struct module_alias **aliases,
+		       struct module_blacklist **blacklist);
+
+void read_toplevel_config(const char *filename,
+				 const char *name,
+				 int dump_only,
+				 int removing,
+				 struct module_options **options,
+				 struct module_command **commands,
+				 struct module_alias **aliases,
+				 struct module_blacklist **blacklist);
+
+void add_to_env_var(const char *option);
+
+/* Prepend options from environment. */
+char **merge_args(char *args, char *argv[], int *argc);
+
+char *gather_options(char *argv[]);
+
+void handle_module(const char *modname,
+			  struct list_head *todo_list,
+			  const char *newname,
+			  int remove,
+			  char *options,
+			  int first_time,
+			  errfn_t error,
+			  int dry_run,
+			  int verbose,
+			  struct module_options *modoptions,
+			  struct module_command *commands,
+			  int ignore_commands,
+			  int ignore_proc,
+			  int strip_vermagic,
+			  int strip_modversion,
+			  int unknown_silent,
+			  const char *cmdline_opts);
+
+/* This is a horrible hack to allow devfsd, which calls modprobe with
+   -C /etc/modules.conf or /etc/modules.devfs, to work.  FIXME. */
+/* Modern devfsd or variants should use -q explicitly in 2.6. */
+int is_devfs_call(char *argv[]);
+
+
+#define MODPROBE_DEVFSD_CONF "/etc/modprobe.devfs"
--- ./libmodprobe.c.lib	2007-08-13 17:54:42.000000000 +0200
+++ ./libmodprobe.c	2007-08-13 17:54:42.000000000 +0200
@@ -0,0 +1,1312 @@
+/* libmodprobe.c: add or remove a module from the kernel, intelligently.
+    Copyright (C) 2001  Rusty Russell.
+    Copyright (C) 2002, 2003  Rusty Russell, IBM Corporation.
+
+    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
+*/
+
+#include "zlibsupport.h"
+#include "backwards_compat.c"
+#include "modprobe.h"
+
+/* Do we use syslog or stderr for messages? */
+int log;
+
+void message(const char *prefix, const char *fmt, va_list *arglist)
+{
+	char *buf, *buf2;
+
+	vasprintf(&buf, fmt, *arglist);
+	asprintf(&buf2, "%s%s", prefix, buf);
+
+	if (log)
+		syslog(LOG_NOTICE, "%s", buf2);
+	else
+		fprintf(stderr, "%s", buf2);
+	free(buf2);
+	free(buf);
+}
+
+int warned = 0;
+void warn(const char *fmt, ...)
+{
+	va_list arglist;
+	warned++;
+	va_start(arglist, fmt);
+	message("WARNING: ", fmt, &arglist);
+	va_end(arglist);
+}
+
+void fatal(const char *fmt, ...)
+{
+	va_list arglist;
+	va_start(arglist, fmt);
+	message("FATAL: ", fmt, &arglist);
+	va_end(arglist);
+	exit(1);
+}
+
+
+void grammar(const char *cmd, const char *filename, unsigned int line)
+{
+	warn("%s line %u: ignoring bad line starting with '%s'\n",
+	     filename, line, cmd);
+}
+
+void *do_nofail(void *ptr, const char *file, int line, const char *expr)
+{
+	if (!ptr) {
+		fatal("Memory allocation failure %s line %d: %s.\n",
+		      file, line, expr);
+	}
+	return ptr;
+}
+
+void print_usage(const char *progname)
+{
+	fprintf(stderr,
+		"Usage: %s [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b] [-o <modname>] [ --dump-modversions ] <modname> [parameters...]\n"
+		"%s -r [-n] [-i] [-v] <modulename> ...\n"
+		"%s -l -t <dirname> [ -a <modulename> ...]\n",
+		progname, progname, progname);
+	exit(1);
+}
+
+int fgetc_wrapped(FILE *file, unsigned int *linenum)
+{
+	for (;;) {
+	  	int ch = fgetc(file);
+		if (ch != '\\')
+			return ch;
+		ch = fgetc(file);
+		if (ch != '\n')
+			return ch;
+		if (linenum)
+			(*linenum)++;
+	}
+}
+
+char *getline_wrapped(FILE *file, unsigned int *linenum)
+{
+	int size = 1024;
+	int i = 0;
+	char *buf = NOFAIL(malloc(size));
+	for(;;) {
+		int ch = fgetc_wrapped(file, linenum);
+		if (i == size) {
+			size *= 2;
+			buf = NOFAIL(realloc(buf, size));
+		}
+		if (ch < 0 && i == 0) {
+			free(buf);
+			return NULL;
+		}
+		if (ch < 0 || ch == '\n') {
+			if (linenum)
+				(*linenum)++;
+			buf[i] = '\0';
+			return NOFAIL(realloc(buf, i+1));
+		}
+		buf[i++] = ch;
+	}
+}
+
+struct module *find_module(const char *filename, struct list_head *list)
+{
+	struct module *i;
+
+	list_for_each_entry(i, list, list) {
+		if (strcmp(i->filename, filename) == 0)
+			return i;
+	}
+	return NULL;
+}
+
+/* Convert filename to the module name.  Works if filename == modname, too. */
+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';
+}
+
+int lock_file(const char *filename)
+{
+	int fd = open(filename, O_RDWR, 0);
+
+	if (fd >= 0) {
+		struct flock lock;
+		lock.l_type = F_WRLCK;
+		lock.l_whence = SEEK_SET;
+		lock.l_start = 0;
+		lock.l_len = 1;
+		fcntl(fd, F_SETLKW, &lock);
+	} else
+		/* Read-only filesystem?  There goes locking... */
+		fd = open(filename, O_RDONLY, 0);
+	return fd;
+}
+
+void unlock_file(int fd)
+{
+	/* Valgrind is picky... */
+	close(fd);
+}
+
+void add_module(char *filename, int namelen, struct list_head *list)
+{
+	struct module *mod;
+
+	/* If it's a duplicate: move it to the end, so it gets
+	   inserted where it is *first* required. */
+	mod = find_module(filename, list);
+	if (mod)
+		list_del(&mod->list);
+	else {
+		/* No match.  Create a new module. */
+		mod = NOFAIL(malloc(sizeof(struct module) + namelen + 1));
+		memcpy(mod->filename, filename, namelen);
+		mod->filename[namelen] = '\0';
+		mod->modname = NOFAIL(malloc(namelen + 1));
+		filename2modname(mod->modname, mod->filename);
+	}
+
+	list_add_tail(&mod->list, list);
+}
+
+/* Compare len chars of a to b, with _ and - equivalent. */
+int modname_equal(const char *a, const char *b, unsigned int len)
+{
+	unsigned int i;
+
+	if (strlen(b) != len)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		if ((a[i] == '_' || a[i] == '-')
+		    && (b[i] == '_' || b[i] == '-'))
+			continue;
+		if (a[i] != b[i])
+			return 0;
+	}
+	return 1;
+}
+
+/* Fills in list of modules if this is the line we want. */
+int add_modules_dep_line(char *line,
+				const char *name,
+				struct list_head *list)
+{
+	char *ptr;
+	int len;
+	char *modname;
+
+	/* Ignore lines without : or which start with a # */
+	ptr = strchr(line, ':');
+	if (ptr == NULL || line[strspn(line, "\t ")] == '#')
+		return 0;
+
+	/* Is this the module we are looking for? */
+	*ptr = '\0';
+	if (strrchr(line, '/'))
+		modname = strrchr(line, '/') + 1;
+	else
+		modname = line;
+
+	len = strlen(modname);
+	if (strchr(modname, '.'))
+		len = strchr(modname, '.') - modname;
+	if (!modname_equal(modname, name, len))
+		return 0;
+
+	/* Create the list. */
+	add_module(line, ptr - line, list);
+
+	ptr++;
+	for(;;) {
+		char *dep_start;
+		ptr += strspn(ptr, " \t");
+		if (*ptr == '\0')
+			break;
+		dep_start = ptr;
+		ptr += strcspn(ptr, " \t");
+		add_module(dep_start, ptr - dep_start, list);
+	}
+	return 1;
+}
+
+void read_depends(const char *dirname,
+			 const char *start_name,
+			 struct list_head *list)
+{
+	char *modules_dep_name;
+	char *line;
+	FILE *modules_dep;
+	int done = 0;
+
+	asprintf(&modules_dep_name, "%s/%s", dirname, "modules.dep");
+	modules_dep = fopen(modules_dep_name, "r");
+	if (!modules_dep)
+		fatal("Could not load %s: %s\n",
+		      modules_dep_name, strerror(errno));
+
+	/* Stop at first line, as we can have duplicates (eg. symlinks
+           from boot/ */
+	while (!done && (line = getline_wrapped(modules_dep, NULL)) != NULL) {
+		done = add_modules_dep_line(line, start_name, list);
+		free(line);
+	}
+	fclose(modules_dep);
+	free(modules_dep_name);
+}
+
+/* We use error numbers in a loose translation... */
+const char *insert_moderror(int err)
+{
+	switch (err) {
+	case ENOEXEC:
+		return "Invalid module format";
+	case ENOENT:
+		return "Unknown symbol in module, or unknown parameter (see dmesg)";
+	case ENOSYS:
+		return "Kernel does not have module support";
+	default:
+		return strerror(err);
+	}
+}
+
+const char *remove_moderror(int err)
+{
+	switch (err) {
+	case ENOENT:
+		return "No such module";
+	case ENOSYS:
+		return "Kernel does not have module unloading support";
+	default:
+		return strerror(err);
+	}
+}
+
+/* Is module in /proc/modules?  If so, fill in usecount if not NULL. 
+   0 means no, 1 means yes, -1 means unknown.
+ */
+int module_in_kernel(const char *modname, unsigned int *usecount)
+{
+	FILE *proc_modules;
+	char *line;
+
+again:
+	/* Might not be mounted yet.  Don't fail. */
+	proc_modules = fopen("/proc/modules", "r");
+	if (!proc_modules)
+		return -1;
+
+	while ((line = getline_wrapped(proc_modules, NULL)) != NULL) {
+		char *entry = strtok(line, " \n");
+
+		if (entry && streq(entry, modname)) {
+			/* If it exists, usecount is the third entry. */
+			if (!strtok(NULL, " \n"))
+				goto out;
+
+			if (!(entry = strtok(NULL, " \n"))) /* usecount */
+				goto out;
+			else
+				if (usecount)
+					*usecount = atoi(entry);
+
+			/* Followed by - then status. */
+			if (strtok(NULL, " \n")
+			    && (entry = strtok(NULL, " \n")) != NULL) {
+				/* Locking will fail on ro fs, we might hit
+				 * cases where module is in flux.  Spin. */
+				if (streq(entry, "Loading")
+				    || streq(entry, "Unloading")) {
+					usleep(100000);
+					free(line);
+					fclose(proc_modules);
+					goto again;
+				}
+			}
+
+		out:
+			free(line);
+			fclose(proc_modules);
+			return 1;
+		}
+		free(line);
+	}
+	fclose(proc_modules);
+	return 0;
+}
+
+void replace_modname(struct module *module,
+			    void *mem, unsigned long len,
+			    const char *oldname, const char *newname)
+{
+	char *p;
+
+	/* 64 - sizeof(unsigned long) - 1 */
+	if (strlen(newname) > 55)
+		fatal("New name %s is too long\n", newname);
+
+	/* Find where it is in the module structure.  Don't assume layout! */
+	for (p = mem; p < (char *)mem + len - strlen(oldname); p++) {
+		if (memcmp(p, oldname, strlen(oldname)) == 0) {
+			strcpy(p, newname);
+			return;
+		}
+	}
+
+	warn("Could not find old name in %s to replace!\n", module->filename);
+}
+
+void *get_section32(void *file,
+			   unsigned long size,
+			   const char *name,
+			   unsigned long *secsize)
+{
+	Elf32_Ehdr *hdr = file;
+	Elf32_Shdr *sechdrs = file + hdr->e_shoff;
+	const char *secnames;
+	unsigned int i;
+
+	/* Too short? */
+	if (size < sizeof(*hdr))
+		return NULL;
+	if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0]))
+		return NULL;
+	if (size < sechdrs[hdr->e_shstrndx].sh_offset)
+		return NULL;
+		
+	secnames = file + sechdrs[hdr->e_shstrndx].sh_offset;
+	for (i = 1; i < hdr->e_shnum; i++)
+		if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
+			*secsize = sechdrs[i].sh_size;
+			return file + sechdrs[i].sh_offset;
+		}
+	return NULL;
+}
+
+void *get_section64(void *file,
+			   unsigned long size,
+			   const char *name,
+			   unsigned long *secsize)
+{
+	Elf64_Ehdr *hdr = file;
+	Elf64_Shdr *sechdrs = file + hdr->e_shoff;
+	const char *secnames;
+	unsigned int i;
+
+	/* Too short? */
+	if (size < sizeof(*hdr))
+		return NULL;
+	if (size < hdr->e_shoff + hdr->e_shnum * sizeof(sechdrs[0]))
+		return NULL;
+	if (size < sechdrs[hdr->e_shstrndx].sh_offset)
+		return NULL;
+		
+	secnames = file + sechdrs[hdr->e_shstrndx].sh_offset;
+	for (i = 1; i < hdr->e_shnum; i++)
+		if (strcmp(secnames + sechdrs[i].sh_name, name) == 0) {
+			*secsize = sechdrs[i].sh_size;
+			return file + sechdrs[i].sh_offset;
+		}
+	return NULL;
+}
+
+int elf_ident(void *mod, unsigned long size)
+{
+	/* "\177ELF" <byte> where byte = 001 for 32-bit, 002 for 64 */
+	char *ident = mod;
+
+	if (size < EI_CLASS || memcmp(mod, ELFMAG, SELFMAG) != 0)
+		return ELFCLASSNONE;
+	return ident[EI_CLASS];
+}
+
+void *get_section(void *file,
+			 unsigned long size,
+			 const char *name,
+			 unsigned long *secsize)
+{
+	switch (elf_ident(file, size)) {
+	case ELFCLASS32:
+		return get_section32(file, size, name, secsize);
+	case ELFCLASS64:
+		return get_section64(file, size, name, secsize);
+	default:
+		return NULL;
+	}
+}
+
+void rename_module(struct module *module,
+			  void *mod,
+			  unsigned long len,
+			  const char *newname)
+{
+	void *modstruct;
+	unsigned long modstruct_len;
+
+	/* Old-style */
+	modstruct = get_section(mod, len, ".gnu.linkonce.this_module",
+				&modstruct_len);
+	/* New-style */
+	if (!modstruct)
+		modstruct = get_section(mod, len, "__module", &modstruct_len);
+	if (!modstruct)
+		warn("Could not find module name to change in %s\n",
+		     module->filename);
+	else
+		replace_modname(module, modstruct, modstruct_len,
+				module->modname, newname);
+}
+
+/* Kernel told to ignore these sections if SHF_ALLOC not set. */
+void invalidate_section32(void *mod, const char *secname)
+{
+	Elf32_Ehdr *hdr = mod;
+	Elf32_Shdr *sechdrs = mod + hdr->e_shoff;
+	const char *secnames = mod + sechdrs[hdr->e_shstrndx].sh_offset;
+	unsigned int i;
+
+	for (i = 1; i < hdr->e_shnum; i++)
+		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0)
+			sechdrs[i].sh_flags &= ~SHF_ALLOC;
+}
+
+void invalidate_section64(void *mod, const char *secname)
+{
+	Elf64_Ehdr *hdr = mod;
+	Elf64_Shdr *sechdrs = mod + hdr->e_shoff;
+	const char *secnames = mod + sechdrs[hdr->e_shstrndx].sh_offset;
+	unsigned int i;
+
+	for (i = 1; i < hdr->e_shnum; i++)
+		if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0)
+			sechdrs[i].sh_flags &= ~(unsigned long long)SHF_ALLOC;
+}
+
+void strip_section(struct module *module,
+			  void *mod,
+			  unsigned long len,
+			  const char *secname)
+{
+	switch (elf_ident(mod, len)) {
+	case ELFCLASS32:
+		invalidate_section32(mod, secname);
+		break;
+	case ELFCLASS64:
+		invalidate_section64(mod, secname);
+		break;
+	default:
+		warn("Unknown module format in %s: not forcing version\n",
+		     module->filename);
+	}
+}
+
+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;
+}
+
+void clear_magic(struct module *module, void *mod, unsigned long len)
+{
+	const char *p;
+	unsigned long modlen;
+
+	/* Old-style: __vermagic section */
+	strip_section(module, mod, len, "__vermagic");
+
+	/* New-style: in .modinfo section */
+	for (p = get_section(mod, len, ".modinfo", &modlen);
+	     p;
+	     p = next_string(p, &modlen)) {
+		if (strncmp(p, "vermagic=", strlen("vermagic=")) == 0) {
+			memset((char *)p, 0, strlen(p));
+			return;
+		}
+	}
+}
+
+/* Link in a new option line from the config file. */
+struct module_options *
+add_options(const char *modname,
+	    const char *option,
+	    struct module_options *options)
+{
+	struct module_options *new;
+	char *tab; 
+
+	new = NOFAIL(malloc(sizeof(*new)));
+	new->modulename = NOFAIL(strdup(modname));
+	new->options = NOFAIL(strdup(option));
+	/* We can handle tabs, kernel can't. */
+	for (tab = strchr(new->options, '\t'); tab; tab = strchr(tab, '\t'))
+		*tab = ' ';
+	new->next = options;
+	return new;
+}
+
+/* Link in a new install line from the config file. */
+struct module_command *
+add_command(const char *modname,
+	       const char *command,
+	       struct module_command *commands)
+{
+	struct module_command *new;
+
+	new = NOFAIL(malloc(sizeof(*new)));
+	new->modulename = NOFAIL(strdup(modname));
+	new->command = NOFAIL(strdup(command));
+	new->next = commands;
+	return new;
+}
+
+/* Link in a new alias line from the config file. */
+struct module_alias *
+add_alias(const char *modname, struct module_alias *aliases)
+{
+	struct module_alias *new;
+
+	new = NOFAIL(malloc(sizeof(*new)));
+	new->module = NOFAIL(strdup(modname));
+	new->next = aliases;
+	return new;
+}
+
+/* Link in a new blacklist line from the config file. */
+struct module_blacklist *
+add_blacklist(const char *modname, struct module_blacklist *blacklist)
+{
+	struct module_blacklist *new;
+
+	new = NOFAIL(malloc(sizeof(*new)));
+	new->modulename = NOFAIL(strdup(modname));
+	new->next = blacklist;
+	return new;
+}
+
+/* Find blacklist commands if any. */
+ int
+find_blacklist(const char *modname, const struct module_blacklist *blacklist)
+{
+	while (blacklist) {
+		if (strcmp(blacklist->modulename, modname) == 0)
+			return 1;
+		blacklist = blacklist->next;
+	}
+	return 0;
+}
+
+/* return a new alias list, with backlisted elems filtered out */
+struct module_alias *
+apply_blacklist(const struct module_alias *aliases,
+		const struct module_blacklist *blacklist)
+{
+	struct module_alias *result = NULL;
+	while (aliases) {
+		char *modname = aliases->module;
+		if (!find_blacklist(modname, blacklist))
+			result = add_alias(modname, result);
+		aliases = aliases->next;
+	}
+	return result;
+}
+
+/* Find install commands if any. */
+const char *find_command(const char *modname,
+				const struct module_command *commands)
+{
+	while (commands) {
+		if (fnmatch(commands->modulename, modname, 0) == 0)
+			return commands->command;
+		commands = commands->next;
+	}
+	return NULL;
+}
+
+char *append_option(char *options, const char *newoption)
+{
+	options = NOFAIL(realloc(options, strlen(options) + 1
+				 + strlen(newoption) + 1));
+	if (strlen(options)) strcat(options, " ");
+	strcat(options, newoption);
+	return options;
+}
+
+/* Add to options */
+char *add_extra_options(const char *modname,
+			       char *optstring,
+			       const struct module_options *options)
+{
+	while (options) {
+		if (strcmp(options->modulename, modname) == 0)
+			optstring = append_option(optstring, options->options);
+		options = options->next;
+	}
+	return optstring;
+}
+
+/* If we don't flush, then child processes print before we do */
+void verbose_printf(int verbose, const char *fmt, ...)
+{
+	va_list arglist;
+
+	if (verbose) {
+		va_start(arglist, fmt);
+		vprintf(fmt, arglist);
+		fflush(stdout);
+		va_end(arglist);
+	}
+}
+
+/* Do an install/remove command: replace $CMDLINE_OPTS if it's specified. */
+void do_command(const char *modname,
+		       const char *command,
+		       int verbose, int dry_run,
+		       errfn_t error,
+		       const char *type,
+		       const char *cmdline_opts)
+{
+	int ret;
+	char *p, *replaced_cmd = NOFAIL(strdup(command));
+
+	while ((p = strstr(replaced_cmd, "$CMDLINE_OPTS")) != NULL) {
+		char *new;
+		asprintf(&new, "%.*s%s%s",
+			 (int)(p - replaced_cmd), replaced_cmd, cmdline_opts,
+			 p + strlen("$CMDLINE_OPTS"));
+		NOFAIL(new);
+		free(replaced_cmd);
+		replaced_cmd = new;
+	}
+
+	verbose_printf(verbose, "%s %s\n", type, replaced_cmd);
+	if (dry_run)
+		return;
+
+	setenv("MODPROBE_MODULE", modname, 1);
+	ret = system(replaced_cmd);
+	if (ret == -1 || WEXITSTATUS(ret))
+		error("Error running %s command for %s\n", type, modname);
+	free(replaced_cmd);
+}
+
+/* Actually do the insert.  Frees second arg. */
+void insmod(struct list_head *list,
+		   char *optstring,
+		   const char *newname,
+		   int first_time,
+		   errfn_t error,
+		   int dry_run,
+		   int verbose,
+		   const struct module_options *options,
+		   const struct module_command *commands,
+		   int ignore_commands,
+		   int ignore_proc,
+		   int strip_vermagic,
+		   int strip_modversion,
+		   const char *cmdline_opts)
+{
+	int ret, fd;
+	unsigned long len;
+	void *map;
+	const char *command;
+	struct module *mod = list_entry(list->next, struct module, list);
+
+	/* Take us off the list. */
+	list_del(&mod->list);
+
+	/* Do things we (or parent) depend on first, but don't die if
+	 * they fail. */
+	if (!list_empty(list)) {
+		insmod(list, NOFAIL(strdup("")), NULL, 0, warn,
+		       dry_run, verbose, options, commands, 0, ignore_proc,
+		       strip_vermagic, strip_modversion, "");
+	}
+
+	/* Lock before we look, in case it's initializing. */
+	fd = lock_file(mod->filename);
+	if (fd < 0) {
+		error("Could not open '%s': %s\n",
+		      mod->filename, strerror(errno));
+		goto out_optstring;
+	}
+
+	/* Don't do ANYTHING if already in kernel. */
+	if (!ignore_proc
+	    && module_in_kernel(newname ?: mod->modname, NULL) == 1) {
+		if (first_time)
+			error("Module %s already in kernel.\n",
+			      newname ?: mod->modname);
+		goto out_unlock;
+	}
+
+	command = find_command(mod->modname, commands);
+	if (command && !ignore_commands) {
+		/* It might recurse: unlock. */
+		unlock_file(fd);
+		do_command(mod->modname, command, verbose, dry_run, error,
+			   "install", cmdline_opts);
+		goto out_optstring;
+	}
+
+	map = grab_fd(fd, &len);
+	if (!map) {
+		error("Could not read '%s': %s\n",
+		      mod->filename, strerror(errno));
+		goto out_unlock;
+	}
+
+	/* Rename it? */
+	if (newname)
+		rename_module(mod, map, len, newname);
+
+	if (strip_modversion)
+		strip_section(mod, map, len, "__versions");
+	if (strip_vermagic)
+		clear_magic(mod, map, len);
+
+	/* Config file might have given more options */
+	optstring = add_extra_options(mod->modname, optstring, options);
+
+	verbose_printf(verbose, "insmod %s %s\n", mod->filename, optstring);
+
+	if (dry_run)
+		goto out;
+
+	ret = init_module(map, len, optstring);
+	if (ret != 0) {
+		if (errno == EEXIST) {
+			if (first_time)
+				error("Module %s already in kernel.\n",
+				      newname ?: mod->modname);
+			goto out_unlock;
+		}
+		error("Error inserting %s (%s): %s\n",
+		      mod->modname, mod->filename, insert_moderror(errno));
+	}
+ out:
+	release_file(map, len);
+ out_unlock:
+	unlock_file(fd);
+ out_optstring:
+	free(optstring);
+	return;
+}
+
+/* Do recursive removal. */
+void rmmod(struct list_head *list,
+		  const char *name,
+		  int first_time,
+		  errfn_t error,
+		  int dry_run,
+		  int verbose,
+		  struct module_command *commands,
+		  int ignore_commands,
+		  int ignore_inuse,
+		  const char *cmdline_opts)
+{
+	const char *command;
+	unsigned int usecount = 0;
+	int lock;
+	struct module *mod = list_entry(list->next, struct module, list);
+
+	/* Take first one off the list. */
+	list_del(&mod->list);
+
+	/* Ignore failure; it's best effort here. */
+	lock = lock_file(mod->filename);
+
+	if (!name)
+		name = mod->modname;
+
+	/* Even if renamed, find commands to orig. name. */
+	command = find_command(mod->modname, commands);
+	if (command && !ignore_commands) {
+		/* It might recurse: unlock. */
+		unlock_file(lock);
+		do_command(mod->modname, command, verbose, dry_run, error,
+			   "remove", cmdline_opts);
+		goto remove_rest_no_unlock;
+	}
+
+	if (module_in_kernel(name, &usecount) == 0)
+		goto nonexistent_module;
+
+	if (usecount != 0) {
+		if (!ignore_inuse)
+			error("Module %s is in use.\n", name);
+		goto remove_rest;
+	}
+
+	verbose_printf(verbose, "rmmod %s\n", mod->filename);
+
+	if (dry_run)
+		goto remove_rest;
+
+	if (delete_module(name, O_EXCL) != 0) {
+		if (errno == ENOENT)
+			goto nonexistent_module;
+		error("Error removing %s (%s): %s\n",
+		      name, mod->filename,
+		      remove_moderror(errno));
+	}
+
+ remove_rest:
+	unlock_file(lock);
+ remove_rest_no_unlock:
+	/* Now do things we depend. */
+	if (!list_empty(list))
+		rmmod(list, NULL, 0, warn, dry_run, verbose, commands,
+		      0, 1, "");
+	return;
+
+nonexistent_module:
+	if (first_time)
+		fatal("Module %s is not in kernel.\n", mod->modname);
+	goto remove_rest;
+}
+
+/* Does path contain directory(s) subpath? */
+int type_matches(const char *path, const char *subpath)
+{
+	char *subpath_with_slashes;
+	int ret;
+
+	asprintf(&subpath_with_slashes, "/%s/", subpath);
+	NOFAIL(subpath_with_slashes);
+
+	ret = (strstr(path, subpath_with_slashes) != NULL);
+	free(subpath_with_slashes);
+	return ret;
+}
+
+/* Careful!  Don't munge - in [ ] as per Debian Bug#350915 */
+char *underscores(char *string)
+{
+	if (string) {
+		unsigned int i;
+		int inbracket = 0;
+		for (i = 0; string[i]; i++) {
+			switch (string[i]) {
+			case '[':
+				inbracket++;
+				break;
+			case ']':
+				inbracket--;
+				break;
+			case '-':
+				if (!inbracket)
+					string[i] = '_';
+			}
+		}
+		if (inbracket)
+			warn("Unmatched bracket in %s\n", string);
+	}
+	return string;
+}
+
+int do_wildcard(const char *dirname,
+		       const char *type,
+		       const char *wildcard)
+{
+	char modules_dep_name[strlen(dirname) + sizeof("modules.dep") + 1];
+	char *line, *wcard;
+	FILE *modules_dep;
+
+	/* Canonicalize wildcard */
+	wcard = strdup(wildcard);
+	underscores(wcard);
+
+	sprintf(modules_dep_name, "%s/%s", dirname, "modules.dep");
+	modules_dep = fopen(modules_dep_name, "r");
+	if (!modules_dep)
+		fatal("Could not load %s: %s\n",
+		      modules_dep_name, strerror(errno));
+
+	while ((line = getline_wrapped(modules_dep, NULL)) != NULL) {
+		char *ptr;
+
+		/* Ignore lines without : or which start with a # */
+		ptr = strchr(line, ':');
+		if (ptr == NULL || line[strspn(line, "\t ")] == '#')
+			goto next;
+		*ptr = '\0';
+
+		/* "type" must match complete directory component(s). */
+		if (!type || type_matches(line, type)) {
+			char modname[strlen(line)+1];
+
+			filename2modname(modname, line);
+			if (fnmatch(wcard, modname, 0) == 0)
+				printf("%s\n", line);
+		}
+	next:
+		free(line);
+	}
+
+	free(wcard);
+	return 0;
+}
+
+char *strsep_skipspace(char **string, char *delim)
+{
+	if (!*string)
+		return NULL;
+	*string += strspn(*string, delim);
+	return strsep(string, delim);
+}
+
+/* Recursion */
+int read_config(const char *filename,
+		       const char *name,
+		       int dump_only,
+		       int removing,
+		       struct module_options **options,
+		       struct module_command **commands,
+		       struct module_alias **alias,
+		       struct module_blacklist **blacklist);
+
+/* FIXME: Maybe should be extended to "alias a b [and|or c]...". --RR */
+int read_config_file(const char *filename,
+			    const char *name,
+			    int dump_only,
+			    int removing,
+			    struct module_options **options,
+			    struct module_command **commands,
+			    struct module_alias **aliases,
+			    struct module_blacklist **blacklist)
+{
+	char *line;
+	unsigned int linenum = 0;
+	FILE *cfile;
+
+	cfile = fopen(filename, "r");
+	if (!cfile)
+		return 0;
+
+	while ((line = getline_wrapped(cfile, &linenum)) != NULL) {
+		char *ptr = line;
+		char *cmd, *modname;
+
+		if (dump_only)
+			printf("%s\n", line);
+
+		cmd = strsep_skipspace(&ptr, "\t ");
+		if (cmd == NULL || cmd[0] == '#' || cmd[0] == '\0')
+			continue;
+
+		if (strcmp(cmd, "alias") == 0) {
+			char *wildcard
+				= underscores(strsep_skipspace(&ptr, "\t "));
+			char *realname
+				= underscores(strsep_skipspace(&ptr, "\t "));
+
+			if (!wildcard || !realname)
+				grammar(cmd, filename, linenum);
+			else if (fnmatch(wildcard,name,0) == 0)
+				*aliases = add_alias(realname, *aliases);
+		} else if (strcmp(cmd, "include") == 0) {
+			struct module_alias *newalias = NULL;
+			char *newfilename;
+
+			newfilename = strsep_skipspace(&ptr, "\t ");
+			if (!newfilename)
+				grammar(cmd, filename, linenum);
+			else {
+				if (!read_config(newfilename, name,
+						 dump_only, removing,
+						 options, commands, &newalias,
+						 blacklist))
+					warn("Failed to open included"
+					      " config file %s: %s\n",
+					      newfilename, strerror(errno));
+
+				/* Files included override aliases,
+				   etc that was already set ... */
+				if (newalias)
+					*aliases = newalias;
+			}
+		} else if (strcmp(cmd, "options") == 0) {
+			modname = strsep_skipspace(&ptr, "\t ");
+			if (!modname || !ptr)
+				grammar(cmd, filename, linenum);
+			else {
+				ptr += strspn(ptr, "\t ");
+				*options = add_options(underscores(modname),
+						       ptr, *options);
+			}
+		} else if (strcmp(cmd, "install") == 0) {
+			modname = strsep_skipspace(&ptr, "\t ");
+			if (!modname || !ptr)
+				grammar(cmd, filename, linenum);
+			else if (!removing) {
+				ptr += strspn(ptr, "\t ");
+				*commands = add_command(underscores(modname),
+							ptr, *commands);
+			}
+		} else if (strcmp(cmd, "blacklist") == 0) {
+			modname = strsep_skipspace(&ptr, "\t ");
+			if (!modname)
+				grammar(cmd, filename, linenum);
+			else if (!removing) {
+				*blacklist = add_blacklist(underscores(modname),
+							*blacklist);
+			}
+		} else if (strcmp(cmd, "remove") == 0) {
+			modname = strsep_skipspace(&ptr, "\t ");
+			if (!modname || !ptr)
+				grammar(cmd, filename, linenum);
+			else if (removing) {
+				ptr += strspn(ptr, "\t ");
+				*commands = add_command(underscores(modname),
+							ptr, *commands);
+			}
+		} else
+			grammar(cmd, filename, linenum);
+
+		free(line);
+	}
+	fclose(cfile);
+	return 1;
+}
+
+/* Simple format, ignore lines starting with #, one command per line.
+   Returns true or false. */
+int read_config(const char *filename,
+		       const char *name,
+		       int dump_only,
+		       int removing,
+		       struct module_options **options,
+		       struct module_command **commands,
+		       struct module_alias **aliases,
+		       struct module_blacklist **blacklist)
+{
+	DIR *dir;
+	int ret = 0;
+
+	/* Reiser4 has file/directory duality: treat it as both. */
+	dir = opendir(filename);
+	if (dir) {
+		struct dirent *i;
+		while ((i = readdir(dir)) != NULL) {
+			if (!streq(i->d_name,".") && !streq(i->d_name,"..")) {
+				char sub[strlen(filename) + 1
+					 + strlen(i->d_name) + 1];
+
+				sprintf(sub, "%s/%s", filename, i->d_name);
+				if (!read_config(sub, name,
+						 dump_only, removing, options,
+						 commands, aliases, blacklist))
+					warn("Failed to open"
+					     " config file %s: %s\n",
+					     sub, strerror(errno));
+			}
+		}
+		closedir(dir);
+		ret = 1;
+	}
+
+	if (read_config_file(filename, name, dump_only, removing,
+			     options, commands, aliases, blacklist))
+		ret = 1;
+
+	return ret;
+}
+
+const char *default_configs[] = 
+{
+	"/etc/modprobe.conf",
+	"/etc/modprobe.d",
+};
+
+void read_toplevel_config(const char *filename,
+				 const char *name,
+				 int dump_only,
+				 int removing,
+				 struct module_options **options,
+				 struct module_command **commands,
+				 struct module_alias **aliases,
+				 struct module_blacklist **blacklist)
+{
+	unsigned int i;
+
+	if (filename) {
+		if (!read_config(filename, name, dump_only, removing,
+				 options, commands, aliases, blacklist))
+			fatal("Failed to open config file %s: %s\n",
+			      filename, strerror(errno));
+		return;
+	}
+
+	/* Try defaults. */
+	for (i = 0; i < ARRAY_SIZE(default_configs); i++) {
+		if (read_config(default_configs[i], name, dump_only, removing,
+				options, commands, aliases, blacklist))
+			return;
+	}
+}
+
+void add_to_env_var(const char *option)
+{
+	const char *oldenv;
+
+	if ((oldenv = getenv("MODPROBE_OPTIONS")) != NULL) {
+		char *newenv;
+		asprintf(&newenv, "%s %s", oldenv, option);
+		setenv("MODPROBE_OPTIONS", newenv, 1);
+	} else
+		setenv("MODPROBE_OPTIONS", option, 1);
+}
+
+/* Prepend options from environment. */
+char **merge_args(char *args, char *argv[], int *argc)
+{
+	char *arg, *argstring;
+	char **newargs = NULL;
+	unsigned int i, num_env = 0;
+
+	if (!args)
+		return argv;
+
+	argstring = NOFAIL(strdup(args));
+	for (arg = strtok(argstring, " "); arg; arg = strtok(NULL, " ")) {
+		num_env++;
+		newargs = NOFAIL(realloc(newargs,
+					 sizeof(newargs[0])
+					 * (num_env + *argc + 1)));
+		newargs[num_env] = arg;
+	}
+
+	/* Append commandline args */
+	newargs[0] = argv[0];
+	for (i = 1; i <= *argc; i++)
+		newargs[num_env+i] = argv[i];
+
+	*argc += num_env;
+	return newargs;
+}
+
+char *gather_options(char *argv[])
+{
+	char *optstring = NOFAIL(strdup(""));
+
+	/* Rest is module options */
+	while (*argv) {
+		/* Quote value if it contains spaces. */
+		unsigned int eq = strcspn(*argv, "=");
+
+		if (strchr(*argv+eq, ' ') && !strchr(*argv, '"')) {
+			char quoted[strlen(*argv) + 3];
+			(*argv)[eq] = '\0';
+			sprintf(quoted, "%s=\"%s\"", *argv, *argv+eq+1);
+			optstring = append_option(optstring, quoted);
+		} else
+			optstring = append_option(optstring, *argv);
+		argv++;
+	}
+	return optstring;
+}
+
+void handle_module(const char *modname,
+			  struct list_head *todo_list,
+			  const char *newname,
+			  int remove,
+			  char *options,
+			  int first_time,
+			  errfn_t error,
+			  int dry_run,
+			  int verbose,
+			  struct module_options *modoptions,
+			  struct module_command *commands,
+			  int ignore_commands,
+			  int ignore_proc,
+			  int strip_vermagic,
+			  int strip_modversion,
+			  int unknown_silent,
+			  const char *cmdline_opts)
+{
+	if (list_empty(todo_list)) {
+		const char *command;
+
+		/* The dependencies have to be real modules, but
+		   handle case where the first is completely bogus. */
+		command = find_command(modname, commands);
+		if (command && !ignore_commands) {
+			do_command(modname, command, verbose, dry_run, error,
+				   remove ? "remove":"install", cmdline_opts);
+			return;
+		}
+
+		if (unknown_silent)
+			exit(1);
+		error("Module %s not found.\n", modname);
+		return;
+	}
+
+	if (remove)
+		rmmod(todo_list, newname, first_time, error, dry_run, verbose,
+		      commands, ignore_commands, 0, cmdline_opts);
+	else
+		insmod(todo_list, NOFAIL(strdup(options)), newname,
+		       first_time, error, dry_run, verbose, modoptions,
+		       commands, ignore_commands, ignore_proc, strip_vermagic,
+		       strip_modversion, cmdline_opts);
+}
+
+/* This is a horrible hack to allow devfsd, which calls modprobe with
+   -C /etc/modules.conf or /etc/modules.devfs, to work.  FIXME. */
+/* Modern devfsd or variants should use -q explicitly in 2.6. */
+int is_devfs_call(char *argv[])
+{
+	unsigned int i;
+
+	/* Look for "/dev" arg */
+	for (i = 1; argv[i]; i++) {
+		if (strncmp(argv[i], "/dev/", 5) == 0)
+			return 1;
+	}
+	return 0;
+}
+
--- ./Makefile.am.lib	2007-03-22 08:36:02.000000000 +0100
+++ ./Makefile.am	2007-08-13 18:24:53.000000000 +0200
@@ -1,9 +1,21 @@
+# Build a libtool library, libmodprobe.la for installation in libdir.
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
+libtool: $(LIBTOOL_DEPS)
+	$(SHELL) ./config.status --recheck
+
+lib_LTLIBRARIES = libmodprobe.la
+libmodprobe_la_SOURCES = libmodprobe.c zlibsupport.c zlibsupport.h
+libmodprobe_la_LDFLAGS = -version-info 0:0:0 -lz
+
 insmod_SOURCES = insmod.c testing.h
 lsmod_SOURCES = lsmod.c testing.h
-modprobe_SOURCES = modprobe.c zlibsupport.c testing.h zlibsupport.h
+modprobe_SOURCES = modprobe.c testing.h zlibsupport.h
+modprobe_LDFLAGS = -lmodprobe
 rmmod_SOURCES = rmmod.c testing.h
-depmod_SOURCES = depmod.c moduleops.c tables.c zlibsupport.c depmod.h moduleops.h tables.h list.h testing.h  zlibsupport.h
-modinfo_SOURCES = modinfo.c zlibsupport.c testing.h zlibsupport.h
+depmod_SOURCES = depmod.c moduleops.c tables.c depmod.h moduleops.h tables.h list.h testing.h  zlibsupport.h
+depmod_LDFLAGS = -lmodprobe
+modinfo_SOURCES = modinfo.c testing.h zlibsupport.h
+modinfo_LDFLAGS = -lmodprobe
 
 insmod_static_SOURCES = insmod.c
 insmod_static_LDFLAGS = -static
--- ./configure.ac.lib	2007-08-13 17:57:52.000000000 +0200
+++ ./configure.ac	2007-08-13 18:07:42.000000000 +0200
@@ -2,6 +2,10 @@ AC_INIT
 
 AC_CANONICAL_SYSTEM
 
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+
+
 AM_INIT_AUTOMAKE(module-init-tools, "3.3-pre11")
 
 # If zlib is required, libz must be linked static, modprobe is in