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.c498
1 files changed, 261 insertions, 237 deletions
diff --git a/mdk-stage1/modules.c b/mdk-stage1/modules.c
index 1fe1cd42a..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 'other.img' for seldom used SCSI modules)", 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))
@@ -197,52 +197,125 @@ static void add_modules_conf(char * str)
}
-static int module_already_present(const char * name)
+int module_already_present(const char * name)
{
FILE * f;
+ struct stat sb;
+ char *path;
int answ = 0;
- f = fopen("/proc/modules", "rb");
- while (1) {
- char buf[500];
- if (!fgets(buf, sizeof(buf), f)) break;
- if (!strncmp(name, buf, strlen(name)) && buf[strlen(name)] == ' ')
+
+ if ((f = fopen("/proc/modules", "rb"))) {
+ while (1) {
+ char buf[500];
+ if (!fgets(buf, sizeof(buf), f)) break;
+ if (!strncmp(name, buf, strlen(name)) && buf[strlen(name)] == ' ')
+ answ = 1;
+ }
+ 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);
}
- fclose(f);
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;
@@ -250,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
@@ -282,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++;
@@ -309,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;
}
@@ -321,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);
}