#include #include #include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "isys/imount.h" #include "../isys/isys.h" #include "lang.h" #include "loader.h" #include "log.h" #include "misc.h" #include "modules.h" #include "windows.h" #include "../kudzu/kudzu.h" #include "isys/cpio.h" void eject(char * deviceName) { int fd; #if !defined(__sparc__) if (!strncmp(deviceName, "fd", 2)) return; #endif logMessage("ejecting floppy"); devMakeInode(deviceName, "/tmp/ejectDevice"); fd = open("/tmp/ejectDevice", O_RDONLY); ioctl(fd, FDEJECT, 1); close(fd); unlink("/tmp/ejectDevice"); } static int getModuleArgs(struct moduleInfo * mod, char *** argPtr) { struct newtWinEntry * entries; int i; int numArgs; char ** values; char * chptr, * end; int misc = -1; char ** args; int argc; int rc; char * text; entries = alloca(sizeof(*entries) * (mod->numArgs + 2)); values = alloca(sizeof(*values) * (mod->numArgs + 2)); for (i = 0; i < mod->numArgs; i++) { entries[i].text = mod->args[i].description; if (mod->args[i].arg) { int io = !strcmp (mod->args[i].arg, "io"); values[i] = malloc(strlen(mod->args[i].arg) + (io ? 4 : 2)); strcpy(values[i], mod->args[i].arg); strcat(values[i], (io ? "=0x" : "=")); } else { values[i] = NULL; } entries[i].value = values + i; entries[i].flags = NEWT_FLAG_SCROLL; } numArgs = i; if (!(mod->flags & MI_FLAG_NOMISCARGS)) { values[i] = NULL; entries[i].text = _("Miscellaneous"); entries[i].value = values + i; entries[i].flags = NEWT_FLAG_SCROLL; misc = i; i++; } entries[i].text = (void *) entries[i].value = NULL; text = _("This module can take parameters which affects its " "operation. If you don't know what parameters to supply, " "just skip this screen by pressing the \"OK\" button " "now."); rc = newtWinEntries(_("Module Parameters"), text, 40, 5, 15, 20, entries, _("OK"), _("Back"), NULL); if (rc == 2) { for (i = 0; i < numArgs; i++) if (values[i]) free(values[i]); return LOADER_BACK; } /* we keep args big enough for the args we know about, plus a NULL */ args = malloc(sizeof(*args) * (numArgs + 1)); argc = 0; for (i = 0; i < numArgs; i++) { if (values[i] && *values[i]) { chptr = values[i] + strlen(values[i]) - 1; while (isspace(*chptr)) chptr--; if (*chptr != '=') args[argc++] = values[i]; } } if (misc >= 0 && values[misc]) { chptr = values[misc]; i = 1; while (*chptr) { if (isspace(*chptr)) i++; chptr++; } args = realloc(args, sizeof(*args) * (argc + i + 1)); chptr = values[misc]; while (*chptr) { while (*chptr && isspace(*chptr)) chptr++; if (!*chptr) break; end = chptr; while (!isspace(*end) && *end) end++; args[argc] = malloc(end - chptr + 1); memcpy(args[argc], chptr, end - chptr); args[argc][end - chptr] = '\0'; argc++; chptr = end; } free(values[misc]); } args[argc] = NULL; *argPtr = args; return 0; } int devInitDriverDisk(moduleInfoSet modInfo, moduleList modLoaded, moduleDeps *modDepsPtr, int flags, char * mntPoint, struct driverDiskInfo * ddi) { int badDisk = 0; char from[200], to[200]; struct stat sb; static int ddNum = 0; char * diskName; FILE * f; int fd; char * fileCheck[] = { "rhdd-6.1", "modinfo", "modules.dep", "pcitable", NULL }; char ** fnPtr; for (fnPtr = fileCheck; *fnPtr; fnPtr++) { sprintf(from, "%s/%s", mntPoint, *fnPtr); if (access(from, R_OK)) { logMessage("cannot find %s; bad driver disk", from); badDisk = 1; } } sprintf(from, "%s/rhdd-6.1", mntPoint); stat(from, &sb); if (!sb.st_size) badDisk = 1; if (badDisk) return 1; diskName = malloc(sb.st_size + 1); fd = open(from, O_RDONLY); read(fd, diskName, sb.st_size); if (diskName[sb.st_size - 1] == '\n') sb.st_size--; diskName[sb.st_size] = '\0'; close(fd); ddi->title = strdup(diskName); sprintf(from, "%s/modinfo", mntPoint); fd = isysReadModuleInfo(from, modInfo, ddi); sprintf(from, "%s/modules.dep", mntPoint); mlLoadDeps(modDepsPtr, from); sprintf(from, "%s/pcitable", mntPoint); pciReadDrivers(from); /* save this modinfo file for later -- we may need it again in ddReadDriverDiskModInfo() */ sprintf(to, "/tmp/DD-%d", ddNum); mkdirChain(to); sprintf(from, "%s/modinfo", mntPoint); sprintf(to, "/tmp/DD-%d/modinfo", ddNum); if (copyFile(from, to)) return 0; sprintf(to, "/tmp/DD-%d/diskInfo", ddNum); f = fopen(to, "w"); fprintf(f, "%s\n", ddi->title); fprintf(f, "%s\n", ddi->mntDevice); fprintf(f, "%s\n", ddi->fs); fprintf(f, "%s\n", ddi->device ? ddi->device : "(NONE)"); fclose(f); ddNum++; return 0; } int devLoadDriverDisk(moduleInfoSet modInfo, moduleList modLoaded, moduleDeps *modDepsPtr, int flags, int cancelNotBack, int askForExistence, char * device) { int rc; int done = 0; struct driverDiskInfo * ddi; ddi = calloc(sizeof(*ddi), 1); do { if (askForExistence) { rc = newtWinChoice(_("Devices"), _("Yes"), _("No"), _("Do you have a driver disk?")); if (rc == 2) return LOADER_BACK; } eject(device); rc = newtWinChoice(_("Devices"), _("OK"), cancelNotBack ? _("Cancel") : _("Back"), _("Insert your driver disk and press \"OK\" to continue.")); if (rc == 2) return LOADER_BACK; mlLoadModule("vfat", NULL, modLoaded, (*modDepsPtr), NULL, modInfo, flags); ddi->device = strdup(device); ddi->mntDevice = malloc(strlen(device) + 10); sprintf(ddi->mntDevice, "/tmp/%s", device); devMakeInode(ddi->device, ddi->mntDevice); ddi->fs = "vfat"; logMessage("trying to mount device %s", ddi->mntDevice); if (doPwMount(ddi->mntDevice, "/tmp/drivers", ddi->fs, 1, 0, NULL, NULL)) { ddi->fs = "ext2"; if (doPwMount(ddi->mntDevice, "/tmp/drivers", ddi->fs, 1, 0, NULL, NULL)) newtWinMessage(_("Error"), _("OK"), _("Failed to mount driver disk.")); } if (devInitDriverDisk(modInfo, modLoaded, modDepsPtr, flags, "/tmp/drivers", ddi)) newtWinMessage(_("Error"), _("OK"), _("The floppy disk you inserted is not a valid driver disk " "for this release of Red Hat Linux.")); else done = 1; umount("/tmp/drivers"); } while (!done); return 0; } struct sortModuleList { int index; moduleInfoSet modInfo; }; static int sortDrivers(const void * a, const void * b) { const struct sortModuleList * one = a; const struct sortModuleList * two = b; return strcmp(one->modInfo->moduleList[one->index].description, one->modInfo->moduleList[two->index].description); } static int pickModule(moduleInfoSet modInfo, enum driverMajor type, moduleList modLoaded, moduleDeps * modDepsPtr, struct moduleInfo * suggestion, struct moduleInfo ** modp, int * specifyParams, char * ddDevice, int flags) { int i; newtComponent form, text, listbox, checkbox, ok, back; newtGrid buttons, grid, subgrid; char specifyParameters = *specifyParams ? '*' : ' '; struct newtExitStruct es; struct sortModuleList * sortedOrder; int numSorted; do { sortedOrder = malloc(sizeof(*sortedOrder) * modInfo->numModules); numSorted = 0; for (i = 0; i < modInfo->numModules; i++) { if (modInfo->moduleList[i].major == type && !mlModuleInList(modInfo->moduleList[i].moduleName, modLoaded)) { sortedOrder[numSorted].index = i; sortedOrder[numSorted++].modInfo = modInfo; } } if (!numSorted) { /* If nothing appears in this list, force them to insert a driver disk. */ i = devLoadDriverDisk(modInfo, modLoaded, modDepsPtr, flags, 0, 1, ddDevice); if (i) return i; continue; } qsort(sortedOrder, numSorted, sizeof(*sortedOrder), sortDrivers); text = newtTextboxReflowed(-1, -1, _("Which driver should I try?. " "If the driver you need does not appear in this list, and " "you have a separate driver disk, please press F2."), 30, 0, 10, 0); listbox = newtListbox(-1, -1, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT); buttons = newtButtonBar(_("OK"), &ok, _("Back"), &back, NULL); checkbox = newtCheckbox(-1, -1, _("Specify module parameters"), specifyParameters, NULL, &specifyParameters); form = newtForm(NULL, NULL, 0); newtFormAddHotKey(form, NEWT_KEY_F2); for (i = 0; i < numSorted; i++) { char buf[80]; int num = sortedOrder[i].index; snprintf (buf, sizeof(buf), "%s (%s)", modInfo->moduleList[num].description, modInfo->moduleList[num].moduleName); newtListboxAppendEntry(listbox, buf, (void *) num); if (modp && (modInfo->moduleList + num) == *modp) newtListboxSetCurrentByKey(listbox, (void *) num); } subgrid = newtGridVStacked(NEWT_GRID_COMPONENT, listbox, NEWT_GRID_COMPONENT, checkbox, NULL); grid = newtGridBasicWindow(text, subgrid, buttons); newtGridAddComponentsToForm(grid, form, 1); newtGridWrappedWindow(grid, _("Devices")); newtFormRun(form, &es); i = (int) newtListboxGetCurrent(listbox); newtGridFree(grid, 1); newtFormDestroy(form); newtPopWindow(); free(sortedOrder); if (es.reason == NEWT_EXIT_COMPONENT && es.u.co == back) { return LOADER_BACK; } else if (es.reason == NEWT_EXIT_HOTKEY && es.u.key == NEWT_KEY_F2) { devLoadDriverDisk(modInfo, modLoaded, modDepsPtr, flags, 0, 0, ddDevice); continue; } else { break; } } while (1); *specifyParams = (specifyParameters != ' '); *modp = modInfo->moduleList + i; return 0; } int devDeviceMenu(enum driverMajor type, moduleInfoSet modInfo, moduleList modLoaded, moduleDeps * modDepsPtr, char * ddDevice, int flags, char ** moduleName) { struct moduleInfo * mod = NULL; enum { S_MODULE, S_ARGS, S_DONE } stage = S_MODULE; int rc; char ** args = NULL, ** arg; int specifyArgs = 0; while (stage != S_DONE) { switch (stage) { case S_MODULE: if ((rc = pickModule(modInfo, type, modLoaded, modDepsPtr, mod, &mod, &specifyArgs, ddDevice, flags))) return LOADER_BACK; stage = S_ARGS; break; case S_ARGS: if (specifyArgs) { rc = getModuleArgs(mod, &args); if (rc) { stage = S_MODULE; break; } } stage = S_DONE; break; case S_DONE: } } if (mod->major == DRIVER_SCSI) { scsiWindow(mod->moduleName); sleep(1); } rc = mlLoadModule(mod->moduleName, mod->locationID, modLoaded, *modDepsPtr, args, modInfo, flags); if (mod->major == DRIVER_SCSI) newtPopWindow(); if (args) { for (arg = args; *arg; arg++) free(*arg); free(args); } if (rc) newtWinMessage(_("Error"), _("OK"), _("Failed to insert %s module."), mod->moduleName); if (!rc && moduleName) *moduleName = mod->moduleName; return rc; } char * extractModule(struct driverDiskInfo * ddi, char * modName) { char * pattern[] = { NULL, NULL }; struct utsname un; gzFile from; gzFile to; int first = 1; int fd; char * buf; struct stat sb; int rc; int failed; char * toPath; char * chptr; uname(&un); /* strip off BOOT, -SMP, whatever */ chptr = un.release + strlen(un.release) - 1; while (!isdigit(*chptr)) chptr--; *(chptr + 1) = '\0'; pattern[0] = alloca(strlen(modName) + strlen(un.release) + 5); sprintf(pattern[0], "%s*/%s.o", un.release, modName); logMessage("extracting pattern %s", pattern[0]); if (ddi->device) devMakeInode(ddi->device, ddi->mntDevice); while (1) { failed = 0; if (doPwMount(ddi->mntDevice, "/tmp/drivers", ddi->fs, 1, 0, NULL, NULL)) failed = 1; if (failed && !first) { newtWinMessage(_("Error"), _("OK"), _("Failed to mount driver disk: %s."), strerror(errno)); } else if (!failed) { if ((fd = open("/tmp/drivers/rhdd-6.1", O_RDONLY)) < 0) failed = 1; if (!failed) { fstat(fd, &sb); buf = malloc(sb.st_size + 1); read(fd, buf, sb.st_size); if (buf[sb.st_size - 1] == '\n') sb.st_size--; buf[sb.st_size] = '\0'; close(fd); failed = strcmp(buf, ddi->title); free(buf); } if (failed && !first) { umount("/tmp/drivers"); newtWinMessage(_("Error"), _("OK"), _("The wrong diskette was inserted.")); } } if (!failed) { from = gzopen("/tmp/drivers/modules.cgz", "r"); toPath = malloc(strlen(modName) + 30); sprintf(toPath, "/tmp/modules/%s", modName); mkdirChain(toPath); strcat(toPath, "/modules.cgz"); to = gzopen(toPath, "w"); winStatus(50, 3, _("Loading"), _("Loading %s driver..."), modName); myCpioFilterArchive(from, to, pattern); newtPopWindow(); gzclose(from); gzclose(to); umount("/tmp/drivers"); sprintf(toPath, "/tmp/modules/%s", modName); return toPath; } first = 0; if (ddi->device) eject(ddi->device); rc = newtWinChoice(_("Driver Disk"), _("OK"), _("Cancel"), _("Please insert the %s driver disk now."), ddi->title); if (rc == 2) return NULL; } } void ddReadDriverDiskModInfo(moduleInfoSet modInfo) { int num = 0; char fileName[80]; struct stat sb; FILE * f; struct driverDiskInfo * ddi; sprintf(fileName, "/tmp/DD-%d/diskInfo", num); while (!access(fileName, R_OK)) { stat(fileName, &sb); f = fopen(fileName, "r"); ddi = malloc(sizeof(*ddi)); ddi->title = readLine(f); ddi->mntDevice = readLine(f); ddi->fs = readLine(f); ddi->device = readLine(f); if (!strcmp("(NONE)", ddi->device)) { free(ddi->device); ddi->device = NULL; } fclose(f); sprintf(fileName, "/tmp/DD-%d/modinfo", num); isysReadModuleInfo(fileName, modInfo, ddi); sprintf(fileName, "/tmp/DD-%d/diskName", ++num); } }