/* * Guillaume Cottenceau (gc@mandrakesoft.com) * * Copyright 2000 MandrakeSoft * * This software may be freely redistributed under the terms of the GNU * public license. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * (1) calculate dependencies * (2) unarchive relevant modules * (3) insmod them */ #include #include #include #include #include #include #include #include #include #include #include "stage1.h" #include "log.h" #include "frontend.h" #include "mount.h" #include "modules.h" static const char *moderror(int err) { 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); } } 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; } int insmod_call(char *pathname, char *params) { void *file; unsigned long len; int rc = -1; file = grab_file(pathname, &len); if (!file) { log_message("insmod: can't read '%s': %s", pathname, strerror(errno)); return rc; } rc = init_module(file, len, params == NULL ? "" : params); free(file); if (rc != 0 && errno != EEXIST) { log_message("init_module: '%s': %s", pathname, moderror(errno)); return rc; } return 0; } static enum insmod_return modprobe(const char * mod_name, char * options) { int pid, status; if (!(pid = fork())) { char * argv[] = { "/sbin/modprobe", (char *)mod_name, options, NULL }; execve(argv[0], argv, NULL); log_message("modprobe %s failed", mod_name); } waitpid(pid, &status, 0); return WIFEXITED(status) ? INSMOD_OK : INSMOD_FAILED; } enum insmod_return my_insmod(const char * mod_name, char * options) { int i; log_message("have to insmod %s", mod_name); if (IS_TESTING) return INSMOD_OK; i = modprobe(mod_name, options); if (i == 0) { log_message("\tsucceeded %s", mod_name); } else log_message("warning, insmod failed (%s %s) (%d)", mod_name, options, i); return i; } enum return_type ask_insmod() { return RETURN_ERROR; } 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", 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?"); 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, options); if (ret != INSMOD_OK) { log_message("\t%s (marfile): failed", module); stg1_error_message("Insmod %s (marfile) failed.", module); } } } fclose(f); }