diff options
Diffstat (limited to 'loader/moduleinfo.c')
-rw-r--r-- | loader/moduleinfo.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/loader/moduleinfo.c b/loader/moduleinfo.c new file mode 100644 index 0000000..2e0ab77 --- /dev/null +++ b/loader/moduleinfo.c @@ -0,0 +1,276 @@ +/* + * moduleinfo.c - module info functionality + * + * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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 <http://www.gnu.org/licenses/>. + * + * Author(s): Erik Troan <ewt@redhat.com> + * Matt Wilson <msw@redhat.com> + */ + +#include <alloca.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <stdio.h> + +#include "moduleinfo.h" + +struct moduleInfo * getModuleList(moduleInfoSet mis, + enum driverMajor major) { + struct moduleInfo * miList, * next; + int i; + + next = miList = malloc(sizeof(*miList) * mis->numModules + 1); + for (i = 0; i < mis->numModules; i++) { + if (mis->moduleList[i].major == major || major == DRIVER_NONE) { + *next = mis->moduleList[i]; + next++; + } + } + + if (next == miList) { + free(next); + return NULL; + } + + next->moduleName = NULL; + next++; + + miList = realloc(miList, sizeof(*miList) * (next - miList)); + return miList; +} + +struct moduleInfo * findModuleInfo(moduleInfoSet mis, + const char * moduleName) { + int i; + struct moduleInfo * found = NULL; + + for (i = 0; i < mis->numModules; i++) { + if (!strcmp(moduleName, mis->moduleList[i].moduleName)) { + if (!found) + found = mis->moduleList + i; + else if (found->locationID && !mis->moduleList[i].locationID) + ; + else + found = mis->moduleList + i; + } + } + + return found; +} + +moduleInfoSet newModuleInfoSet(void) { + return calloc(sizeof(struct moduleInfoSet_s), 1); +} + +/* filename: file to read module-info from + * mis: moduleInfoSet + * location: moduleBallLocation struct describing the location of + * these modules. (may be NULL) + * override: 1 if modules from this module ball should override old ones + * of the same name. + */ +int readModuleInfo(const char * filename, moduleInfoSet mis, + void * location, int override) { + int fd, isIndented; + char * buf, * start, * next = NULL, * chptr; + struct stat sb; + char oldch; + struct moduleInfo * nextModule; + int modulesAlloced; + int i; + int found = 0, skipModule = 0; + + fd = open(filename, O_RDONLY); + if (fd < 0) return -1; + + fstat(fd, &sb); + buf = alloca(sb.st_size + 1); + i = read(fd, buf, sb.st_size); + buf[sb.st_size] = '\0'; + close(fd); + + if (i != sb.st_size) + return -1; + + nextModule = NULL; + modulesAlloced = mis->numModules; + + if (strncmp(buf, "Version 0\n", 10)) return -1; + + start = buf + 10; + while (start && *start) { + chptr = strchr(start, '\n'); + if (chptr) { + /* slice and dice */ + next = chptr + 1; + } else { + chptr += strlen(start) - 1; + } + + chptr--; + while (isspace(*chptr)) chptr--; + chptr++; + *chptr = '\0'; + + isIndented = 0; + if (isspace(*start)) { + while (isspace(*start) && *start != '\n') start++; + isIndented = 1; + } + + if (*start != '\n' && *start && *start != '#') { + if (!isIndented) { + if (nextModule && nextModule->moduleName && + nextModule == (mis->moduleList + mis->numModules)) { + mis->numModules++; + } + + if (mis->numModules == modulesAlloced) { + modulesAlloced += 5; + mis->moduleList = realloc(mis->moduleList, + modulesAlloced * sizeof(*mis->moduleList)); + } + + nextModule = NULL; + found = 0; + skipModule = 0; + for (i = 0; i < mis->numModules; i++) { + if (!strcmp(mis->moduleList[i].moduleName, start)) { + if (override) + nextModule = mis->moduleList + i; + else + skipModule = 1; + found = 1; + break; + } + } + + if (!found && !nextModule) { + nextModule = mis->moduleList + mis->numModules; + + nextModule->moduleName = strdup(start); + } + + if (nextModule) { + nextModule->major = DRIVER_NONE; + nextModule->minor = DRIVER_MINOR_NONE; + nextModule->description = NULL; + nextModule->flags = 0; + nextModule->args = NULL; + nextModule->numArgs = 0; + nextModule->locationID = location; + } + } else if (!nextModule && skipModule) { + /* we're skipping this one (not overriding), do nothing */ + } else if (!nextModule && skipModule) { + /* ACK! syntax error */ + fprintf(stderr, "module-info syntax error in %s\n", filename); + return 1; + } else if (nextModule->major == DRIVER_NONE) { + chptr = start + strlen(start) - 1; + while (!isspace(*chptr) && chptr > start) chptr--; + if (chptr != start) chptr++; + + if (!strcmp(chptr, "eth")) { + nextModule->major = DRIVER_NET; + nextModule->minor = DRIVER_MINOR_ETHERNET; + } else if (!strcmp(chptr, "tr")) { + nextModule->major = DRIVER_NET; + nextModule->minor = DRIVER_MINOR_TR; + } else if (!strcmp(chptr, "scsi_hostadapter") || + !strcmp(chptr, "scsi")) { + nextModule->major = DRIVER_SCSI; + } else if (!strcmp(chptr, "pcmcia")) { + nextModule->major = DRIVER_PCMCIA; + } else if (!strcmp(chptr, "fs")) { + nextModule->major = DRIVER_FS; + } else if (!strcmp(chptr, "cdrom")) { + nextModule->major = DRIVER_CDROM; + } else if (!strcmp(chptr, "ide")) { + nextModule->major = DRIVER_IDE; + } else { + nextModule->major = DRIVER_OTHER; + } + } else if (!nextModule->description) { + chptr = start + strlen(start) - 1; + if (*start == '"' && *chptr == '"') { + start++; + *chptr = '\0'; + nextModule->description = strdup(start); + } + } else { + nextModule->args = realloc(nextModule->args, + sizeof(*nextModule->args) * (nextModule->numArgs + 1)); + chptr = start; + while (!isspace(*chptr) && *chptr) chptr++; + if (*chptr) { + oldch = *chptr; + *chptr = '\0'; + nextModule->args[nextModule->numArgs].arg = strdup(start); + + start = chptr + 1; + while (*start && isspace(*start)) start++; + + if (*start == '"') { + start++; + chptr = strchr(start, '"'); + if (chptr) { + *chptr = '\0'; + nextModule->args[nextModule->numArgs].description = + strdup(start); + nextModule->numArgs++; + } + } + } + } + } + + start = next; + } + + /* do we need to add in this last module? */ + if (nextModule && ((nextModule - mis->moduleList) == mis->numModules)) + mis->numModules++; + + return 0; +} + +void freeModuleInfoSet(moduleInfoSet mis) { + int i, j; + + for (i = 0; i < mis->numModules; i++) { + if (mis->moduleList[i].moduleName) + free(mis->moduleList[i].moduleName); + + if (mis->moduleList[i].description) + free(mis->moduleList[i].description); + + for (j = 0; i < mis->moduleList[i].numArgs; j++) { + if (mis->moduleList[i].args[j].arg) + free(mis->moduleList[i].args[j].arg) ; + if (mis->moduleList[i].args[j].description) + free(mis->moduleList[i].args[j].description) ; + } + } + + free(mis); +} |