diff options
Diffstat (limited to 'mdk-stage1/modules.c')
| -rw-r--r-- | mdk-stage1/modules.c | 533 | 
1 files changed, 218 insertions, 315 deletions
| diff --git a/mdk-stage1/modules.c b/mdk-stage1/modules.c index 11e118030..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,34 +18,34 @@   * (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 <errno.h> -#include "insmod.h" -#include "stage1.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"; -static char additional_archive_name[] = "/tmp/tmpfs/modules.mar"; -int allow_additional_modules_floppy = 1; +static char modules_directory[100]; +static struct module_descr_elem * modules_descr = NULL;  extern long init_module(void *, unsigned long, const char *); -  static const char *moderror(int err)  {  	switch (err) { @@ -62,206 +62,86 @@ static const char *moderror(int err)  	}  } -static void *grab_file(const char *filename, unsigned long *size) -{ -	unsigned int max = 16384; -	int ret, fd; -	void *buffer = malloc(max); - -        fd = open(filename, O_RDONLY, 0); -	if (fd < 0) -		return NULL; - -	*size = 0; -	while ((ret = read(fd, buffer + *size, max - *size)) > 0) { -		*size += ret; -		if (*size == max) -			buffer = realloc(buffer, max *= 2); -	} -	if (ret < 0) { -		free(buffer); -		buffer = NULL; -	} -	close(fd); -	return buffer; -} - -static enum return_type ensure_additional_modules_available(void) -{ -#ifdef ENABLE_ADDITIONAL_MODULES -        struct stat statbuf; -        if (stat(additional_archive_name, &statbuf)) { -                char floppy_mount_location[] = "/tmp/floppy"; -                char floppy_modules_mar[] = "/tmp/floppy/modules.mar"; -                int ret; -                int automatic = 0; - -                if (stat("/tmp/tmpfs", &statbuf)) { -                        if (scall(mkdir("/tmp/tmpfs", 0755), "mkdir")) -                                return RETURN_ERROR; -                        if (scall(mount("none", "/tmp/tmpfs", "tmpfs", MS_MGC_VAL, NULL), "mount tmpfs")) -                                return RETURN_ERROR; -                } -                 -                if (IS_AUTOMATIC) { -                        unset_automatic(); -                        automatic = 1; -                } -           -        retry: -                stg1_info_message("Please insert the Additional Drivers floppy.");; - -                while (my_mount(floppy_device(), floppy_mount_location, "ext2", 0) == -1) { -                        enum return_type results = ask_yes_no(errno == ENXIO ? -                                                              "There is no detected floppy drive, or no floppy disk in drive.\nRetry?" -                                                              : errno == EINVAL ? -                                                              "Floppy is not a Linux ext2 floppy in first floppy drive.\nRetry?" -                                                              : "Can't find a linux ext2 floppy in first floppy drive.\nRetry?"); -                        if (results != RETURN_OK) { -                                allow_additional_modules_floppy = 0; -                                if (automatic) -                                        set_param(MODE_AUTOMATIC); -                                return results; -                        } -                } -                                 -                if (stat(floppy_modules_mar, &statbuf)) { -                        stg1_error_message("This is not an Additional Drivers floppy, as far as I can see."); -                        umount(floppy_mount_location); -                        goto retry; -                } - -                init_progression("Copying...", file_size(floppy_modules_mar)); -                ret = copy_file(floppy_modules_mar, additional_archive_name, update_progression); -                end_progression(); -                umount(floppy_mount_location); -                if (automatic) -                        set_param(MODE_AUTOMATIC); -                return ret; -        } else -                return RETURN_OK; -#else -	allow_additional_modules_floppy = 0; -	return RETURN_ERROR; -#endif -} -  int insmod_local_file(char * path, char * options)  { -        if (kernel_version() <= 4) { -                return insmod_call(path, options); -        } else { -                void *file; -                unsigned long len; -                int rc; +	void *file; +	unsigned long len; +	int rc; -                file = grab_file(path, &len); +	if (IS_TESTING) +		return 0; + +	file = grab_file(path, &len); -                if (!file) { -                        log_perror(asprintf_("\terror reading %s", path)); -                        return -1; -                } +	if (!file) { +		log_perror(asprintf_("\terror reading %s", path)); +		return -1; +	} -                rc = init_module(file, len, options ? options : ""); -                if (rc) -                        log_message("\terror: %s", moderror(errno)); -                return rc; -        } +	rc = init_module(file, len, options ? options : ""); +	if (rc) +		log_message("\terror: %s", moderror(errno)); +	return rc;  }  static char *kernel_module_extension(void)  { -  return kernel_version() <= 4 ? ".o" : ".ko"; +	return ".ko.xz";  } -/* 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, int allow_modules_floppy) -{ -	char module_name[50]; -	char final_name[50] = "/tmp/"; -	int i, rc; - -	strncpy(module_name, mod_name, sizeof(module_name)); -	strcat(module_name, kernel_module_extension()); -	i = mar_extract_file(archive_name, module_name, "/tmp/"); -	if (i == 1) { -                static int recurse = 0; -                if (allow_additional_modules_floppy && allow_modules_floppy && !recurse) { -                        recurse = 1; -                        if (ensure_additional_modules_available() == RETURN_OK) -                                i = mar_extract_file(additional_archive_name, module_name, "/tmp/"); -                        recurse = 0; -                } -        } -        if (i == 1) { -                log_message("file-not-found-in-archive %s (maybe you can try another boot floppy such as 'hdcdrom_usb.img')", module_name); -                return INSMOD_FAILED_FILE_NOT_FOUND; -        } -	if (i != 0) -		return INSMOD_FAILED; - -	strcat(final_name, module_name); -        rc = insmod_local_file(final_name, options); +static char *filename2modname(char * filename) { +	char *modname, *p; -	unlink(final_name); /* sucking no space left on device */ +	modname = strdup(basename(filename)); +	if (strstr(modname, kernel_module_extension())) { +		modname[strlen(modname)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko.gz */ +	} -	if (rc) { -		log_message("\tfailed"); -		return INSMOD_FAILED; +	p = modname; +	while (p && *p) { +		if (*p == '-') +			*p = '_'; +		p++;  	} -	return INSMOD_OK; -} +	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_dependencies(void) +static int load_modules_descriptions(void)  { -	char * deps_file = "/modules/modules.dep"; +	char * descr_file = asprintf_("%s/%s", modules_directory, "modules.description");  	char * buf, * ptr, * start, * end;  	struct stat s; -	int fd, line, i; - -	log_message("loading modules dependencies"); +	int line; -	if (IS_TESTING) -		return 0; +	log_message("loading modules descriptions"); -	fd = open(deps_file, O_RDONLY); -	if (fd == -1) { -		log_perror(deps_file); +	buf = cat_file(descr_file, &s); +	if (!buf)  		return -1; -	} -	 -	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; -	} -	buf[s.st_size] = '\0'; -	close(fd); - -	ptr = buf; -	line = 0; -	while (ptr) { -		line++; -		ptr = strchr(ptr + 1, '\n'); -	} - -	modules_deps = malloc(sizeof(*modules_deps) * (line+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; @@ -269,45 +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()) { -		fatal_error("warning, error initing modules stuff, modules loading disabled"); +	find_modules_directory(); +	if (load_modules_descriptions()) { +		log_message("warning, error initing modules stuff");  	}  } @@ -341,6 +200,8 @@ 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"))) { @@ -352,76 +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, int allow_modules_floppy) -{ -	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, allow_modules_floppy); -			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 (module_already_present(mod_name)) -		return INSMOD_OK; +	if (!*modules_directory) +		find_modules_directory(); -	log_message("needs %s", mod_name); -	{ -		char *file = asprintf_("/modules/%s%s", mod_name, kernel_module_extension()); -		if (access(file, R_OK) == 0) -			return insmod_local_file(file, options); -		else -			return insmod_archived_file(mod_name, options, allow_modules_floppy); +	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; +	} -static const char * get_name_kernel_26_transition(const char * name) -{ -	struct kernel_24_26_mapping { -		const char * name_24; -		const char * name_26; -	}; -	static struct kernel_24_26_mapping mappings[] = { -                { "usb-ohci", "ohci-hcd" }, -                { "usb-uhci", "uhci-hcd" }, -                { "uhci", "uhci-hcd" }, -//                { "printer", "usblp" }, -                { "bcm4400", "b44" }, -                { "3c559", "3c359" }, -                { "3c90x", "3c59x" }, -                { "dc395x_trm", "dc395x" }, -//                { "audigy", "snd-emu10k1" }, -        }; -	int mappings_nb = sizeof(mappings) / sizeof(struct kernel_24_26_mapping); -        int i; - -        /* pcitable contains 2.4 names. this will need to change if/when it contains 2.6 names! */ -        if (kernel_version() > 4) -                for (i=0; i<mappings_nb; i++) { -                        if (streq(name, mappings[i].name_24)) -                                return mappings[i].name_26; -                } -        return name; +	kmod_module_unref_list(list); + +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, int allow_modules_floppy) +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, int allow_modules_floppy) +enum insmod_return my_modprobe(const char * mod_name, enum driver_type type __attribute__ ((unused)), char * options)  #endif  {  	int i; @@ -429,21 +323,16 @@ enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attr  	char ** net_devices = NULL; /* fucking compiler */  #endif -        const char * real_mod_name = get_name_kernel_26_transition(mod_name); - -	if (module_already_present(real_mod_name)) +	if (module_already_present(mod_name))  		return INSMOD_OK; -	log_message("have to insmod %s", real_mod_name); +	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) :  @@ -452,10 +341,10 @@ enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attr  		i = system(cmd);  	}  #else -	i = insmod_with_deps(real_mod_name, options, allow_modules_floppy); +	i = insmod_with_deps(mod_name, options);  #endif  	if (i == 0) { -		log_message("\tsucceeded %s", real_mod_name); +		log_message("\tsucceeded %s", mod_name);  #ifndef DISABLE_NETWORK  		if (type == NETWORK_DEVICES) {  			char ** new_net_devices = get_net_devices(); @@ -470,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++; @@ -478,7 +366,7 @@ enum insmod_return my_insmod(const char * mod_name, enum driver_type type __attr  		}  #endif  	} else -		log_message("warning, insmod failed (%s %s) (%d)", real_mod_name, options, i); +		log_message("warning, insmod failed (%s %s) (%d)", mod_name, options, i);  	return i; @@ -497,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], 1) != INSMOD_OK) { +	if (my_modprobe(mod, type, answers[0]) != INSMOD_OK) {  		stg1_error_message("Insmod failed.");  		return RETURN_ERROR;  	} @@ -509,50 +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_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); -	snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype); +	unset_automatic(); /* we are in a fallback mode */ -	{ -		char ** modules = mar_list_contents(ensure_additional_modules_available() == RETURN_OK ? additional_archive_name -                                                                                                       : archive_name); -		char ** descrs = malloc(sizeof(char *) * string_array_length(modules)); -		char ** p_modules = modules; -		char ** p_descrs = descrs; -		while (p_modules && *p_modules) { -			int i; -			*p_descrs = NULL; -			for (i = 0 ; i < modules_descriptions_num ; i++) { -				if (!strncmp(*p_modules, modules_descriptions[i].module, strlen(modules_descriptions[i].module)) -				    && (*p_modules)[strlen(modules_descriptions[i].module)] == '.') /* one contains '.o' not the other */ -					*p_descrs = modules_descriptions[i].descr; -			} -			p_modules++; -			p_descrs++; +	while (p_dlist && *p_dlist) { +		struct module_descr_elem * descr; +		if (!strstr(*p_dlist, kernel_module_extension())) { +			p_dlist++; +			continue;  		} -		if (modules && *modules) -			results = ask_from_list_comments(msg, modules, descrs, &choice); -		else -			results = RETURN_BACK; +		*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++;  	} +	*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; -	if (results == RETURN_OK) { -		choice[strlen(choice)-strlen(kernel_module_extension())] = '\0'; /* remove trailing .ko or .o */ -		return insmod_with_options(choice, type); -	} else -		return results; +		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 insmod_with_options(choice, type); +		else +			return results; +	} else { +		return RETURN_BACK; +	}  } | 
