#include #include #include #include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "install.h" #include "kickstart.h" #include "log.h" #include "net.h" #include "perror.h" #include "run.h" #include "scsi.h" #include "windows.h" #include "pci-probing/pciprobe.h" #include "install.h" #define MODULES_PATH "/modules/" static char * plipDevice = NULL; /* hack */ struct devnum { char * name; short major, minor; int isChar; }; const static struct devnum devices[] = { { "aztcd", 29, 0, 0 }, { "bpcd", 41, 0, 0 }, { "cdu31a", 15, 0, 0 }, { "cdu535", 24, 0, 0 }, { "cm206cd", 32, 0, 0 }, { "fd0", 2, 0, 0 }, { "fd1", 2, 1, 0 }, { "gscd", 16, 0, 0 }, { "lp0", 6, 0, 1 }, { "lp1", 6, 1, 1 }, { "lp2", 6, 2, 1 }, { "mcd", 23, 0, 0 }, { "mcdx", 20, 0, 0 }, { "nst0", 9, 128, 1 }, { "optcd", 17, 0, 0 }, { "sbpcd", 25, 0, 0 }, { "scd0", 11, 0, 0 }, { "scd1", 11, 1, 0 }, { "sjcd", 18, 0, 0 }, }; const int numDevices = sizeof(devices) / sizeof(struct devnum); struct moduleOptions { char * arg; char * desc; char * defaults; } ; const struct moduleOptions neOptions[] = { { "io", "Base IO port:", "0x300:0x280:0x320:0x340:0x360" }, { "irq", "IRQ level:", NULL }, { NULL, NULL, NULL } } ; const struct moduleOptions de4x5Options[] = { { "io", "Base IO port:", "0x0b" }, { NULL, NULL, NULL } } ; const struct moduleOptions cdu31aOptions[] = { { "cdu31a", "IO base, IRQ, PAS?:", "" }, { NULL, NULL, NULL } } ; const struct moduleOptions cm206Options[] = { { "cm206", "IO base, IRQ:", "" }, { NULL, NULL, NULL } } ; const struct moduleOptions mcdOptions[] = { { "mcd", "IO base address:", "" }, { NULL, NULL, NULL } } ; const struct moduleOptions optcdOptions[] = { { "optcd", "IO base address:", "" }, { NULL, NULL, NULL } } ; const struct moduleOptions fdomainOptions[] = { { "setup_called", "Use other options", "1" }, { "port_base", "IO base address:", "0xd800" }, { "interrupt_level", "Interrupt level (IRQ):", "10" }, { NULL, NULL, NULL } } ; const struct moduleOptions sbpcdOptions[] = { { "sbpcd", "IO base, IRQ, label:", "" }, { NULL, NULL, NULL } } ; #define MODULE_AUTOPROBE (1 << 0) #define MODULE_FAKEAUTOPROBE (1 << 1) struct moduleInfo { char * name; int shouldAutoprobe; const struct moduleOptions * options; int flags; char * defaultOptions; } ; /* keep this alphabetical! */ struct moduleInfo modules[] = { { "8390", 1, NULL, 0, NULL }, { "cdu31a", 0, cdu31aOptions, 0, NULL }, { "cm206", 0, cm206Options, 0, NULL }, { "de4x5", 1, de4x5Options, MODULE_AUTOPROBE, "io=0" }, { "ds", 1, NULL, 0, NULL }, { "fdomain", 1, fdomainOptions, 0, NULL }, { "i82365", 1, NULL, 0, NULL }, { "isofs", 1, NULL, 0, NULL }, { "loop", 1, NULL, 0, NULL }, { "lp", 1, NULL, 0, NULL }, { "mcd", 0, mcdOptions, 0, NULL }, { "ne", 0, neOptions, MODULE_FAKEAUTOPROBE, "io=0x300" }, { "nfs", 1, NULL, 0, NULL }, { "optcd", 0, optcdOptions, 0, NULL }, { "pcmcia_core", 1, NULL, 0, NULL }, { "sbpcd", 1, sbpcdOptions, 0, NULL }, { "smbfs", 1, NULL, 0, NULL }, { "tcic", 1, NULL, 0, NULL }, { NULL, 0, NULL, 0, NULL } /* sentinel */ } ; struct driver { char * name; char * modules; int isLoaded; driverOkayFn okay; enum driverTypes type; enum driverMinor minor; }; static int checkEthernetDev(struct driver * dev); static int checkSCSIDev(struct driver * dev); static int checkPlipDev(struct driver * dev); static int checkTokenRingDev(struct driver * dev); static struct driver drivers[] = { { "3com 3c509", "3c509", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c59x (Vortex)", "3c59x", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c90x (Boomerang)", "3c59x", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c501", "3c501", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c503", "8390:3c503", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Allied Telesis AT1700", "at1700", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Apricot 82596", "apricot", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Cabletron E2100", "8390:e2100", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Digital 425,434,435,450,500", "de4x5", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Digital DEPCA and EtherWORKS", "depca", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Digital EtherWORKS 3", "ewrk3", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Digital 21040 (Tulip)", "tulip", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "D-Link DE-600 pocket adapter", "de600", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "D-Link DE-620 pocket adapter", "de620", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "HP10/100VG any LAN ", "hp100", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "HP LAN/AnyLan", "hp", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "HP PCLAN/plus", "8390:hp-plus", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Intel EtherExpress", "eexpress", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Intel EtherExpress Pro", "eepro", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Intel EtherExpress Pro 100", "eepro100", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NE2000 and compatible", "8390:ne", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NI 5210", "ni52", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NI 6510", "ni65", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "PLIP (parallel port)", "plip", 0, checkPlipDev, DRIVER_NET, DRIVER_MINOR_PLIP }, { "SMC 9000 series", "smc9194", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "SMC Ultra ethernet", "8390:smc-ultra", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Token Ring", "ibmtr", 0, checkTokenRingDev, DRIVER_NET, DRIVER_MINOR_TR }, { "WD8003, WD8013 and compatible", "8390:wd", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Adaptec 152x", "aha152x", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Adaptec 1542", "aha1542", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Adaptec 1740", "aha1740", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Adaptec 2740, 2840, 2940", "aic7xxx", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "AdvanSys Adapters", "advansys", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Always IN2000", "in2000", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "BusLogic Adapters", "BusLogic", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "DTC 3180/3280", "dtc", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "EATA DMA Adapters", "eata_dma", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "EATA PIO Adapters", "eata_pio", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Future Domain TMC-885, TMC-950", "seagate", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Future Domain TMC-16x0", "fdomain", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Iomega PPA3 (parallel port Zip)", "ppa", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "NCR 5380", "g_NCR5380", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "NCR 53c406a", "NCR53c406a", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "NCR 53c7xx", "53c7,8xx", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "NCR 53C8xx PCI", "ncr53c8xx", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Pro Audio Spectrum/Studio 16", "pas16", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Qlogic FAS", "qlogicfas", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Qlogic ISP", "qlogicisp", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Seagate ST01/02", "seagate", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Trantor T128/T128F/T228", "t128", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "UltraStor 14F/34F", "u14-34f", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "UltraStor 14F/24F/34F", "ultrastor", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Western Digital wd7000", "wd7000", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "PCMCIA core support", "pcmcia_core", 0, NULL, DRIVER_PCMCIA, DRIVER_MINOR_NONE }, { "PCMCIA card support", "ds", 0, NULL, DRIVER_PCMCIA, DRIVER_MINOR_NONE }, { "PCMCIA i82365 controller", "i82365", 0, NULL, DRIVER_PCMCIA, DRIVER_MINOR_NONE }, { "PCMCIA tcic controller", "tcic", 0, NULL, DRIVER_PCMCIA, DRIVER_MINOR_NONE }, { "iso9660", "isofs", 0, NULL, DRIVER_FS, DRIVER_MINOR_NONE }, { "Network File System (nfs)", "nfs", 0, NULL, DRIVER_FS, DRIVER_MINOR_NONE }, { "Windows SMB", "smbfs", 0, NULL, DRIVER_FS, DRIVER_MINOR_NONE }, { "Aztech CD", "aztcd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Backpack CDROM", "bpcd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Goldstar R420", "gscd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Mitsumi", "mcd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Mitsumi (alternate)", "mcdx", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Optics Storage 8000", "optcd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Phillips CM206/CM260", "cm206:cdrom", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Sanyo", "sjcd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Sony CDU-31A", "cdu31a", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Sony CDU-5xx", "sonycd535", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "SoundBlaster/Panasonic", "sbpcd", 0, NULL, DRIVER_CDROM, DRIVER_MINOR_NONE }, { "Loopback device", "loop", 0, NULL, DRIVER_OTHER, DRIVER_MINOR_NONE }, { "Parallel Printer", "lp", 0, NULL, DRIVER_OTHER, DRIVER_MINOR_NONE }, { NULL, NULL, 0, NULL, DRIVER_OTHER }, /* sentinel */ }; static const int numDrivers = (sizeof(drivers) / sizeof(struct driver)) - 1; static int loadDeviceModule(struct driver * driver, struct driversLoaded ** drlist, int skipPrompts, char * args); static int getOptions(const char * name, int * argcp, char *** argvp, int skipPrompts); static struct driversLoaded * allocDL(struct driversLoaded ** drlist); static int intLoadModule(char * modName, enum driverTypes type, enum driverMinor minor, struct driversLoaded ** drlist, int skipPrompts, char * args); static int modulesPanel(enum driverTypes type, struct driver ** drvptr, struct driver * defaultDriver); int devMakeInode(char * name, char * path) { int i; int major, minor; int type; if (name[0] == 's' && name[1] == 'd') { type = S_IFBLK; major = 8; minor = (name[2] - 'a') << 4; if (name[3] && name[4]) minor += 10 + (name[4] - '0'); else if (name[3]) minor += (name[3] - '0'); } else if (name[0] == 'h' && name[1] == 'd') { type = S_IFBLK; if (name[2] == 'a') major = 3, minor = 0; else if (name[2] == 'b') major = 3, minor = 64; else if (name[2] == 'c') major = 22, minor = 0; else if (name[2] == 'd') major = 22, minor = 64; else if (name[2] == 'e') major = 33, minor = 0; else if (name[2] == 'f') major = 33, minor = 64; else if (name[2] == 'g') major = 34, minor = 0; else if (name[2] == 'h') major = 34, minor = 64; else return INST_ERROR; if (name[3] && name[4]) minor += 10 + (name[4] - '0'); else if (name[3]) minor += (name[3] - '0'); } else if (!strncmp(name, "ram", 3)) { type = S_IFBLK; major = 1; minor = 1; if (name[3]) minor += name[3] - '1'; } else { for (i = 0; i < numDevices; i++) { if (!strcmp(devices[i].name, name)) break; } if (i == numDevices) return INST_ERROR; major = devices[i].major; minor = devices[i].minor; if (devices[i].isChar) type = S_IFCHR; else type = S_IFBLK; } /* logMessage("making device %s (%d, %d) as %s", name, major, minor, path); if (testing) newtWinMessage("mknod", "Ok", "making device %s (%d, %d) as %s", name, major, minor, path); */ unlink(path); if (mknod(path, type | 0600, makedev(major, minor))) { newtWinMessage("Error", "Ok", perrorstr("mknod() failed")); return INST_ERROR; } return 0; } void devRemoveInode(char * path) { logMessage("removing device file %s", path); unlink(path); } static int modulesPanel(enum driverTypes type, struct driver ** drvptr, struct driver * defaultDriver) { int drCount = 0; int i; newtComponent label, f, listbox; newtComponent okay, answer, cancel; for (i = 0; i < numDrivers; i++) { if (drivers[i].type == type) drCount++; } if (defaultDriver) logMessage("default driver is %s\n", defaultDriver->modules); newtCenteredWindow(45, 15, "Load module"); f = newtForm(NULL, NULL, 0); label = newtLabel(1, 1, "Which driver should I try?"); newtFormAddComponent(f, label); listbox = newtListbox(5, 3, 6, NEWT_LISTBOX_RETURNEXIT); drCount = 0; for (i = 0; i < numDrivers; i++) { if (drivers[i].type == type) { newtListboxAddEntry(listbox, drivers[i].name, drivers + i); if ((drivers + i) == defaultDriver) newtListboxSetCurrent(listbox, drCount); drCount++; } } newtFormAddComponent(f, listbox); okay = newtButton(8, 10, "Ok"); cancel = newtButton(28, 10, "Cancel"); newtFormAddComponents(f, okay, cancel, NULL); answer = newtRunForm(f); if (answer == cancel) { newtFormDestroy(f); newtPopWindow(); return INST_CANCEL; } *drvptr = newtListboxGetCurrent(listbox); newtFormDestroy(f); newtPopWindow(); return 0; } int loadDeviceDriver(enum driverTypes type, struct driversLoaded ** drlist, int justProbe) { struct driver * driver, * defDriver = NULL; int rc, i, j; int numAvail = -1; enum pciClass pciType = PCI_UNSET; struct pciDevice **devs, ** probedDev, ** lastDriver; int foundOne = 0; int ksArgc; char * start; char ** ksArgv = NULL; poptContext optCon; char * ksType; char * ksDevice; char * ksOpts; int ksFailOkay; char * typeName = ""; struct poptOption ksOptions[] = { { "missingok", '\0', POPT_ARG_NONE, &ksFailOkay, 0 }, { "opts", '\0', POPT_ARG_STRING, &ksOpts, 0 }, { 0, 0, 0, 0, 0 } }; switch (type) { case DRIVER_SCSI: pciType = PCI_SCSI; typeName = "SCSI"; break; case DRIVER_NET: pciType = PCI_ETHERNET; typeName = "ethernet"; break; case DRIVER_CDROM: typeName = "cdrom"; break; default: pciType = PCI_UNSET; break; } logMessage("in loadDeviceDriver, ks = %d, typName = %s", kickstart, typeName); #ifdef __i386__ if (pciType != PCI_UNSET) { logMessage("pci probing for %s devices", typeName); numAvail = pciProbeDevice(pciType, &devs); logMessage("pci probe found %d %s devices", numAvail, typeName); } #else numAvail = 0; #endif #ifdef __i386__ if (numAvail > 0) { lastDriver = devs + numAvail; probedDev = devs; for (j = 0; j < numAvail; j++) { probedDev = devs + j; /* if this is the same as the module suggested for another device, just skip this incarnation */ for (i = 0; i < j; i++) { if (!strcmp((*probedDev)->module[0], devs[i]->module[0])) break; } if (i < j) { logMessage("multiple %s devices found", devs[i]->module[0]); continue; } for (i = 0; i < numDrivers; i++) { if (!strcmp(drivers[i].modules, (*probedDev)->module[0])) break; } if (numDrivers == i) { logMessage("module not in install table"); } else { logMessage("found driver for %s", drivers[i].name); if (expert || (*probedDev)->nhits > 1) { if (!defDriver) defDriver = drivers + i; } else { rc = loadDeviceModule(drivers + i, drlist, 1, NULL); if (!rc) { if (!kickstart) newtWinMessage("Probe", "Ok", "A %s card has been found on your system.", drivers[i].name); foundOne = 1; } } } } probedDev = devs; for (j = 0; j < numAvail; j++) { pciFreeDevice(devs[j]); } free(devs); } #endif if (foundOne) return 0; /* If we're kickstarting, walk through the list of suggested devices. We stop once one is found. If --missingok is not used, give an error. */ if (kickstart) { while (!ksGetCommand(KS_CMD_DEVICE, ksArgv, &ksArgc, &ksArgv) && !foundOne) { ksFailOkay = 0; ksOpts = NULL; optCon = poptGetContext(NULL, ksArgc, ksArgv, ksOptions, 0); if ((rc = poptGetNextOpt(optCon)) < -1) { newtWinMessage("device command", "Ok", "bad argument to kickstart device command %s: %s", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); poptFreeContext(optCon); continue; } ksType = poptGetArg(optCon); ksDevice = poptGetArg(optCon); if (!ksType || !ksType || poptGetArg(optCon)) { newtWinMessage("device command", "Ok", "bad arguemnts to kickstart device command"); poptFreeContext(optCon); continue; } if (strcasecmp(ksType, typeName)) break; for (i = 0; i < numDrivers; i++) { start = strstr(drivers[i].modules, ksDevice); if (start && !strcmp(ksDevice, start)) break; } if (numDrivers == i) { newtWinMessage("error", "Ok", "No module exists for %s", ksDevice); poptFreeContext(optCon); continue; } else { logMessage("found driver for %s", drivers[i].name); rc = loadDeviceModule(drivers + i, drlist, 1, ksOpts); if (!rc) { foundOne = 1; } else { if (!ksFailOkay) break; /* out of while ksGetCmd() loop */ } } poptFreeContext(optCon); } } if (foundOne) return 0; if (justProbe) return INST_ERROR; do { rc = modulesPanel(type, &driver, defDriver); if (rc) return rc; rc = loadDeviceModule(driver, drlist, 0, NULL); if (rc == INST_ERROR) { errorWindow("I can't find the device anywhere on your system!"); } } while (rc); return 0; } static int loadDeviceModule(struct driver * driver, struct driversLoaded ** drlist, int skipPrompts, char * args) { char * start, * chptr, ** modStack; char moduleName[100]; int rc; int nummods = 1; enum driverTypes type; chptr = start = driver->modules; while (*chptr) { if (*chptr == ':') nummods++; chptr++; } modStack = alloca(sizeof(char *) * (nummods + 1)); nummods = 0; while (start && *start) { chptr = strchr(start, ':'); if (chptr) { strncpy(moduleName, start, chptr - start); moduleName[chptr - start] = '\0'; start = chptr + 1; type = DRIVER_PREREQ; } else { strcpy(moduleName, start); start = NULL; type = driver->type; } if ((rc = intLoadModule(moduleName, type, driver->minor, drlist, skipPrompts, NULL))) { while (nummods) { removeModule(modStack[--nummods]); } return rc; } modStack[nummods] = alloca(strlen(moduleName) + 1); strcpy(modStack[nummods++], moduleName); } /* don't do this check for autoprobed devices */ if (!skipPrompts && driver->okay && !driver->okay(driver)) { while (nummods) { removeModule(modStack[--nummods]); } logMessage("device check function failed to find device"); return INST_ERROR; } return 0; } int removeModule(char * module) { char * argv[] = { "/bin/rmmod", NULL, NULL }; argv[1] = module; return runProgram(RUN_LOG, "/bin/rmmod", argv); } char * getPlipDeviceName(void) { return plipDevice; } int loadModule(char * modName, enum driverTypes type, enum driverMinor minor, struct driversLoaded ** drlist) { return intLoadModule(modName, type, minor, drlist, 0, NULL); } static int intLoadModule(char * modName, enum driverTypes type, enum driverMinor minor, struct driversLoaded ** drlist, int skipPrompts, char * args) { struct driversLoaded * dl; char * objName; char * chptr, * start; char ** argv; int argc; int rc; int fd; int rmObj = 0; int clearWindow = 0; gzFile stream; char buf[4096]; int i = 0; if (testing) return 0; if (type == DRIVER_SCSI) { winStatus(35, 3, "SCSI", "Scanning SCSI bus..."); clearWindow = 1; } objName = alloca(strlen(modName) + 15 + strlen(MODULES_PATH)); strcpy(objName, MODULES_PATH); strcat(objName, modName); strcat(objName, ".o"); #ifdef __i386__ if (access(objName, R_OK)) { /* it might be gzipped */ strcat(objName, ".gz"); if (access(objName, R_OK)) { logMessage("can't find module %s", modName); return INST_ERROR; } stream = gzopen(objName, "r"); if (!stream) { logMessage("gzopen failed to read %s: %s", objName, strerror(errno)); return INST_ERROR; } strcpy(objName, "/tmp/"); strcat(objName, modName); strcat(objName, ".o"); if ((fd = open(objName, O_WRONLY | O_CREAT | O_TRUNC)) < 0) { logMessage("failed to create %s: %s", objName, strerror(errno)); gzclose(stream); return INST_ERROR; } logMessage("uncompressing module for installation"); while ((i = gzread(stream, buf, sizeof(buf))) > 0) { if (write(fd, buf, i) != i) { logMessage("write() failed during module decompression: %s\n", strerror(errno)); close(fd); gzclose(stream); unlink(objName); return INST_ERROR; } } if (i < 0) { logMessage("write() failed during module decompression: %s\n", strerror(errno)); close(fd); gzclose(stream); unlink(objName); return INST_ERROR; } close(fd); gzclose(stream); if (i < 0) return INST_ERROR; rmObj = 1; } #endif argc = 2; argv = malloc((argc + 1) * sizeof(char *)); argv[0] = "/bin/insmod"; argv[1] = objName; argv[2] = NULL; if (args) { chptr = strcpy(alloca(strlen(args) + 1), args); while (*chptr) { while (isspace(*chptr) && *chptr) chptr++; if (!*chptr) break; start = chptr; argc++; argv = realloc(argv, (argc + 1) * sizeof(char *)); while (!isspace(*chptr) && *chptr) chptr++; argv[argc - 1] = start; if (*chptr) { *chptr = '\0'; chptr++; } } argv[argc] = NULL; } else { if ((rc = getOptions(modName, &argc, &argv, skipPrompts))) { free(argv); if (clearWindow) newtPopWindow(); return rc; } } if (runProgram(RUN_LOG, "/bin/insmod", argv)) { free(argv); logMessage("insmod failed!"); if (clearWindow) newtPopWindow(); return INST_ERROR; } if (drlist) { dl = allocDL(drlist); dl->type = type; dl->minor = minor; dl->argv = argv; dl->argc = argc; dl->module = strdup(modName); dl->persistFlags = 0; } if (clearWindow) newtPopWindow(); if (rmObj) unlink(objName); return 0; } static struct driversLoaded * allocDL(struct driversLoaded ** drlist) { struct driversLoaded * new; if (*drlist == NULL) { *drlist = malloc(sizeof(**drlist)); new = *drlist; } else { new = *drlist; while (new->next) new = new->next; new->next = malloc(sizeof(**drlist)); new = new->next; } new->next = NULL; return new; } #define OPTIONS_SPECIFY ((void *) 1) #define OPTIONS_DEFAULT ((void *) 2) static int getOptions(const char * name, int * argcp, char *** argvp, int skipPrompts) { newtComponent form, listbox, text, okay, answer, cancel; char ** parameters = NULL; char * miscParameters; char buf[2000]; struct moduleInfo * mod; void * choice = OPTIONS_DEFAULT; int numOptions, col, miscRow, buttonRow, i; const struct moduleOptions * option; char * miscText; char * chptr, * start; mod = modules; while (mod->name) { if (!strcmp(mod->name, name)) break; mod++; } if (!mod->name) mod = NULL; if (mod && !mod->options) { (*argcp)++; (*argvp) = realloc(*argvp, (*argcp + 1) * sizeof(char *)); (*argvp)[(*argcp) - 1] = mod->defaultOptions; (*argvp)[(*argcp)] = NULL; if (!mod->defaultOptions) (*argcp)--; return 0; } if (!skipPrompts) { if (!mod || mod->shouldAutoprobe) { sprintf(buf, "In some cases, the %s driver needs to have extra " "information to work properly, although it normally works " "fine without. Would you like to specify extra options " "for it or allow the driver to probe your machine for the " "information it needs? Occasionally, probing will hang a " "computer, but it should not cause any damage.", name); newtCenteredWindow(60, 16, "Module Options"); listbox = newtListbox(20, 9, 0, NEWT_LISTBOX_RETURNEXIT); newtListboxAddEntry(listbox, "Autoprobe", OPTIONS_DEFAULT); newtListboxAddEntry(listbox, "Specify options", OPTIONS_SPECIFY); buttonRow = 12; } else { sprintf(buf, "In many cases, the %s driver needs to be provided with " "extra information on your hardware. If you prefer, " "some common values for those parameters will be tried. " "This process can hang a machine, although it should " "not cause any damage.", name); newtCenteredWindow(60, 14, "Module Options"); listbox = newtListbox(20, 7, 0, NEWT_LISTBOX_RETURNEXIT); newtListboxAddEntry(listbox, "Specify options", OPTIONS_SPECIFY); newtListboxAddEntry(listbox, "Autoprobe", OPTIONS_DEFAULT); buttonRow = 10; } text = newtTextbox(1, 1, 55, 7, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, buf); okay = newtButton(13, buttonRow, "Ok"); cancel = newtButton(39, buttonRow, "Cancel"); form = newtForm(NULL, NULL, 0); newtFormAddComponents(form, text, listbox, okay, cancel, NULL); answer = newtRunForm(form); newtPopWindow(); choice = newtListboxGetCurrent(listbox); newtFormDestroy(form); if (answer == cancel) { return INST_CANCEL; } } if (choice == OPTIONS_DEFAULT) { (*argcp)++; (*argvp) = realloc(*argvp, (*argcp + 1) * sizeof(char *)); if (mod) (*argvp)[(*argcp) - 1] = mod->defaultOptions; (*argvp)[(*argcp)] = NULL; if (!mod || !mod->defaultOptions) (*argcp)--; return 0; } form = newtForm(NULL, NULL, 0); newtFormAddComponent(form, newtLabel(1, 1, "Module options:")); numOptions = 0; col = 0; if (mod) { option = mod->options; while (option->arg) { newtFormAddComponent(form, newtLabel(3, 3 + numOptions, option->desc)); if (strlen(option->desc) > col) col = strlen(option->desc); numOptions++; option++; } miscText = "Miscellaneous options:"; } else { miscText = "Module options:"; } if (numOptions) miscRow = 4 + numOptions; else miscRow = 3; newtFormAddComponent(form, newtLabel(3, miscRow, "Miscellaneous options:")); if (22 > col) col = 22; if (numOptions) { parameters = alloca(sizeof(*parameters) * numOptions); numOptions = 0; option = mod->options; while (option->arg) { sprintf(buf, "%s=", option->arg); newtFormAddComponent(form, newtEntry(col + 5, 3 + numOptions, buf, 20, parameters + numOptions, NEWT_ENTRY_SCROLL)); numOptions++; option++; } } newtFormAddComponent(form, newtEntry(col + 5, miscRow, "", 20, &miscParameters, NEWT_ENTRY_SCROLL)); newtCenteredWindow(col + 30, miscRow + 6, "Module Parameters"); okay = newtButton((col + 10) / 3, miscRow + 2, "Ok"); cancel = newtButton(10 + 2 * ((col + 10) / 3), miscRow + 2, "Cancel"); newtFormAddComponents(form, okay, cancel, NULL); answer = newtRunForm(form); newtPopWindow(); if (answer == cancel) { newtFormDestroy(form); return INST_CANCEL; } if (mod) { i = *argcp; (*argcp) += numOptions; (*argvp) = realloc(*argvp, (*argcp + 1) * sizeof(char *)); numOptions = 0; option = mod->options; while (option->arg) { sprintf(buf, "%s=", option->arg); if (strcmp(parameters[numOptions], buf)) (*argvp)[i++] = strdup(parameters[numOptions]); numOptions++, option++; } (*argcp) = i; } chptr = miscParameters; numOptions = 0; while (*chptr) { while (isspace(*chptr) && *chptr) chptr++; if (!*chptr) continue; numOptions++; while (!isspace(*chptr) && *chptr) chptr++; } i = *argcp; (*argcp) += numOptions; (*argvp) = realloc(*argvp, (*argcp + 1) * sizeof(char *)); numOptions = 0; chptr = miscParameters; numOptions = 0; while (*chptr) { while (isspace(*chptr) && *chptr) chptr++; if (!*chptr) continue; start = chptr; numOptions++; while (!isspace(*chptr) && *chptr) chptr++; if (*chptr) { *chptr = '\0'; (*argvp)[i++] = strdup(start); *chptr = ' '; } else (*argvp)[i++] = strdup(start); } (*argcp) = i; (*argvp)[*argcp] = NULL; newtFormDestroy(form); return 0; } int readModuleConfPersist(char * prefix, struct driversLoaded * drlist) { char buf[255]; FILE * f; char * start, * end, * chptr; enum driverTypes type; enum driverMinor minor; struct driversLoaded * dl; strcpy(buf, prefix); strcat(buf, "/conf.modules"); f = fopen(buf, "r"); if (!f) { logMessage("failed to open %s for module information", prefix); return INST_ERROR; } while (fgets(buf, sizeof(buf) - 1, f)) { start = buf; end = start + strlen(start) - 1; *end = '\0'; if (!strncmp(start, "alias ", 6)) { start += 6; type = DRIVER_OTHER; minor = DRIVER_MINOR_NONE; while (isspace(*start) && *start) start++; if (!strncmp(start, "eth", 3)) { type = DRIVER_NET; minor = DRIVER_MINOR_ETHERNET; start += 5; } else if (!strncmp(start, "scsi_hostadapter", 16)) { type = DRIVER_SCSI; start += 17; } if (type != DRIVER_OTHER) { dl = drlist; while (dl) { if (dl->type == type && dl->minor == minor) break; dl = dl->next; } while (isspace(*start) && *start) start++; if (dl && *start && !strcmp(start, dl->module)) { dl->persistFlags |= PERSIST_ALIAS; } } } else if (!strncmp(start, "options ", 8)) { start += 8; chptr = start; while (!isspace(*chptr) && *chptr) chptr++; if (!*chptr) continue; *chptr = '\0'; dl = drlist; while (dl) { if (!strcmp(dl->module, start)) break; dl = dl->next; } if (dl) { /* we really should check that these options match the ones we used, but that's nontrivial FIXME */ dl->persistFlags |= PERSIST_OPTIONS; } } } fclose(f); return 0; } int readModuleConf(char * prefix, struct driversLoaded ** drlist) { char buf[255]; FILE * f; char * start, * end, * chptr; struct driversLoaded * item = NULL; if (testing) return 0; strcpy(buf, prefix); strcat(buf, "/conf.modules"); f = fopen(buf, "r"); if (!f) { return INST_ERROR; } while (fgets(buf, sizeof(buf) - 1, f)) { start = buf; end = start + strlen(start) - 1; *end = '\0'; if (!strncmp(start, "alias ", 6)) { start += 6; if (!strncmp(start, "eth", 3)) { start += 5; item = allocDL(drlist); item->module = strdup(start); item->argv = NULL; item->argc = 0; item->persistFlags = 0; item->type = DRIVER_NET; item->minor = DRIVER_MINOR_ETHERNET; } else if (!strncmp(start, "scsi_hostadapter", 16)) { start += 17; while (isspace(*start) && *start) start++; if (!*start) continue; item = allocDL(drlist); item->module = strdup(start); item->argv = NULL; item->argc = 0; item->persistFlags = 0; item->type = DRIVER_SCSI; item->minor = DRIVER_MINOR_NONE; } } else if (!strncmp(start, "options ", 8)) { start += 8; chptr = start; while (!isspace(*chptr) && *chptr) chptr++; if (!*chptr) continue; *chptr = '\0'; item = *drlist; while (item && strcmp(item->module, start)) item = item->next; if (!item) { item = allocDL(drlist); item->module = strdup(start); item->argv = NULL; item->argc = 0; item->persistFlags = 0; item->type = DRIVER_NET; item->minor = DRIVER_MINOR_ETHERNET; } item->argv = malloc(sizeof(char *) * 5); item->argc = 3; item->argv[2] = strdup(chptr + 1); } } fclose(f); return 0; } int writeModuleConf(char * prefix, struct driversLoaded * dl, int append) { char buf[255]; char buf2[255]; FILE * f; int i; int numEth = 0, numTr = 0, numScsi = 0; char * mode = append ? "a" : "w"; if (testing) return 0; strcpy(buf, prefix); strcat(buf, "/conf.modules"); if (!append && !access(buf, F_OK)) { logMessage("backing up old conf.modules"); strcpy(buf2, buf); strcat(buf2, ".orig"); rename(buf, buf2); } f = fopen(buf, mode); if (!f) { errorWindow("cannot open module config file: %s"); return INST_ERROR; } while (dl) { if (dl->type == DRIVER_NET) { if (!append || !(dl->persistFlags & PERSIST_ALIAS)) { if (dl->minor == DRIVER_MINOR_TR) fprintf(f, "alias tr%d %s\n", numTr++, dl->module); else if (dl->minor == DRIVER_MINOR_ETHERNET) fprintf(f, "alias eth%d %s\n", numEth++, dl->module); } } else if (dl->type == DRIVER_SCSI) { if (!append || !(dl->persistFlags & PERSIST_ALIAS)) { if (!numScsi) fprintf(f, "alias scsi_hostadapter %s\n", dl->module); else fprintf(f, "alias scsi_hostadapter%d %s\n", numScsi, dl->module); numScsi++; } } if (!append || !(dl->persistFlags & PERSIST_OPTIONS)) { if (dl->argc > 2) { fprintf(f, "options %s", dl->module); for (i = 2; i < dl->argc; i++) { fprintf(f, " %s", dl->argv[i]); } fprintf(f, "\n"); } } dl = dl->next; } fclose(f); return 0; } static int checkSCSIDev(struct driver * dev) { return scsiDeviceAvailable(); } static int checkEthernetDev(struct driver * dev) { return netDeviceAvailable("eth0"); } static int checkTokenRingDev(struct driver * dev) { return netDeviceAvailable("tr0"); } static int checkPlipDev(struct driver * dev) { plipDevice = NULL; if (netDeviceAvailable("plip0")) { logMessage("plip0 will be used for PLIP"); plipDevice = "plip0"; } else if (netDeviceAvailable("plip1")) { logMessage("plip1 will be used for PLIP"); plipDevice = "plip1"; } else if (netDeviceAvailable("plip2")) { logMessage("plip2 will be used for PLIP"); plipDevice = "plip2"; } return (plipDevice != NULL); } /* This assumes only one of each driver type is loaded */ int removeDeviceDriver(enum driverTypes type, struct driversLoaded ** drlist) { char * buf, * chptr; struct driversLoaded * dl, * head; struct driver * dri; dl = *drlist; while (dl && dl->type != type) { dl = dl->next; } if (!dl) return 0; dri = drivers; while (dri->name) { if (!strcmp(dri->modules, dl->module)) break; dri++; } if (!dri->name) return 0; buf = alloca(strlen(dri->modules) + 1); strcpy(buf, dri->modules); chptr = buf + strlen(buf) - 1; while (chptr > buf) { while (chptr > buf && *chptr != ':') chptr--; if (*chptr == ':') { chptr = '\0'; removeModule(chptr + 1); chptr--; } } removeModule(buf); if (dl == *drlist) { *drlist = dl->next; free(dl); } else if (dl) { head = *drlist; while (head->next != dl) head = head->next; head->next = dl->next; free(dl); } return 0; } int loadFilesystem(char * name, struct driversLoaded ** drlist) { #ifdef __i386__ static int gotNfs = 0; static int gotSmb = 0; static int gotIso = 0; int * which; char * modname = name; int rc; if (!strcmp(name, "nfs")) which = &gotNfs; else if (!strcmp(name, "smb")) which = &gotSmb; else if (!strcmp(name, "iso9660")) { which = &gotIso; modname = "isofs"; } else { return INST_ERROR; } if (!*which) { rc = loadModule(modname, DRIVER_FS, DRIVER_MINOR_NONE, drlist); if (rc) return rc; *which = 1; } #endif return 0; }