This includes: - removal of the moddeps code - removal of the module list tracking For handling passed options in the installed system, write a /etc/modprobe.d files with: 1) any options passed on the installer command line 2) any modules blacklisted via the command line 3) any options directly specified for modules --- loader2/modstubs.c | 263 ------------ loader2/modstubs.h | 9 - loader2/moduledeps.c | 196 --------- loader2/moduledeps.h | 15 - loader2/modules.c | 1146 +++++++------------------------------------------- loader2/modules.h | 42 +-- 6 files changed, 160 insertions(+), 1511 deletions(-) diff --git a/loader2/modstubs.c b/loader2/modstubs.c deleted file mode 100644 index 1e929bf..0000000 --- a/loader2/modstubs.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * modstubs.c - stubs around modutils commands - * - * Erik Troan <ewt@xxxxxxxxxx> - * Matt Wilson <msw@xxxxxxxxxx> - * Michael Fulbright <msf@xxxxxxxxxx> - * Jeremy Katz <katzj@xxxxxxxxxx> - * - * 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 <stdio.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/utsname.h> -#include <sys/wait.h> -#include <sys/mman.h> - -#include "log.h" -#include "modstubs.h" -#include "modules.h" - -#include "../isys/cpio.h" -#include "../isys/stubs.h" - -extern long init_module(void *, unsigned long, const char *); -extern long delete_module(const char *, unsigned int); - -static int usage() { - fprintf(stderr, "usage: insmod [-p <path>] <module>.ko\n"); - return 1; -} - -static int rmmod_usage() { - fprintf(stderr, "usage: rmmod <module>\n"); - return 1; -} - -static char * extractModule(char * file, char * ballPath, int version, - int *rmObj) { - gzFile fd; - /* Make finaleName and fullName REALLY static, otherwise they get dropped - from the stack after the function returns and the addresses are no - longer valid. */ - static char finalName[100], fullName[100]; - char * chptr = NULL; - char *loc = NULL; - - if (access(file, R_OK)) { - /* it might be having a ball */ - fd = gunzip_open(ballPath); - if (!fd) - return NULL; - - chptr = strrchr(file, '/'); - if (chptr) file = chptr + 1; - sprintf(finalName, "/tmp/%s", file); - - loc = getModuleLocation(version); - sprintf(fullName, "%s/%s", loc, file); - free(loc); - - int ret = installCpioFile(fd, fullName, finalName, 0); - gunzip_close(fd); - if (ret) - return NULL; - - *rmObj = 1; - file = finalName; - } - - return file; -} - -int ourInsmodCommand(int argc, char ** argv) { - char * file; - int rc, rmObj = 0; - char * ballPath = NULL; - int version = 1; - int fd; - void * modbuf = NULL; - struct stat sb; - int i; - char *options = NULL, *tmp = NULL; - - if (argc < 2) { - return usage(); - } - - while (argc > 2) { - if (!strcmp(argv[1], "-p")) { - ballPath = malloc(strlen(argv[2]) + 30); - if (!ballPath) { - logMessage(ERROR, "cannot allocate memory for ballPath: %m"); - return 1; - } - sprintf(ballPath, "%s/modules.cgz", argv[2]); - argv += 2; - argc -= 2; - } else if (!strcmp(argv[1], "--modballversion")) { - version = atoi(argv[2]); - argv += 2; - argc -= 2; - } else if (!strncmp(argv[1], "-", 1)) { /* ignore all other options */ - argc -= 1; - argv += 1; - } else { - break; - } - } - - if (!ballPath) { - ballPath = strdup("/modules/modules.cgz"); - } - - file = extractModule(argv[1], ballPath, version, &rmObj); - free(ballPath); - - if (file == NULL) - return 1; - - if (stat(file, &sb) == -1) { - logMessage(ERROR, "unable to stat file %s: %s", file, strerror(errno)); - return 1; - } - - fd = open(file, O_RDONLY); - if (fd < 0) { - logMessage(ERROR, "unable to open file %s: %s", file, strerror(errno)); - return 1; - } - - modbuf = mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (modbuf == NULL) { - logMessage(ERROR, "error reading file %s: %s", file, strerror(errno)); - close(fd); - return 1; - } - - options = strdup(""); - if (!options) { - logMessage(ERROR, "cannot allocate memory for module options: %m"); - munmap(modbuf, sb.st_size); - close(fd); - return 1; - } - for (i = 2; i < argc; i++) { - tmp = realloc(options, strlen(options) + 1 + strlen(argv[i]) + 1); - if (!tmp) { - logMessage(ERROR, "cannot allocate memory for module options: %m"); - free(options); - munmap(modbuf, sb.st_size); - close(fd); - return 1; - } - options = tmp; - strcat(options, argv[i]); - strcat(options, " "); - } - - while ((rc = init_module(modbuf, sb.st_size, options)) == -1 && - errno == EINTR) - ; - if (rc != 0) - logMessage(WARNING, "failed to insert module (%d)", errno); - free(options); - munmap(modbuf, sb.st_size); - close(fd); - return rc; -} - -int ourRmmodCommand(int argc, char ** argv) { - if (argc < 2) { - return rmmod_usage(); - } - - return rmmod(argv[1]); -} - -static char * modNameMunge(char * mod) { - unsigned int i; - - for (i = 0; mod[i]; i++) { - if (mod[i] == '-') - mod[i] = '_'; - } - return mod; -} - -int rmmod(char * modName) { - pid_t child; - int status; - int rc = 0; - - modName = modNameMunge(modName); - if ((child = fork()) == 0) { - rc = delete_module(modName, O_NONBLOCK|O_EXCL); - exit(rc); - } - - waitpid(child, &status, 0); - - if (WIFEXITED(status)) - rc = WEXITSTATUS(status); - else - rc = -1; - - return rc; -} - -int insmod(char * modName, char * path, char ** args) { - int argc; - char ** argv; - int rc = 0; - pid_t child; - int status; - int count; - - argc = 0; - for (argv = args; argv && *argv; argv++, argc++); - - argv = alloca(sizeof(*argv) * (argc + 5)); - argv[0] = "/bin/insmod"; - count = 1; - if (path) { - argv[1] = "-p"; - argv[2] = path; - count += 2; - } - - argv[count] = modName; - count++; - - if (args) - memcpy(argv + count, args, sizeof(*args) * argc); - - argv[argc + count] = NULL; - - argc += count; - - if ((child = fork()) == 0) { - exit(ourInsmodCommand(argc, argv)); - } - - waitpid(child, &status, 0); - - if (WIFEXITED(status)) - rc = WEXITSTATUS(status); - else - rc = -1; - - return rc; -} diff --git a/loader2/modstubs.h b/loader2/modstubs.h deleted file mode 100644 index cd80b60..0000000 --- a/loader2/modstubs.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef H_MODSTUBS -#define H_MODSTUBS - -int ourInsmodCommand(int argc, char ** argv); -int ourRmmodCommand(int argc, char ** argv); -int rmmod(char * modName); -int insmod(char * modName, char * path, char ** args); - -#endif diff --git a/loader2/moduledeps.c b/loader2/moduledeps.c deleted file mode 100644 index 1fc4138..0000000 --- a/loader2/moduledeps.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * moduledeps.c - module dependency determination - * - * Erik Troan <ewt@xxxxxxxxxx> - * Matt Wilson <msw@xxxxxxxxxx> - * Michael Fulbright <msf@xxxxxxxxxx> - * Jeremy Katz <katzj@xxxxxxxxxx> - * - * 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 <alloca.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <newt.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "moduledeps.h" - -moduleDeps mlNewDeps(void) { - moduleDeps md; - - md = malloc(sizeof(*md)); - md->name = NULL; - md->deps = NULL; - - return md; -} - -/* JKFIXME: if we have a new module with different deps, this doesn't - * handle it correctly */ -int mlLoadDeps(moduleDeps * moduleDepListPtr, const char * path) { - int fd; - char * buf; - struct stat sb; - char * start, * end, * chptr; - int i, numItems; - moduleDeps nextDep; - moduleDeps moduleDepList = *moduleDepListPtr; - int ret; - - fd = open(path, O_RDONLY); - if (fd < 0) { - return -1; - } - - fstat(fd, &sb); - buf = alloca(sb.st_size + 1); - ret = read(fd, buf, sb.st_size); - buf[sb.st_size] = '\0'; - close(fd); - - start = buf; - numItems = 0; - while (start) { - numItems++; - start = strchr(start + 1, '\n'); - } - - for (nextDep = moduleDepList; nextDep->name; nextDep++) numItems++; - - moduleDepList = realloc(moduleDepList, sizeof(*moduleDepList) * numItems); - for (nextDep = moduleDepList; nextDep->name; nextDep++) ; - - /* We have to remove `\' first. */ - start = buf; - start = strchr(start, '\\'); - while (start) { - /* Replace `\\' with a space. */ - *start++ = ' '; - /* Replace the following `\n' and `\r' with a space. */ - if (*start == '\n') { - *start++ = ' '; - if (*start == '\r') - *start++ = ' '; - } - else if (*start == '\r') { - *start++ = ' '; - if (*start == '\n') - *start++ = ' '; - } - start = strchr(start, '\\'); - - } - - start = buf; - while (start < (buf + sb.st_size) && *start) { - end = strchr(start, '\n'); - *end = '\0'; - - chptr = strchr(start, ':'); - if (!chptr) { - start = end + 1; - continue; - } - - *chptr++ = '\0'; - while (*chptr && isspace(*chptr)) chptr++; - if (!*chptr) { - start = end + 1; - continue; - } - - /* found something */ - nextDep->name = strdup(start); - nextDep->deps = malloc(sizeof(char *) * (strlen(chptr) + 1)); - start = chptr, i = 0; - while (start && *start) { - chptr = strchr(start, ' '); - if (chptr) *chptr = '\0'; - nextDep->deps[i++] = strdup(start); - if (chptr) - start = chptr + 1; - else - start = NULL; - while (start && *start && isspace(*start)) start++; - } - nextDep->deps[i] = NULL; - nextDep->deps = realloc(nextDep->deps, sizeof(char *) * (i + 1)); - nextDep++; - - start = end + 1; - } - - nextDep->name = NULL; - nextDep->deps = NULL; - moduleDepList = realloc(moduleDepList, sizeof(*moduleDepList) * - (nextDep - moduleDepList + 1)); - - *moduleDepListPtr = moduleDepList; - - return 0; -} - -char ** mlGetDeps(moduleDeps modDeps, const char * modName) { - moduleDeps dep; - - for (dep = modDeps; dep && dep->name && strcmp(dep->name, modName); dep++); - - if (dep) return dep->deps; - - return NULL; -} - -/* fun test cases... */ -#ifdef TESTING - -void printDeps(moduleDeps modDeps) { - moduleDeps dep; - char buf[1024]; - char **foo; - - for (dep = modDeps; dep && dep->name; dep++) { - if (strcmp(dep->name, "pcnet32")) - continue; - if (!dep->deps) - printf("module: %s, no deps\n", dep->name); - else { - buf[0] = '\0'; - for (foo = dep->deps; *foo; foo++) { - strcat(buf, *foo); - strcat(buf, " "); - } - printf("module: %s, deps: %s\n", dep->name, buf); - } - } -} - -int main(int argc, char ** argv) { - moduleDeps deps; - - deps = mlNewDeps(); - printDeps(deps); - mlLoadDeps(&deps, "modules.dep.1"); - printDeps(deps); - - printf("----------------------------------------\n"); - printf("Loading second set\n"); - mlLoadDeps(&deps, "modules.dep.2"); - printDeps(deps); - - return 0; -} -#endif diff --git a/loader2/moduledeps.h b/loader2/moduledeps.h deleted file mode 100644 index de040c2..0000000 --- a/loader2/moduledeps.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MODULEDEPS_H -#define MODULEDEPS_H - -typedef struct moduleDependency_s * moduleDeps; - -struct moduleDependency_s { - char * name; - char ** deps; -}; - -moduleDeps mlNewDeps(void); -int mlLoadDeps(moduleDeps * moduleDepListPtr, const char * path); -char ** mlGetDeps(moduleDeps modDeps, const char * modName); - -#endif diff --git a/loader2/modules.c b/loader2/modules.c index ebe6cba..9ba2714 100644 --- a/loader2/modules.c +++ b/loader2/modules.c @@ -19,12 +19,12 @@ #include <ctype.h> #include <errno.h> #include <fcntl.h> -#include <kudzu/kudzu.h> #include <newt.h> #include <popt.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/utsname.h> @@ -34,238 +34,111 @@ #include "loader.h" #include "log.h" #include "modules.h" -#include "modstubs.h" #include "windows.h" -#include "usb.h" #include "../isys/cpio.h" /* boot flags */ extern uint64_t flags; -static int writeModulesConf(moduleList list, char *conf); -static struct extractedModule * extractModules (char * const * modNames, - struct extractedModule * oldPaths, - struct moduleBallLocation * location); - -/* pass in the type of device (eth or tr) that you're looking for */ -static int ethCount(const char * type) { - 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); - close(fd); - 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, type, strlen(type))) - count++; - chptr = strchr(chptr, '\n'); - if (chptr) chptr++; - } - - return count; -} - -static int scsiCount(char *conf) { - FILE *f; - int count = 0; - - f = fopen(conf, "r"); - if (!f) - return 0; - do { - char *buf = NULL; - size_t n = 0; - if (getline(&buf, &n, f) < 0) - break; - if (!strncmp(buf, "alias scsi_hostadapter", 22)) - count++; - free(buf); - } while (1); - fclose(f); - return count; -} - -static int scsiDiskCount(void) { - struct device ** devices; - int i = 0, count = 0; +static int writeModulesConf(char *conf); +struct moduleOptions { + char *name; + int numopts; + char **options; +}; - devices = probeDevices(CLASS_HD, BUS_SCSI, PROBE_LOADED); - if (devices) { - for (i=0; devices[i]; i++, count++); - free(devices); - } - /* have to probe for usb floppies too */ - devices = probeDevices(CLASS_FLOPPY, BUS_SCSI, PROBE_LOADED); - if (devices) { - for (i=0; devices[i]; i++, count++); - free(devices); - } - /* have to probe for usb cdrom too */ - devices = probeDevices(CLASS_CDROM, BUS_SCSI, PROBE_LOADED); - if (devices) { - for (i=0; devices[i]; i++, count++); - free(devices); - } +static struct moduleOptions * modopts = NULL; +static int nummodopts = -1; - return count; -} +static char ** blacklists = NULL; +static int numblacklists = 0; -int mlReadLoadedList(moduleList * mlp) { +static void readBlacklist() { int fd; - char * start; - char * end; - char buf[4096]; - struct stat sb; - int i; - moduleList ml; + size_t len = 0; + char buf[1024]; + char *start, *end; - if ((fd = open("/proc/modules", O_RDONLY)) < 0) - return -1; + if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) + return; - fstat(fd, &sb); - i = read(fd, buf, sizeof(buf)); - buf[i] = '\0'; + len = read(fd, buf, sizeof(buf) - 1); close(fd); - - ml = malloc(sizeof(*ml)); - ml->numModules = 0; - + buf[len] = '\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 there 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++; + 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); - /* 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; - } + blacklists = realloc(blacklists, sizeof(*blacklists) * (numblacklists + 1)); + blacklists[numblacklists] = strdup(start+10); + numblacklists++; - /* 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++; + if (!end) + break; + start = end + 1; } - - return list; } -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; +static void addOption(const char *module, const char *option) { + int found = 0, i; - return 0; + 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 struct loadedModuleInfo * getLoadedModuleInfo(moduleList modLoaded, - const char * modName) { - int i = 0; - - for (i = 0; i < modLoaded->numModules; i++) - if (!strcmp(modLoaded->mods[i].name, modName)) - return &modLoaded->mods[i]; +static int isValidModule(char *module) { + char mod_name[64], path[512]; + struct utsname utsbuf; + struct stat sbuf; + char *buf; - return NULL; -} - -struct moduleOptions { - char *name; - int numopts; - char **options; -}; + uname(&utsbuf); + snprintf(path, 512, "/lib/modules/%s/modules.dep", utsbuf.release); + if (!stat(path, &sbuf)) { + int fd; -static struct moduleOptions * modopts = NULL; -static int nummodopts = -1; + 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:", 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() { @@ -273,7 +146,6 @@ static void readModuleOpts() { size_t len = 0; char buf[1024]; char *start, *end, *sep; - int found = 0, i; nummodopts = 0; if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) @@ -304,830 +176,126 @@ static void readModuleOpts() { } *sep = '\0'; sep++; - found = 0; - for (i = 0; i < nummodopts; i++) { - if (strncmp(modopts[i].name, start, 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(start); - 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(sep); + if (isValidModule(start)) + addOption(start, sep); if (!end) break; start = end + 1; } - - /* null-terminate options for each module */ - for (i = 0; i < nummodopts; i++) { - modopts[i].options[modopts[i].numopts] = NULL; - } -} - -/* look for options for a specific module from the command line */ -static char ** cmdLineModuleOpts(const char *modName) { - int i; - - if (nummodopts == -1) - readModuleOpts(); - for (i = 0; i < nummodopts; i++) { - if (strncmp(modName, modopts[i].name, strlen(modName))) - continue; - return modopts[i].options; - } - return NULL; } +static int doLoadModule(const char *module, char ** args) { + int child; + int status; -/* 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) { - char fileName[300]; - char ** argPtr, ** newArgs, ** arg, ** cmdlineArgs; - struct moduleInfo * mi = NULL; - int deviceCount = -1; - int popWindow = 0; - int rc, child, i, status; - static int usbWasLoaded = 0; - - /* don't need to load a module that's already loaded */ - if (mlModuleInList(modName, modLoaded)) - return 0; + if (!(child = fork())) { + int i, rc; + char **argv = malloc(3 * sizeof(*argv)); + int fd = open("/dev/tty3", O_RDWR); - if (modInfo && (mi = findModuleInfo(modInfo, modName))) { - if ((mi->major == DRIVER_NET) && (mi->minor == DRIVER_MINOR_ETHERNET)) { - deviceCount = ethCount("eth"); - } else if ((mi->major == DRIVER_NET) && (mi->minor == DRIVER_MINOR_TR)) { - deviceCount = ethCount("tr"); - } + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + close(fd); - if (mi->major == DRIVER_SCSI) { - deviceCount = scsiDiskCount(); - if (!FL_CMDLINE(flags)) { - startNewt(); - scsiWindow(modName); - popWindow = 1; + 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"); } + rc = execv("/sbin/modprobe", argv); + _exit(rc); } - /* look to see if there are options for this module specified on - * the command line. should be specified in the form of - * module.option=value - */ - cmdlineArgs = cmdLineModuleOpts(modName); - if (!args && cmdlineArgs) { - args = cmdlineArgs; - } else if (cmdlineArgs) { - for (i=0, arg = args; *arg; arg++, i++); - for (arg = cmdlineArgs; *arg; arg++, i++); - args = realloc(args, sizeof(*newArgs) * (i + 1)); - for (i=0, arg = args; *arg; arg++, i++); - for (arg = cmdlineArgs; *arg; arg++, i++) - args[i] = strdup(*arg); - args[i] = NULL; - } + waitpid(child, &status, 0); - sprintf(fileName, "%s.ko", modName); - for (argPtr = args; argPtr && *argPtr; argPtr++) { - strcat(fileName, " "); - strcat(fileName, *argPtr); - } - - if (FL_TESTING(flags)) { - logMessage(INFO, "would have insmod %s (%s)", path->path, fileName); - rc = 0; + if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) { + return 1; } 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) || (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) && - (mi->minor == DRIVER_MINOR_ETHERNET)) { - modLoaded->mods[num].firstDevNum = deviceCount; - modLoaded->mods[num].lastDevNum = ethCount("eth") - 1; - } else if ((mi->major == DRIVER_NET) && - (mi->minor == DRIVER_MINOR_TR)) { - modLoaded->mods[num].firstDevNum = deviceCount; - modLoaded->mods[num].lastDevNum = ethCount("tr") - 1; - } else if (mi->major == DRIVER_SCSI) { - /* FIXME: this is a hack, but usb-storage seems to - * like to take forever to enumerate. try to - * give it some time */ - if (!strcmp(modName, "usb-storage") && !usbWasLoaded) { - int slp; - usbWasLoaded = 1; - for (slp = 0; slp < 10; slp++) { - if (scsiDiskCount() > deviceCount) break; - sleep(2); - } - logMessage(DEBUGLVL, "slept %d seconds", slp * 2); - } - modLoaded->mods[num].firstDevNum = deviceCount; - modLoaded->mods[num].lastDevNum = scsiDiskCount(); - } - } - } 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; -} - -/* - * This takes the list of modules we're going to load and sorts - * some to be at the end on an arbitrary criteria (eg, fiberchannel). - * This should help the problems where people's FC controller ends up being - * sda and they then can't boot or otherwise have things being strange. - * And yes, this is a hack. *sigh* - */ -static char ** lateModuleSort(char **allmods, int num) { - int i, j, k, l; - char ** modList; - /* the qlogic drivers are usually for fibrechannel according to coughlan - * as is lpfc. ibmvscsic needs to be sure to be loaded after ipr on - * power5 due to bug #137920 */ - char * lateList[] = { "qla2100", "qla2200", "qla2300", "qla2322", - "qla6312", "qla6322", "qla2400", "qla2xxx", - "lpfc", "ibmvscsic", "pata_pcmcia", NULL }; - char ** lateMods; - - for (i=0; allmods[i]; i++) {} - modList = malloc(sizeof(*modList) * (num + i + 1)); - - lateMods = alloca(sizeof(*lateMods) * 10); - lateMods = memset(lateMods, 0, 10); - - i = j = k = l = 0; - - for (; allmods[i]; i++) { - int late = 0; - for (j = 0; lateList[j]; j++) { - if (!strcmp(allmods[i], lateList[j])) { - lateMods[l++] = allmods[i]; - late = 1; - break; - } - } - if (!late) - modList[k++] = allmods[i]; - } - - for (i = 0; i < l; i++) { - modList[k++] = lateMods[i]; + return 0; } - modList[k] = NULL; - - return modList; } -/* 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, - const char * argModule, char ** args) { - char * modNames; - char * start, * next, * end; - char ** initialList; - char ** list, ** l; - char items[1024] = ""; /* 1024 characters should be enough... */ - struct extractedModule * paths, * p; - struct loadedModuleInfo * mod; +void mlRemoveBlacklist(char *module) { 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++; + for (i = 0 ; i < numblacklists ; i++) { + if (!strcmp(blacklists[i], module)) + blacklists[i] = NULL; } +} - 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; - } - list = lateModuleSort(list, i); - - for (i = 0; list[i]; i++) { - strcat(items, " "); - strcat(items, list[i]); - } - - logMessage(INFO, "modules to insert%s", items); - - paths = NULL; - reloadUsbStorage = 0; - if (modInfo) { - for (i = 0; list[i]; i++) { - mi = findModuleInfo(modInfo, list[i]); - if (mi) { - if (mi->locationID) - paths = extractModules(list, paths, mi->locationID); - - if (mi->major == DRIVER_SCSI) { - if ((mod = getLoadedModuleInfo(modLoaded, "usb-storage")) && - mod->firstDevNum != mod->lastDevNum) { - logMessage(DEBUGLVL, "setting reloadUsbStorage"); - reloadUsbStorage = 1; - } - } - - } - } - } - - paths = extractModules(list, paths, NULL); - - i = 0; - if (!paths) { - logMessage(ERROR, "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(DEBUGLVL, "module(s) %s not found", items); - - if (reloadUsbStorage) { - mod = getLoadedModuleInfo(modLoaded, "usb-storage"); - - if (!mod) { - fprintf(stderr, "ERROR: %s was in module list, but can't be found now", "usb-storage"); - exit(1); - } - - if (mod->lastDevNum != scsiDiskCount()) { - logMessage(WARNING, "usb-storage isn't claiming the last scsi dev (%d vs %d)", modLoaded->mods[i].lastDevNum, scsiDiskCount()); - /* JKFIXME: return? or not, because of firewire */ - } - - /* here we need to save the state of stage2 */ - logMessage(INFO, "unloading module usb-storage"); - removeLoadedModule("usb-storage", modLoaded); - - - /* 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)) { - logMessage(ERROR, "failed to insert %s", p->path); - } else { - logMessage(INFO, "inserted %s", p->path); - } - } - - if (reloadUsbStorage) { - logMessage(INFO, "reloading module usb-storage"); - mlLoadModule("usb-storage", modLoaded, modDeps, modInfo, NULL); - /* JKFIXME: here's the rest of the hacks. basically do the reverse - * of what we did before. - */ - } - - if (!FL_TESTING(flags)) - writeModulesConf(modLoaded, "/tmp/modprobe.conf"); - - for (p = paths; p->path; p++) { - unlink(p->path); - free(p->path); - if (p->location) free(p->location); - } - - free(paths); - free(list); - - logMessage(INFO, "load module set done"); - - return i; +void mlInitModuleConfig() { + readModuleOpts(); + readBlacklist(); + writeModulesConf("/etc/modprobe.d/anaconda"); } /* load a module with a given list of arguments */ -int mlLoadModule(const char * module, moduleList modLoaded, - moduleDeps modDeps, moduleInfoSet modInfo, - char ** args) { - return doLoadModules(module, modLoaded, modDeps, modInfo, module, - args); +int mlLoadModule(const char * module, char ** args) { + return doLoadModule(module, args); } /* loads a : separated list of modules */ -int mlLoadModuleSet(const char * modNames, - moduleList modLoaded, moduleDeps modDeps, - moduleInfoSet modInfo) { - return doLoadModules(modNames, modLoaded, modDeps, modInfo, - NULL, NULL); -} - -static int removeHostAdapter(char *conf, char *name) { - FILE *in = NULL, *out = NULL; - int nhbas = 0; - char *newconf = NULL; - int ret = 0; - - if (asprintf(&newconf, "%s.new", conf) < 0) - return ret; - - if (!(out = fopen(newconf, "w+"))) { - free(newconf); - return ret; - } - - if (!(in = fopen(conf, "r"))) { - fclose(out); - unlink(newconf); - free(newconf); - return ret; - } - - do { - size_t n = 0; - char *buf = NULL; - int d = 0, m = 0; - - if (getline(&buf, &n, in) < 0) - break; - - if (ret || strncmp(buf, "alias scsi_hostadapter", 22)) { - fputs(buf, out); - free(buf); - continue; - } - - if (buf[22] != ' ') - sscanf(buf+22, "%d %n", &d, &m); +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 - sscanf(buf+22, " %n", &m); - if (!ret) { - if (strncmp(buf+22+m, name, strlen(name))) { - if (nhbas) - fprintf(out, "alias scsi_hostadapter%d %s", nhbas, buf+22+m); - else - fprintf(out, "alias scsi_hostadapter %s", buf+22+m); - nhbas++; - } else { - logMessage(INFO, "removed usb-storage from modprobe.conf"); - ret++; - } - } - free(buf); - } while (1); - - fclose(in); - fclose(out); - unlink(conf); - rename(newconf, conf); - free(newconf); - return ret; + name = NULL; + } + return rc; } -static int writeModulesConf(moduleList list, char *conf) { - int i, ret; - struct loadedModuleInfo * lm; - int ethNum; - int scsiNum; - char buf[16384], buf2[512]; /* these will be enough for anyone... */ - char * tmp, ** arg; - int fd; - static int once = 0; - - if (!once) - once = removeHostAdapter(conf, "usb-storage"); - scsiNum = scsiCount(conf); +static int writeModulesConf(char *conf) { + int i; + char buf[16384]; + int fd, rc; - if (!list) return 0; + if (!conf) + conf = "/tmp/modprobe.conf"; - fd = open("/tmp/modprobe.conf", O_WRONLY | O_CREAT | O_APPEND, 0666); + fd = open(conf, O_WRONLY | O_CREAT, 0644); if (fd == -1) { - logMessage(ERROR, "error appending to /tmp/modprobe.conf: %s\n", - strerror(errno)); + logMessage(ERROR, "error opening to %s: %s\n", + conf, strerror(errno)); return 0; } + strcat(buf, "# Module options and blacklists written by anaconda\n"); + for (i = 0; i < nummodopts ; i++) { + int j; - for (i = 0, lm = list->mods; i < list->numModules; i++, lm++) { - if (!lm->weLoaded) continue; - if (lm->written) continue; - - if (lm->major != DRIVER_NONE) { - strcpy(buf, "alias "); - switch (lm->major) { - case DRIVER_SCSI: - /* originally set to # of scsi_hostadapter already in - * /tmp/modprobe.conf. then we increment ourselves */ - if (scsiNum) - sprintf(buf2, "scsi_hostadapter%d ", scsiNum); - else - strcpy(buf2, "scsi_hostadapter "); - scsiNum++; - strcat(buf, buf2); - - strcat(buf, lm->name); - strcat(buf, "\n"); - ret = write(fd, buf, strlen(buf)); - lm->written = 1; - - break; - - case DRIVER_NET: - switch(lm->minor) { - case DRIVER_MINOR_ETHERNET: - tmp = "eth"; - break; - case DRIVER_MINOR_TR: - tmp = "tr"; - break; - default: - logMessage(WARNING, "got net driver that's not ethernet or tr"); - tmp = ""; - } - - if (lm->firstDevNum > lm->lastDevNum) break; - - for (ethNum = lm->firstDevNum; - ethNum <= lm->lastDevNum; ethNum++) { - sprintf(buf2, "%s%d ", tmp, ethNum); - if (ethNum != lm->lastDevNum) { - strcat(buf2, lm->name); - strcat(buf2, "\nalias "); - } - strcat(buf, buf2); - } - - strcat(buf, lm->name); - strcat(buf, "\n"); - ret = write(fd, buf, strlen(buf)); - lm->written = 1; - - break; - - default: - break; - } - - } - - if (lm->args) { - strcpy(buf, "options "); - strcat(buf, lm->name); - for (arg = lm->args; *arg; arg++) { - strcat(buf, " "); - strcat(buf, *arg); - } - strcat(buf, "\n"); - ret = write(fd, buf, strlen(buf)); - lm->written = 1; - } - } - - close(fd); - return 0; -} - -/* writes out /tmp/scsidisks with a scsi disk / module correspondence. - * format is sd%c adapter - */ -void writeScsiDisks(moduleList list) { - int i, fd, num, ret; - struct loadedModuleInfo * lm; - char buf[512]; - - if (!list) return; - - if ((fd = open("/tmp/scsidisks", O_WRONLY | O_CREAT, 0666)) == -1) { - logMessage(ERROR, "error opening /tmp/scsidisks: %s", strerror(errno)); - return; - } - - for (i = 0, lm = list->mods; i < list->numModules; i++, lm++) { - if (!lm->weLoaded) continue; - if (lm->major != DRIVER_SCSI) continue; - - for (num = lm->firstDevNum; num < lm->lastDevNum; num++) { - if (num < 26) - sprintf(buf, "sd%c\t%s\n", 'a' + num, lm->name); - else { - unsigned int one, two; - one = num / 26; - two = num % 26; - - sprintf(buf, "sd%c%c\t%s\n", 'a' + one - 1, - 'a' + two, lm->name); - } - ret = write(fd, buf, strlen(buf)); + 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"); } - - close(fd); - return; -} - -char * getModuleLocation(int version) { - struct utsname u; - static char * arch = NULL; - const char * archfile = "/etc/arch"; - char * ret; - int rc; - - uname(&u); - - if (!arch && !access(archfile, R_OK)) { - struct stat sb; - int fd; - - stat(archfile, &sb); - arch = malloc(sb.st_size + 1); - - fd = open(archfile, O_RDONLY); - rc = read(fd, arch, sb.st_size); - if (arch[sb.st_size -1 ] == '\n') - sb.st_size--; - arch[sb.st_size] = '\0'; - close(fd); - } else if (!arch) { - logMessage(WARNING, "can't find arch file %s, defaulting to %s", - archfile, u.machine); - arch = strdup(u.machine); - } - - if (version == 1) { - ret = malloc(strlen(u.release) + strlen(arch) + 2); - sprintf(ret, "%s/%s", u.release, arch); - } else { - ret = malloc(strlen(u.release) + 1); - strcpy(ret, u.release); - } - - logMessage(DEBUGLVL, "getModuleLocation: %s", ret); - return ret; -} - -/* 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; - char * modpath; - - if (!location) { - ballPath = strdup("/modules/modules.cgz"); - modpath = getModuleLocation(CURRENT_MODBALLVER); - } else { - ballPath = strdup(location->path); - modpath = getModuleLocation(location->version); - } - - fd = gunzip_open(ballPath); - if (!fd) { - logMessage(ERROR, "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(modpath) + - strlen(*m) + 25); - sprintf(map[numMaps].archivePath, "%s/%s.ko", modpath, *m); - map[numMaps].fsPath = alloca(10 + strlen(*m)); - sprintf(map[numMaps].fsPath, "/tmp/%s.ko", *m); - unlink(map[numMaps].fsPath); - map[numMaps].mapFlags = CPIO_MAP_PATH; - numMaps++; - } - } - - if (!numMaps) { - gunzip_close(fd); - free(ballPath); - free(modpath); - 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.ko", 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(INFO, "module %s found on driver disk %s", - modNames[i], location->title); - logMessage(INFO, "loaded %s from %s", modNames[i], - location->path); - } else - logMessage(INFO, "loaded %s from /modules/modules.cgz", modNames[i]); - } - numMaps++; + for (i = 0; i < numblacklists ; i++) { + if (blacklists[i]) { + strcat(buf, "blacklist "); + strcat(buf, blacklists[i]); + strcat(buf, "\n"); } } - - free(ballPath); - free(modpath); - return oldPaths; -} - - - -/* remove a module which has been loaded, including removal from the - * modLoaded struct - */ -int removeLoadedModule(const char * modName, moduleList modLoaded) { - int status, rc = 0; - pid_t child; - struct loadedModuleInfo * mod; - - mod = getLoadedModuleInfo(modLoaded, modName); - if (!mod) - return 0; - - /* since we're unloading, set the devs to 0. this should hopefully only - * ever happen with things at the end */ - mod->firstDevNum = 0; - mod->lastDevNum = 0; - if (FL_TESTING(flags)) { - logMessage(INFO, "would have rmmod %s", modName); - rc = 0; - } else { - logMessage(INFO, "going to rmmod %s", modName); - if (!(child = fork())) { - int fd = open("/dev/tty3", O_RDWR); - - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - close(fd); - - execl("/sbin/rmmod", "/sbin/rmmod", modName, NULL); - _exit(rc); - } - - waitpid(child, &status, 0); - - if (!WIFEXITED(status) || WEXITSTATUS(status)) { - rc = 1; - } else { - int found = -1; - int i; - - /* find our module. once we've found it, shutffle everything - * else back one */ - for (i = 0; i < modLoaded->numModules; i++) { - if (found > -1) { - modLoaded->mods[i - 1] = modLoaded->mods[i]; - } else if (!strcmp(modLoaded->mods[i].name, modName)) { - found = i; - free(modLoaded->mods[i].name); - free(modLoaded->mods[i].path); - } - } - modLoaded->numModules--; - - rc = 0; - } - } - return rc; + rc = write(fd, buf, strlen(buf)); + close(fd); + return (rc != strlen(buf)); } void loadKickstartModule(struct loaderData_s * loaderData, int argc, @@ -1190,7 +358,5 @@ void loadKickstartModule(struct loaderData_s * loaderData, int argc, } - mlLoadModule(module, loaderData->modLoaded, *(loaderData->modDepsPtr), - loaderData->modInfo, args); + mlLoadModule(module, args); } - diff --git a/loader2/modules.h b/loader2/modules.h index bbcc905..b0f7f2d 100644 --- a/loader2/modules.h +++ b/loader2/modules.h @@ -2,43 +2,9 @@ #define H_MODULES #include "moduleinfo.h" -#include "moduledeps.h" - -typedef struct moduleList_s * moduleList; - -struct loadedModuleInfo { - char * name; - char ** args; - int weLoaded; - int written; - char * path; - int firstDevNum, lastDevNum; - enum driverMajor major; - enum driverMinor minor; -}; - -struct extractedModule { - char * path; - char * location; -}; - -struct moduleList_s { - struct loadedModuleInfo mods[100]; - int numModules; -}; - -int mlReadLoadedList(moduleList * mlp); -int mlLoadModule(const char * module, moduleList modLoaded, - moduleDeps modDeps, moduleInfoSet modInfo, - char ** args); -int mlLoadModuleSet(const char * modNames, - moduleList modLoaded, moduleDeps modDeps, - moduleInfoSet modInfo); - -int mlModuleInList(const char * modName, moduleList list); -void writeScsiDisks(moduleList list); - -int removeLoadedModule(const char * modName, moduleList modLoaded); -char * getModuleLocation(int version); +void mlInitModuleConfig(); +int mlLoadModule(const char * module, char ** args); +int mlLoadModuleSet(const char * modNames); +void mlRemoveBlacklist(char *module); #endif -- 1.5.3.7 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list