summaryrefslogtreecommitdiffstats
path: root/loader2/modules.c
diff options
context:
space:
mode:
authorJeremy Katz <katzj@redhat.com>2002-11-26 19:59:19 +0000
committerJeremy Katz <katzj@redhat.com>2002-11-26 19:59:19 +0000
commit32d18cdb5603ba71a27661cc59d78bfaf43a36cc (patch)
treecbef628263c93aba4f3dbb99573f0dc538db714f /loader2/modules.c
parent48ad552b63a95aec286aba9cd91ec0a745152e95 (diff)
downloadanaconda-32d18cdb5603ba71a27661cc59d78bfaf43a36cc.tar.gz
anaconda-32d18cdb5603ba71a27661cc59d78bfaf43a36cc.tar.xz
anaconda-32d18cdb5603ba71a27661cc59d78bfaf43a36cc.zip
restructuring and clean up of some of the older unused code in the loader.
still a lot to do, but this gets to stage2 for cd, nfs, http, and ftp booting from either the cd initrd or the pxe initrd
Diffstat (limited to 'loader2/modules.c')
-rw-r--r--loader2/modules.c595
1 files changed, 595 insertions, 0 deletions
diff --git a/loader2/modules.c b/loader2/modules.c
new file mode 100644
index 000000000..acd723a24
--- /dev/null
+++ b/loader2/modules.c
@@ -0,0 +1,595 @@
+/*
+ * modules.c - module loading functionality
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 2002 Red Hat, Inc.
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * General 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.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kudzu/kudzu.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "log.h"
+#include "modules.h"
+#include "modstubs.h"
+#include "windows.h"
+
+#include "../isys/cpio.h"
+
+static int mlModuleInList(const char * modName, moduleList list);
+static int mlWriteConfModules(moduleList list, int fd);
+static struct extractedModule * extractModules (char * const * modNames,
+ struct extractedModule * oldPaths,
+ struct moduleBallLocation * location);
+
+static int ethCount(void) {
+ int fd;
+ char buf[16384];
+ int i;
+ char * chptr;
+ int count = 0;
+
+ fd = open("/proc/net/dev", O_RDONLY);
+ i = read(fd, buf, sizeof(buf) - 1);
+ buf[i] = '\0';
+
+ /* skip first two header lines */
+ chptr = strchr(buf, '\n') + 1;
+ chptr = strchr(chptr, '\n') + 1;
+
+ while (chptr) {
+ while (*chptr && isspace(*chptr)) chptr++;
+ if (!strncmp(chptr, "eth", 3))
+ count++;
+ chptr = strchr(chptr, '\n');
+ if (chptr) chptr++;
+ }
+
+ return count;
+}
+
+static int scsiDiskCount(void) {
+ struct device ** devices, ** device;
+ int i = 0;
+
+ devices = probeDevices(CLASS_HD, BUS_SCSI, PROBE_ALL);
+
+ for (device = devices; *device; device++) i++;
+
+ return i;
+}
+
+int mlReadLoadedList(moduleList * mlp) {
+ int fd;
+ char * start;
+ char * end;
+ char buf[4096];
+ struct stat sb;
+ int i;
+ moduleList ml;
+
+ if ((fd = open("/proc/modules", O_RDONLY)) < 0)
+ return -1;
+
+ fstat(fd, &sb);
+ i = read(fd, buf, sizeof(buf));
+ buf[i] = '\0';
+ close(fd);
+
+ ml = malloc(sizeof(*ml));
+ ml->numModules = 0;
+
+ start = buf;
+ while (start && *start) {
+ end = start;
+ while (!isspace(*end) && *end != '\n') end++;
+ *end = '\0';
+ ml->mods[ml->numModules].name = strdup(start);
+ ml->mods[ml->numModules].args = NULL;
+ ml->mods[ml->numModules].path = NULL;
+ ml->mods[ml->numModules].weLoaded = 0;
+ *end = ' ';
+ ml->numModules++;
+ start = strchr(end, '\n');
+ if (start) start++;
+ }
+
+ *mlp = ml;
+
+ return 0;
+}
+
+/* this leaks memory if their is a loop in the modules. oh well. */
+char ** tsortModules(moduleList modLoaded, moduleDeps ml, char ** args,
+ int depth, char *** listPtr, int * listSizePtr) {
+ int listSize;
+ char ** list;
+ char ** next;
+ char ** deps;
+
+ if (!depth) {
+ int count;
+
+ listSize = 5;
+ list = malloc((listSize + 1) * sizeof(*list));
+ *list = NULL;
+
+ listPtr = &list;
+ listSizePtr = &listSize;
+
+ for (deps = args, count = 0; *deps; deps++, count++);
+ } else {
+ list = *listPtr;
+ listSize = *listSizePtr;
+ }
+
+ if (depth++ > 100) {
+ return NULL;
+ }
+
+ while (*args) {
+ /* don't load it twice */
+ next = list;
+ while (*next && strcmp(*next, *args)) next++;
+
+ if (*next || mlModuleInList(*args, modLoaded)) {
+ args++;
+ continue;
+ }
+
+ /* load everything this depends on */
+ deps = mlGetDeps(ml, *args);
+ if (deps) {
+ if (!tsortModules(modLoaded, ml, deps, depth,
+ listPtr, listSizePtr))
+ return NULL;
+
+ list = *listPtr;
+ listSize = *listSizePtr;
+ }
+
+ /* add this to the list */
+ next = list;
+ while (*next) next++;
+
+ if ((next - list) >= listSize) {
+ int count = next - list;
+
+ listSize += 10;
+ /* leave room for a NULL */
+ list = realloc(list, sizeof(*list) * (listSize + 1));
+
+ *listSizePtr = listSize;
+ *listPtr = list;
+
+ next = list + count;
+ }
+
+ next[0] = *args;
+ next[1] = NULL;
+
+ args++;
+ }
+
+ return list;
+}
+
+static int mlModuleInList(const char * modName, moduleList list) {
+ int i;
+
+ if (!list) return 0;
+
+ for(i = 0; i < list->numModules; i++)
+ if (!strcmp(list->mods[i].name, modName)) return 1;
+
+ return 0;
+}
+
+/* load a single module. this is the real workhorse of loading modules */
+static int loadModule(const char * modName, struct extractedModule * path,
+ moduleList modLoaded, char ** args,
+ moduleInfoSet modInfo, int flags) {
+ char fileName[300];
+ char ** argPtr, ** newArgs, ** arg;
+ struct moduleInfo * mi = NULL;
+ int deviceCount = -1;
+ int popWindow = 0;
+ int rc, child, i, status;
+
+ /* don't need to load a module that's already loaded */
+ if (mlModuleInList(modName, modLoaded))
+ return 0;
+
+ if (modInfo && (mi = findModuleInfo(modInfo, modName))) {
+ if (mi->major == DRIVER_NET && mi->minor == DRIVER_MINOR_ETHERNET) {
+ deviceCount = ethCount();
+ }
+
+ if (mi->major == DRIVER_SCSI) {
+ startNewt(flags);
+ scsiWindow(modName);
+ popWindow = 1;
+ }
+ }
+
+ sprintf(fileName, "%s.o", modName);
+ for (argPtr = args; argPtr && *argPtr; argPtr++) {
+ strcat(fileName, " ");
+ strcat(fileName, *argPtr);
+ }
+
+ if (FL_TESTING(flags)) {
+ logMessage("would have insmod %s (%s)", path, fileName);
+ rc = 0;
+ } else {
+ if (!(child = fork())) {
+ int fd = open("/dev/tty3", O_RDWR);
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+
+ rc = insmod(path->path, NULL, args);
+ _exit(rc);
+ }
+
+ waitpid(child, &status, 0);
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ rc = 1;
+ } else {
+ rc = 0;
+ }
+ }
+
+ if (!rc) {
+ int num = modLoaded->numModules;
+
+ modLoaded->mods[num].name = strdup(modName);
+ modLoaded->mods[num].weLoaded = 1;
+ modLoaded->mods[num].path =
+ path->location ? strdup(path->location) : NULL;
+ modLoaded->mods[num].firstDevNum = -1;
+ modLoaded->mods[num].lastDevNum = -1;
+ modLoaded->mods[num].written = 0;
+
+ if (mi) {
+ modLoaded->mods[num].major = mi->major;
+ modLoaded->mods[num].minor = mi->minor;
+
+ if (deviceCount >= 0) {
+ if (mi->major == DRIVER_NET) {
+ modLoaded->mods[num].firstDevNum = deviceCount;
+ modLoaded->mods[num].firstDevNum = ethCount() - 1;
+ } else if (mi->major == DRIVER_SCSI) {
+ modLoaded->mods[num].firstDevNum = deviceCount;
+ modLoaded->mods[num].firstDevNum = scsiDiskCount() - 1;
+ }
+ }
+ } else {
+ modLoaded->mods[num].major = DRIVER_NONE;
+ modLoaded->mods[num].minor = DRIVER_MINOR_NONE;
+ }
+
+ if (args) {
+ for (i=0, arg = args; *arg; arg++, i++);
+ newArgs = malloc(sizeof(*newArgs) * (i + 1));
+ for (i = 0, arg = args; *arg; arg++, i++)
+ newArgs[i] = strdup(*arg);
+ newArgs[i] = NULL;
+ } else {
+ newArgs = NULL;
+ }
+
+ modLoaded->mods[modLoaded->numModules++].args = newArgs;
+ }
+
+ if (popWindow) {
+ sleep(1);
+ newtPopWindow();
+ }
+
+ return rc;
+}
+
+/* handle loading a set of modules including their dependencies. also has
+ * a nasty evil hack for handling usb-storage removal/reloading for scsi
+ * device ordering. */
+/* JKFIXME: the location argument is a hack to handle modules
+ * without module-info that I know need to be loaded from other than
+ * /modules/modules.cgz. should module-info be extended to cover
+ * *ALL* modules? this would probably want for auto module-info generation */
+static int doLoadModules(const char * origModNames, moduleList modLoaded,
+ moduleDeps modDeps, moduleInfoSet modInfo,
+ int flags, const char * argModule, char ** args,
+ struct moduleBallLocation * modLocation) {
+ char * modNames;
+ char * start, * next, * end;
+ char ** initialList;
+ char ** list, ** l;
+ char items[1024] = ""; /* 1024 characters should be enough... */
+ struct extractedModule * paths, * p;
+ struct moduleBallLocation *location = NULL;
+ int i;
+ int reloadUsbStorage;
+
+ struct moduleInfo * mi;
+
+ start = modNames = alloca(strlen(origModNames) + 1);
+ strcpy(modNames, origModNames);
+
+ next = start;
+ i = 1;
+ while (*next) {
+ if (*next == ':') i++;
+ next++;
+ }
+
+ initialList = alloca(sizeof(*initialList) * (i + 1));
+
+ i = 0;
+ while (start) {
+ next = end = strchr(start, ':');
+ if (next) {
+ *end = '\0';
+ next++;
+ }
+
+ if (mlModuleInList(start, modLoaded)) {
+ /* already loaded, we don't need to load it again */
+ start = next;
+ continue;
+ }
+
+ initialList[i++] = start;
+ start = next;
+ }
+
+ initialList[i] = NULL;
+
+ list = tsortModules(modLoaded, modDeps, initialList, 0, NULL, NULL);
+ if (!list) {
+ logMessage("ERROR: loop in module dependencies; not inserting");
+ return 1;
+ }
+
+ for (i = 0; list[i]; i++) {
+ strcat(items, " ");
+ strcat(items, list[i]);
+ }
+
+ logMessage("modules to insert%s", items);
+
+ paths = NULL;
+ reloadUsbStorage = 0;
+ if (modInfo) {
+ for (i = 0; list[i]; i++) {
+ mi = findModuleInfo(modInfo, list[i]);
+
+ if (mi && mi->locationID) {
+ location = mi->locationID;
+ }
+
+ if (mi && mi->major == DRIVER_SCSI) {
+ reloadUsbStorage = 1;
+ }
+ }
+ }
+
+ /* JKFIXME: this is a hack to handle an explicit location for modules */
+ if (!location && modLocation)
+ location = modLocation;
+
+ /* JKFIXME: do something to extract the modules */
+ paths = extractModules(list, paths, location);
+
+ i = 0;
+ if (!paths) {
+ logMessage("no modules found -- aborting insertion");
+ return i;
+ }
+
+ *items = '\0';
+ for (l = list, p = paths; *l && p; l++, p++) {
+ if (!p->path) {
+ if (*items) strcat(items, " ");
+ strcat(items, *l);
+ i++;
+ }
+ }
+
+ if (*items) logMessage("module(s) %s not found", items);
+
+ if (reloadUsbStorage) {
+ /* JKFIXME: here are the big hacks... for now, just described.
+ * 1) figure out which scsi devs are claimed by usb-storage.
+ * if lastScsiDev == usb-storage->lastDev,
+ * lastScsiDev = usb->firstDev. else, log that we're screwed.
+ * 2) if stage2 is cdrom and mounted, umount stage2, umount cdrom
+ * 3) rmmod usb-storage
+ */
+ }
+
+ /* insert the modules now */
+
+ for(l = list, p = paths; paths && *l; l++, p++) {
+ if (!p->path)
+ /* no path for this module */
+ continue;
+ if (loadModule(*l, p, modLoaded,
+ (argModule && !strcmp(argModule, *l)) ? args : NULL,
+ modInfo, flags)) {
+ logMessage("failed to insert %s", *p);
+ } else {
+ logMessage("inserted %s", p->path);
+ }
+ }
+
+ if (reloadUsbStorage) {
+ /* JKFIXME: here's the rest of the hacks. basically do the reverse
+ * of what we did before.
+ */
+ }
+
+ if (!FL_TESTING(flags)) {
+ int fd;
+
+ fd = open("/tmp/modules.conf", O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd == -1) {
+ logMessage("error appending to /tmp/modules.conf: %s\n",
+ strerror(errno));
+ } else {
+ mlWriteConfModules(modLoaded, fd);
+ close(fd);
+ }
+ }
+
+ for (p = paths; p->path; p++) {
+ unlink(p->path);
+ free(p->path);
+ if (p->location) free(p->location);
+ }
+
+ free(paths);
+ free(list);
+
+ logMessage("load module set done");
+
+ return i;
+}
+
+/* loads a : separated list of modules. the arg only applies to the
+ first module in the list */
+int mlLoadModuleSet(const char * modNames,
+ moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ return doLoadModules(modNames, modLoaded, modDeps, modInfo,
+ flags, NULL, NULL, NULL);
+}
+
+/* like mlLoadModuleSet but from an explicit location */
+/* JKFIXME: this is a hack */
+int mlLoadModuleSetLocation(const char * modNames,
+ moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags,
+ struct moduleBallLocation * location) {
+ return doLoadModules(modNames, modLoaded, modDeps, modInfo,
+ flags, NULL, NULL, location);
+}
+
+static int mlWriteConfModules(moduleList list, int fd) {
+ /* JKFIXME: add code to do stuff here... */
+ return 0;
+}
+
+/* JKFIXME: needs a way to know about module locations. also, we should
+ * extract them to a ramfs instead of /tmp */
+static struct extractedModule * extractModules (char * const * modNames,
+ struct extractedModule * oldPaths,
+ struct moduleBallLocation * location) {
+
+ gzFile fd;
+ char * ballPath;
+ struct cpioFileMapping * map;
+ int i, numMaps, rc;
+ char * const * m;
+ char fn[255];
+ const char * failedFile;
+ struct stat sb;
+ struct utsname u;
+
+ uname(&u);
+
+ /* JKFIXME: handle driver disk path somehow */
+ if (!location)
+ ballPath = strdup("/modules/modules.cgz");
+ else
+ ballPath = strdup(location->path);
+
+ fd = gunzip_open(ballPath);
+ if (!fd) {
+ logMessage("failed to open %s", ballPath);
+ free(ballPath);
+ return NULL;
+ }
+
+ for(m = modNames, i = 0; *m; i++, m++);
+
+ map = alloca(sizeof(*map) * i);
+ memset(map, 0, sizeof(*map) * i);
+
+ if (!oldPaths)
+ /* +1 NULL to terminate the list */
+ oldPaths = calloc(i + 1, sizeof(*oldPaths));
+
+ for (m = modNames, i = 0, numMaps = 0; *m; m++, i++) {
+ /* if we don't know the path of this module yet, "figure" it out */
+ if (!oldPaths[i].path) {
+ map[numMaps].archivePath = alloca(strlen(u.release) +
+ strlen(*m) + 25);
+ sprintf(map[numMaps].archivePath, "%s/%s.o", u.release, *m);
+ map[numMaps].fsPath = alloca(10 + strlen(*m));
+ sprintf(map[numMaps].fsPath, "/tmp/%s.o", *m);
+ unlink(map[numMaps].fsPath);
+ map[numMaps].mapFlags = CPIO_MAP_PATH;
+ numMaps++;
+ }
+ }
+
+ if (!numMaps) {
+ gunzip_close(fd);
+ free(ballPath);
+ return oldPaths;
+ }
+
+ qsort(map, numMaps, sizeof(*map), myCpioFileMapCmp);
+ rc = myCpioInstallArchive(fd, map, numMaps, NULL, NULL, &failedFile);
+
+ gunzip_close(fd);
+
+ for (m = modNames, i = 0, numMaps = 0; *m; m++, i++) {
+ if (!oldPaths[i].path) {
+ sprintf(fn, "/tmp/%s.o", modNames[i]);
+ if (!stat(fn, &sb)) {
+ oldPaths[i].path = strdup(fn);
+ /* JKFIXME: this is copied from the old stuff -- do we really need it? */
+ if (location && location->path) {
+ oldPaths[i].location = strdup(location->path);
+ if (location->title)
+ logMessage("module %s found on driver disk %s",
+ modNames[i], location->title);
+ logMessage("loaded %s from %s", modNames[i],
+ location->path);
+ } else
+ logMessage("loaded %s from /modules/modules.cgz", modNames[i]);
+ }
+ numMaps++;
+ }
+ }
+
+ free(ballPath);
+ return oldPaths;
+}