propagator/modules.c
2018-05-09 15:21:26 +03:00

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);
}