/*
* modules.c - module loading functionality
*
* Copyright (C) 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author(s): Erik Troan
* Matt Wilson
* Michael Fulbright
* Jeremy Katz
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "loader.h"
#include "log.h"
#include "modules.h"
#include "windows.h"
#include "../isys/cpio.h"
/* boot flags */
extern uint64_t flags;
static int writeModulesConf(char *conf);
struct moduleOptions {
char *name;
int numopts;
char **options;
};
static struct moduleOptions * modopts = NULL;
static int nummodopts = -1;
static char ** blacklists = NULL;
static int numblacklists = 0;
static void readBlacklist() {
int fd;
size_t len = 0;
char buf[1024];
char *start, *end;
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0)
return;
len = read(fd, buf, sizeof(buf) - 1);
close(fd);
buf[len] = '\0';
start = buf;
while (start) {
end = strstr(start, " ");
if (end)
*end = '\0';
if (strncmp(start,"blacklist=",10)) {
if (!end)
break;
start = end + 1;
continue;
}
printf("found %s\n",start);
blacklists = realloc(blacklists, sizeof(*blacklists) * (numblacklists + 1));
blacklists[numblacklists] = strdup(start+10);
numblacklists++;
if (!end)
break;
start = end + 1;
}
}
void mlAddBlacklist(char *module) {
blacklists = realloc(blacklists, sizeof(*blacklists) * (numblacklists + 1));
blacklists[numblacklists] = strdup(module);
numblacklists++;
writeModulesConf("/etc/modprobe.d/anaconda.conf");
}
static void addOption(const char *module, const char *option) {
int found = 0, i;
found = 0;
for (i = 0; i < nummodopts; i++) {
if (strncmp(modopts[i].name, module, strlen(modopts[i].name)))
continue;
modopts[i].numopts++;
found = 1;
break;
}
if (found == 0) {
modopts = realloc(modopts, sizeof(*modopts) * (nummodopts + 1));
modopts[nummodopts].name = strdup(module);
modopts[nummodopts].numopts = 1;
modopts[nummodopts++].options = NULL;
}
modopts[i].options = realloc(modopts[i].options,
sizeof(modopts[i].options) *
(modopts[i].numopts + 1));
modopts[i].options[modopts[i].numopts - 1] = strdup(option);
modopts[i].options[modopts[i].numopts] = NULL;
}
static int isValidModule(char *module) {
char mod_name[64], path[512];
struct utsname utsbuf;
struct stat sbuf;
char *buf;
uname(&utsbuf);
snprintf(path, 512, "/lib/modules/%s/modules.dep", utsbuf.release);
if (!stat(path, &sbuf)) {
int fd;
fd = open(path, O_RDONLY);
buf = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (!buf || buf == MAP_FAILED)
return 0;
close(fd);
snprintf(mod_name, 64, "/%s.ko.gz:", module);
if (strstr(buf, mod_name)) {
munmap(buf, sbuf.st_size);
return 1;
}
snprintf(mod_name, 64, "/%s.ko:", module);
if (strstr(buf, mod_name)) {
munmap(buf, sbuf.st_size);
return 1;
}
munmap(buf, sbuf.st_size);
}
return 0;
}
/* read module options out of /proc/cmdline and into a structure */
static void readModuleOpts() {
int fd;
size_t len = 0;
char buf[1024];
char *start, *end, *sep;
nummodopts = 0;
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0)
return;
len = read(fd, buf, sizeof(buf) - 1);
close(fd);
buf[len] = '\0';
start = buf;
while (start) {
end = strstr(start, " ");
if (end)
*end = '\0';
sep = strstr(start, "=");
if (sep == NULL) {
if (!end)
break;
start = end + 1;
continue;
}
sep = strstr(start, ".");
if (sep == NULL) {
if (!end)
break;
start = end + 1;
continue;
}
*sep = '\0'; sep++;
if (isValidModule(start))
addOption(start, sep);
if (!end)
break;
start = end + 1;
}
}
static int doLoadModule(const char *module, char ** args) {
int child;
int status;
if (!(child = fork())) {
int i, rc;
char **argv = malloc(3 * sizeof(*argv));
int fd = open("/dev/tty3", O_RDWR);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
argv[0] = "/sbin/modprobe";
argv[1] = strdup(module);
argv[2] = NULL;
if (args) {
for (i = 0; args[i] ; i++) {
addOption(module, args[i]);
}
writeModulesConf("/etc/modprobe.d/anaconda.conf");
}
rc = execv("/sbin/modprobe", argv);
_exit(rc);
}
waitpid(child, &status, 0);
if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) {
return 1;
} else {
return 0;
}
}
void mlRemoveBlacklist(char *module) {
int i;
for (i = 0 ; i < numblacklists ; i++) {
if (!strcmp(blacklists[i], module))
blacklists[i] = NULL;
}
}
void mlInitModuleConfig() {
readModuleOpts();
readBlacklist();
writeModulesConf("/etc/modprobe.d/anaconda.conf");
}
/* load a module with a given list of arguments */
int mlLoadModule(const char * module, char ** args) {
return doLoadModule(module, args);
}
/* loads a : separated list of modules */
int mlLoadModuleSet(const char * modNames) {
char *ptr, *name;
int rc = 0;
if (!modNames) return 1;
name = strdup(modNames); while (name) {
ptr = strchr(name, ':');
if (ptr) *ptr = '\0';
rc |= doLoadModule(name, NULL);
if (ptr)
name = ptr+1;
else
name = NULL;
}
return rc;
}
static int writeModulesConf(char *conf) {
int i;
char buf[16384];
int fd, rc;
if (!conf)
conf = "/tmp/modprobe.conf";
fd = open(conf, O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
logMessage(ERROR, "error opening to %s: %m\n", conf);
return 0;
}
strcat(buf, "# Module options and blacklists written by anaconda\n");
for (i = 0; i < nummodopts ; i++) {
int j;
strcat(buf, "options ");
strcat(buf, modopts[i].name);
for (j = 0; j < modopts[i].numopts ; j++) {
strcat(buf, " ");
strcat(buf, modopts[i].options[j]);
}
strcat(buf, "\n");
}
for (i = 0; i < numblacklists ; i++) {
if (blacklists[i]) {
strcat(buf, "blacklist ");
strcat(buf, blacklists[i]);
strcat(buf, "\n");
}
}
rc = write(fd, buf, strlen(buf));
close(fd);
return (rc != strlen(buf));
}
void loadKickstartModule(struct loaderData_s * loaderData, int argc,
char ** argv) {
char * opts = NULL;
char * module = NULL;
char ** args = NULL;
poptContext optCon;
int rc;
struct poptOption ksDeviceOptions[] = {
{ "opts", '\0', POPT_ARG_STRING, &opts, 0, NULL, NULL },
{ 0, 0, 0, 0, 0, 0, 0 }
};
optCon = poptGetContext(NULL, argc, (const char **) argv,
ksDeviceOptions, 0);
if ((rc = poptGetNextOpt(optCon)) < -1) {
startNewt();
newtWinMessage(_("Kickstart Error"), _("OK"),
_("Bad argument to device kickstart method "
"command %s: %s"),
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
return;
}
module = (char *) poptGetArg(optCon);
if (!module) {
startNewt();
newtWinMessage(_("Kickstart Error"), _("OK"),
_("A module name must be specified for "
"the kickstart device command."));
return;
}
if (opts) {
int numAlloced = 5, i = 0;
char * start;
char * end;
args = malloc((numAlloced + 1) * sizeof(args));
start = opts;
while (start && *start) {
end = start;
while (!isspace(*end) && *end) end++;
*end = '\0';
(args)[i++] = strdup(start);
start = end + 1;
*end = ' ';
start = strchr(end, ' ');
if (start) start++;
if (i >= numAlloced) {
numAlloced += 5;
args = realloc(args, sizeof(args) * (numAlloced + 1));
}
}
args[i] = NULL;
}
mlLoadModule(module, args);
}