209 lines
4.5 KiB
C
209 lines
4.5 KiB
C
/*
|
|
* 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 <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/mount.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#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;
|
|
|
|
fd = open(filename, O_RDONLY, 0);
|
|
if (fd < 0)
|
|
return NULL;
|
|
|
|
buffer = malloc(max);
|
|
if (!buffer)
|
|
return NULL;
|
|
|
|
*size = 0;
|
|
while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
|
|
*size += ret;
|
|
if (*size == max) {
|
|
void *nbuffer = realloc(buffer, max *= 2);
|
|
if (!nbuffer) {
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
buffer = nbuffer;
|
|
}
|
|
}
|
|
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", "-q", (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);
|
|
}
|