diff options
Diffstat (limited to 'mdk-stage1/modules.c')
| -rw-r--r-- | mdk-stage1/modules.c | 483 | 
1 files changed, 253 insertions, 230 deletions
| diff --git a/mdk-stage1/modules.c b/mdk-stage1/modules.c index 210579c62..76177302e 100644 --- a/mdk-stage1/modules.c +++ b/mdk-stage1/modules.c @@ -1,7 +1,7 @@  /* - * Guillaume Cottenceau (gc@mandrakesoft.com) + * Guillaume Cottenceau (gc)   * - * Copyright 2000 MandrakeSoft + * Copyright 2000 Mandriva   *   * This software may be freely redistributed under the terms of the GNU   * public license. @@ -18,108 +18,130 @@   * (3) insmod them   */ +#include "stage1.h" +  #include <stdlib.h>  #include <sys/types.h>  #include <sys/stat.h>  #include <sys/mount.h>  #include <fcntl.h> +#include <libgen.h>  #include <unistd.h>  #include <string.h>  #include <stdio.h> -#include "insmod.h" -#include "stage1.h" +#include <errno.h> +#include <time.h> +#include <sys/utsname.h> +#include <libkmod.h>  #include "log.h" -#include "mar/mar-extract-only.h" +#include "utils.h"  #include "frontend.h"  #include "mount.h" -#include "modules_descr.h" +#include "zlibsupport.h"  #include "modules.h" -static struct module_deps_elem * modules_deps = NULL; - -static char * archive_name = "/modules/modules.mar"; -int disable_modules = 0; +static char modules_directory[100]; +static struct module_descr_elem * modules_descr = NULL; +extern long init_module(void *, unsigned long, const char *); -/* unarchive and insmod given module - * WARNING: module must not contain the trailing ".o" - */ -static enum insmod_return insmod_archived_file(const char * mod_name, char * options) +static const char *moderror(int err)  { -	char module_name[50]; -	char final_name[50] = "/tmp/"; -	int i, rc; - -	strncpy(module_name, mod_name, sizeof(module_name)); -	strcat(module_name, ".o"); -	i = mar_extract_file(archive_name, module_name, "/tmp/"); -	if (i == 1) { -		log_message("file-not-found-in-archive %s (maybe you can try another boot floppy such as 'hdcdrom_usb.img' or 'network_gigabit_usb.img')", module_name); -		return INSMOD_FAILED_FILE_NOT_FOUND; +	switch (err) { +	case ENOEXEC: +		return "Invalid module format"; +	case ENOENT: +		return "Unknown symbol in module"; +	case ESRCH: +		return "Module has wrong symbol version"; +	case EINVAL: +		return "Invalid parameters"; +	default: +		return strerror(err);  	} -	if (i != 0) -		return INSMOD_FAILED; +} -	strcat(final_name, mod_name); -	strcat(final_name, ".o"); +int insmod_local_file(char * path, char * options) +{ +	void *file; +	unsigned long len; +	int rc; +                 +	if (IS_TESTING) +		return 0; -	rc = insmod_call(final_name, options); -	unlink(final_name); /* sucking no space left on device */ -	if (rc) { -		log_message("\tfailed"); -		return INSMOD_FAILED; +	file = grab_file(path, &len); +                 +	if (!file) { +		log_perror(asprintf_("\terror reading %s", path)); +		return -1;  	} -	return INSMOD_OK; +                 +	rc = init_module(file, len, options ? options : ""); +	if (rc) +		log_message("\terror: %s", moderror(errno)); +	return rc;  } - - -static int load_modules_dependencies(void) +static char *kernel_module_extension(void)  { -	char * deps_file = "/modules/modules.dep"; -	char * buf, * ptr, * start, * end; -	struct stat s; -	int fd, line, i; +	return ".ko.xz"; +} -	log_message("loading modules dependencies"); -	if (IS_TESTING) -		return 0; +static char *filename2modname(char * filename) { +	char *modname, *p; -	fd = open(deps_file, O_RDONLY); -	if (fd == -1) { -		log_perror(deps_file); -		return -1; +	modname = strdup(basename(filename)); +	if (strstr(modname, kernel_module_extension())) { +		modname[strlen(modname)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */  	} -	 -	fstat(fd, &s); -	buf = alloca(s.st_size + 1); -	if (read(fd, buf, s.st_size) != (ssize_t)s.st_size) { -		log_perror(deps_file); -		return -1; + +	p = modname; +	while (p && *p) { +		if (*p == '-') +			*p = '_'; +		p++;  	} -	buf[s.st_size] = '\0'; -	close(fd); -	ptr = buf; -	line = 0; -	while (ptr) { -		line++; -		ptr = strchr(ptr + 1, '\n'); +	return modname; +} + +static void find_modules_directory(void) +{ +	struct utsname kernel_uname; +	char * prefix = "/lib/modules"; +	char * release; +	if (uname(&kernel_uname)) { +		fatal_error("uname failed");  	} +	release = kernel_uname.release; +	sprintf(modules_directory , "%s/%s", prefix, release); +} + +static int load_modules_descriptions(void) +{ +	char * descr_file = asprintf_("%s/%s", modules_directory, "modules.description"); +	char * buf, * ptr, * start, * end; +	struct stat s; +	int line; -	modules_deps = malloc(sizeof(*modules_deps) * (line+1)); +	log_message("loading modules descriptions"); + +	buf = cat_file(descr_file, &s); +	if (!buf) +		return -1; +	line = line_counts(buf); +	modules_descr = malloc(sizeof(*modules_descr) * (line+1));  	start = buf;  	line = 0;  	while (start < (buf+s.st_size) && *start) { -		char * tmp_deps[50]; -  		end = strchr(start, '\n');  		*end = '\0'; -		ptr = strchr(start, ':'); +		ptr = strchr(start, '\t');  		if (!ptr) {  			start = end + 1;  			continue; @@ -127,46 +149,24 @@ static int load_modules_dependencies(void)  		*ptr = '\0';  		ptr++; -		while (*ptr && (*ptr == ' ')) ptr++; -		if (!*ptr) { -			start = end + 1; -			continue; -		} - -		/* sort of a good line */ -		modules_deps[line].name = strdup(start); - -		start = ptr; -		i = 0; -		while (start && *start) { -			ptr = strchr(start, ' '); -			if (ptr) *ptr = '\0'; -			tmp_deps[i++] = strdup(start); -			if (ptr) -				start = ptr + 1; -			else -				start = NULL; -			while (start && *start && *start == ' ') -				start++; -		} -		tmp_deps[i++] = NULL; - -		modules_deps[line].deps = memdup(tmp_deps, sizeof(char *) * i); +		modules_descr[line].modname = filename2modname(start); +		modules_descr[line].description = strndup(ptr, 50);  		line++;  		start = end + 1;  	} -	modules_deps[line].name = NULL; +	modules_descr[line].modname = NULL; + +	free(buf);  	return 0;  } -  void init_modules_insmoding(void)  { -	if (load_modules_dependencies()) { -		log_message("warning, error initing modules stuff, modules loading disabled"); -		disable_modules = 1; +	find_modules_directory(); +	if (load_modules_descriptions()) { +		log_message("warning, error initing modules stuff");  	}  } @@ -174,7 +174,7 @@ void init_modules_insmoding(void)  static void add_modules_conf(char * str)  {  	static char data[5000] = ""; -	char * target = "/etc/modules.conf"; +	char * target = "/tmp/modules.conf";  	int fd;  	if (strlen(data) + strlen(str) >= sizeof(data)) @@ -200,7 +200,10 @@ static void add_modules_conf(char * str)  int module_already_present(const char * name)  {  	FILE * f; +	struct stat sb; +	char *path;  	int answ = 0; +  	if ((f = fopen("/proc/modules", "rb"))) {                  while (1) {                          char buf[500]; @@ -210,40 +213,109 @@ int module_already_present(const char * name)                  }                  fclose(f);          } + +	/* built-in module case. try to find them through sysfs */ +	if (!answ) { +		asprintf(&path, "/sys/module/%s", name); +		if (!stat(path, &sb)) +			answ = 1; +		free(path); +	} +	if (!answ) { +		asprintf(&path, "/sys/fs/%s", name); +		if (!stat(path, &sb)) +			answ = 1; +		free(path); +	}  	return answ;  } -static enum insmod_return insmod_with_deps(const char * mod_name, char * options) -{ -	struct module_deps_elem * dep; - -	dep = modules_deps; -	while (dep && dep->name && strcmp(dep->name, mod_name)) dep++; - -	if (dep && dep->name && dep->deps) { -		char ** one_dep; -		one_dep = dep->deps; -		while (*one_dep) { -			/* here, we can fail but we don't care, if the error is -			 * important, the desired module will fail also */ -			insmod_with_deps(*one_dep, NULL); -			one_dep++; +#ifndef ENABLE_NETWORK_STANDALONE +static enum insmod_return insmod_with_deps(const char * alias, char * options) { +	struct kmod_ctx *ctx; +	struct kmod_list *l, *list = NULL; +	int err = 0, flags = 0; + +	if (!*modules_directory) +		find_modules_directory(); + +	ctx = kmod_new(modules_directory, NULL); +	if (!ctx) { +		fputs("Error: kmod_new() failed!\n", stderr); +		goto exit; +	} +	kmod_load_resources(ctx); + +	err = kmod_module_new_from_lookup(ctx, alias, &list); +	if (err < 0) +		goto exit; + +	// No module found... +	if (list == NULL) +		goto exit; + +	// filter through blacklist +	struct kmod_list *filtered = NULL; +	err =  kmod_module_apply_filter(ctx, KMOD_FILTER_BLACKLIST, list, &filtered); +	kmod_module_unref_list(list); +	if (err < 0) +		goto exit; +	list = filtered; + +	kmod_list_foreach(l, list) { +		struct kmod_module *mod = kmod_module_get_module(l); +		err = kmod_module_probe_insert_module(mod, flags, +				options, NULL, NULL, NULL); + +		if (err >= 0) +			/* ignore flag return values such as a mod being blacklisted */ +			err = 0; +		else { +			switch (err) { +			    case -EEXIST: +				fprintf(stderr, "could not insert '%s': Module already in kernel\n", +						kmod_module_get_name(mod)); +				break; +			    case -ENOENT: +				fprintf(stderr, "could not insert '%s': Unknown symbol in module, " +						"or unknown parameter (see dmesg)\n", +						kmod_module_get_name(mod)); +				break; +			    default: +				fprintf(stderr, "could not insert '%s': %s\n", +						kmod_module_get_name(mod), +						strerror(-err)); +				break; +			}  		} + +		kmod_module_unref(mod); +		if (err < 0) +			break;  	} -	if (module_already_present(mod_name)) -		return INSMOD_OK; +	kmod_module_unref_list(list); -	log_message("needs %s", mod_name); -	return insmod_archived_file(mod_name, options); +exit: +	kmod_unref(ctx); + +	switch (err){ +	    case 0: +		return INSMOD_OK; +	    case -ENOENT: +		return INSMOD_FAILED_FILE_NOT_FOUND; +	    default: +		return INSMOD_FAILED; +	}  } +#endif  #ifndef DISABLE_NETWORK -enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options) +enum insmod_return my_modprobe(const char * mod_name, enum driver_type type, char * options)  #else -enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attribute__ ((unused)), char * options) +enum insmod_return my_modprobe(const char * mod_name, enum driver_type type __attribute__ ((unused)), char * options)  #endif  {  	int i; @@ -251,22 +323,26 @@ enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attr  	char ** net_devices = NULL; /* fucking compiler */  #endif -	log_message("have to insmod %s", mod_name); - -	if (disable_modules) { -		log_message("\tdisabled"); +	if (module_already_present(mod_name))  		return INSMOD_OK; -	} + +	log_message("have to insmod %s", mod_name);  #ifndef DISABLE_NETWORK  	if (type == NETWORK_DEVICES)  		net_devices = get_net_devices();  #endif -	if (IS_TESTING) -		return INSMOD_OK; - +#ifdef ENABLE_NETWORK_STANDALONE +	{ +		char *cmd = options ? asprintf_("/sbin/modprobe %s %s", mod_name, options) :  +			              asprintf_("/sbin/modprobe %s", mod_name); +		log_message("running %s", cmd); +		i = system(cmd); +	} +#else  	i = insmod_with_deps(mod_name, options); +#endif  	if (i == 0) {  		log_message("\tsucceeded %s", mod_name);  #ifndef DISABLE_NETWORK @@ -283,7 +359,6 @@ enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attr  				sprintf(alias, "alias %s %s", *new_net_devices, mod_name);  				add_modules_conf(alias);  				log_message("NET: %s", alias); -				net_discovered_interface(*new_net_devices);  			already_present:  				new_net_devices++; @@ -310,9 +385,9 @@ static enum return_type insmod_with_options(char * mod, enum driver_type type)  	strcat(options, mod);  	strcat(options, " "); -	strcat(options, answers[0]); // because my_insmod will eventually modify the string +	strcat(options, answers[0]); // because my_modprobe will eventually modify the string -	if (my_insmod(mod, type, answers[0]) != INSMOD_OK) { +	if (my_modprobe(mod, type, answers[0]) != INSMOD_OK) {  		stg1_error_message("Insmod failed.");  		return RETURN_ERROR;  	} @@ -322,117 +397,65 @@ static enum return_type insmod_with_options(char * mod, enum driver_type type)  	return RETURN_OK;  } +static int strsortfunc(const void *a, const void *b) +{ +    return strcmp(* (char * const *) a, * (char * const *) b); +} +  enum return_type ask_insmod(enum driver_type type)  { -	char * mytype; -	char msg[200];  	enum return_type results;  	char * choice; +	char ** dlist = list_directory(modules_directory); +	char ** modules = alloca(sizeof(char *) * (string_array_length(dlist) + 1)); +	char ** descrs = alloca(sizeof(char *) * (string_array_length(dlist) + 1)); +	char ** p_dlist = dlist; +	char ** p_modules = modules; +	char ** p_descrs = descrs; -	unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ - -	if (type == SCSI_ADAPTERS) -		mytype = "SCSI"; -	else if (type == NETWORK_DEVICES) -		mytype = "NET"; -	else -		return RETURN_ERROR; +	qsort(dlist, string_array_length(dlist), sizeof(char *), strsortfunc); -	if (disable_modules) -		return RETURN_BACK; +	unset_automatic(); /* we are in a fallback mode */ -	snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype); - -	{ -		char ** drivers = mar_list_contents(archive_name); -		char ** descrs = malloc(sizeof(char *) * string_array_length(drivers)); -		char ** p_drivers = drivers; -		char ** p_descrs = descrs; -		while (p_drivers && *p_drivers) { -			int i; -			*p_descrs = NULL; -			for (i = 0 ; i < modules_descriptions_num ; i++) { -				if (!strncmp(*p_drivers, modules_descriptions[i].module, strlen(modules_descriptions[i].module)) -				    && (*p_drivers)[strlen(modules_descriptions[i].module)] == '.') /* one contains '.o' not the other */ -					*p_descrs = modules_descriptions[i].descr; -			} -			p_drivers++; -			p_descrs++; +	while (p_dlist && *p_dlist) { +		struct module_descr_elem * descr; +		if (!strstr(*p_dlist, kernel_module_extension())) { +			p_dlist++; +			continue;  		} -		results = ask_from_list_comments(msg, drivers, descrs, &choice); +		*p_modules = *p_dlist; +		*p_descrs = NULL; +		(*p_modules)[strlen(*p_modules)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */ + +		descr = modules_descr; +		while (descr && descr->modname && strcmp(descr->modname, *p_modules)) descr++; +		if (descr) +			*p_descrs = descr->description; + +		p_dlist++; +		p_modules++; +		p_descrs++;  	} - -	if (results == RETURN_OK) { -		choice[strlen(choice)-2] = '\0'; /* remove trailing .o */ -		return insmod_with_options(choice, type); -	} else -		return results; -} - - -void update_modules(void) -{ -	FILE * f; -	char ** disk_contents; -	char final_name[500]; -	char floppy_mount_location[] = "/tmp/floppy"; - -	stg1_info_message("Please insert the Update Modules floppy.");; - -	my_insmod("floppy", ANY_DRIVER_TYPE, NULL); - -	if (my_mount("/dev/fd0", floppy_mount_location, "ext2", 0) == -1) { -		enum return_type results = ask_yes_no("I can't find a Linux ext2 floppy in first floppy drive.\n" -						      "Retry?"); +	*p_modules = NULL; +	*p_descrs = NULL; + +	if (modules && *modules) { +		char * mytype; +		char msg[200]; +		if (type == MEDIA_ADAPTERS) +			mytype = "MEDIA"; +		else if (type == NETWORK_DEVICES) +			mytype = "NET"; +		else +			return RETURN_ERROR; + +		snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype); +		results = ask_from_list_comments(msg, modules, descrs, &choice);  		if (results == RETURN_OK) -			return update_modules(); -		return; -	} - -	disk_contents = list_directory(floppy_mount_location); - -	if (!(f = fopen("/tmp/floppy/to_load", "rb"))) { -		stg1_error_message("I can't find \"to_load\" file."); -		umount(floppy_mount_location); -		return update_modules(); -	} -	while (1) { -		char module[500]; -		char * options; -		char ** entry = disk_contents; - -		if (!fgets(module, sizeof(module), f)) break; -		if (module[0] == '#' || strlen(module) == 0) -			continue; - -		while (module[strlen(module)-1] == '\n') -			module[strlen(module)-1] = '\0'; -		options = strchr(module, ' '); -		if (options) { -			options[0] = '\0'; -			options++; -		} - -		log_message("updatemodules: (%s) (%s)", module, options); -		while (entry && *entry) { -			if (!strncmp(*entry, module, strlen(module)) && (*entry)[strlen(module)] == '.') { -				sprintf(final_name, "%s/%s", floppy_mount_location, *entry); -				if (insmod_call(final_name, options)) { -					log_message("\t%s (floppy): failed", *entry); -					stg1_error_message("Insmod %s (floppy) failed.", *entry); -				} -				break; -			} -			entry++; -		} -		if (!entry || !*entry) { -			enum insmod_return ret = my_insmod(module, ANY_DRIVER_TYPE, options); -			if (ret != INSMOD_OK) { -				log_message("\t%s (marfile): failed", module); -				stg1_error_message("Insmod %s (marfile) failed.", module); -			} -		} +			return insmod_with_options(choice, type); +		else +			return results; +	} else { +		return RETURN_BACK;  	} -	fclose(f); -	umount(floppy_mount_location);  } | 
