summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/modules.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/modules.c')
-rw-r--r--mdk-stage1/modules.c597
1 files changed, 228 insertions, 369 deletions
diff --git a/mdk-stage1/modules.c b/mdk-stage1/modules.c
index 27edb0349..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,199 +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)
-{
- 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_param(MODE_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;
-}
-
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;
}
-/* 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)
+static char *kernel_module_extension(void)
{
- char module_name[50];
- char final_name[50] = "/tmp/";
- int i, rc;
-
- strncpy(module_name, mod_name, sizeof(module_name));
- if (kernel_version() <= 4)
- strcat(module_name, ".o");
- else
- strcat(module_name, ".ko");
- 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;
+ return ".ko.xz";
+}
- 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);
- 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);
+ buf = cat_file(descr_file, &s);
+ if (!buf)
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;
@@ -262,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");
}
}
@@ -334,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"))) {
@@ -345,70 +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 (!*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;
+ }
+ }
- if (module_already_present(mod_name))
- return INSMOD_OK;
+ kmod_module_unref(mod);
+ if (err < 0)
+ break;
+ }
- log_message("needs %s", mod_name);
- return insmod_archived_file(mod_name, options, allow_modules_floppy);
-}
+ kmod_module_unref_list(list);
+exit:
+ kmod_unref(ctx);
-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;
+ 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;
@@ -416,24 +323,28 @@ 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;
-
- i = insmod_with_deps(real_mod_name, options, allow_modules_floppy);
+#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", real_mod_name);
+ log_message("\tsucceeded %s", mod_name);
#ifndef DISABLE_NETWORK
if (type == NETWORK_DEVICES) {
char ** new_net_devices = get_net_devices();
@@ -448,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++;
@@ -456,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;
@@ -475,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;
}
@@ -487,116 +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 */
+ qsort(dlist, string_array_length(dlist), sizeof(char *), strsortfunc);
- if (type == SCSI_ADAPTERS)
- mytype = "SCSI";
- else if (type == NETWORK_DEVICES)
- mytype = "NET";
- else
- return RETURN_ERROR;
+ unset_automatic(); /* we are in a fallback mode */
- snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype);
-
- {
- 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;
}
- results = ask_from_list_comments(msg, modules, 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) {
- if (kernel_version() <= 4)
- choice[strlen(choice)-2] = '\0'; /* remove trailing .o */
- else
- choice[strlen(choice)-3] = '\0'; /* remove trailing .ko */
- 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.");;
-
- if (my_mount(floppy_device(), 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_local_file(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, 0);
- 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);
}