#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpio.h" #include "devices.h" #include "install.h" #include "intl.h" #include "kickstart.h" #include "log.h" #include "net.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; }; 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 }, }; int numDevices = sizeof(devices) / sizeof(struct devnum); struct moduleOptions { char * arg; char * desc; char * defaults; } ; struct moduleOptions neOptions[] = { { "io=", N_("Base IO port:"), "0x300:0x280:0x320:0x340:0x360" }, { "irq=", N_("IRQ level:"), NULL }, { NULL, NULL, NULL } } ; struct moduleOptions de4x5Options[] = { { "io=", N_("Base IO port:"), "0x0b" }, { NULL, NULL, NULL } } ; struct moduleOptions cdu31aOptions[] = { { "cdu31a_port=", N_("Base IO port:"), "" }, { "cdu31a_irq=", N_("IRQ level:"), "" }, { NULL, NULL, NULL } } ; struct moduleOptions cm206Options[] = { { "cm206=", N_("IO base, IRQ:"), "" }, { NULL, NULL, NULL } } ; struct moduleOptions mcdOptions[] = { { "mcd=", N_("Base IO port:"), "" }, { NULL, NULL, NULL } } ; struct moduleOptions optcdOptions[] = { { "optcd=", N_("Base IO port:"), "" }, { NULL, NULL, NULL } } ; struct moduleOptions fdomainOptions[] = { { "setup_called=", N_("Use other options"), "1" }, { "port_base=", N_("Base IO port:"), "0xd800" }, { "interrupt_level=", N_("Interrupt level (IRQ):"), "10" }, { NULL, NULL, NULL } } ; struct moduleOptions sbpcdOptions[] = { { "sbpcd=", N_("IO base, IRQ, label:"), "" }, { NULL, NULL, NULL } } ; #define MODULE_AUTOPROBE (1 << 0) #define MODULE_FAKEAUTOPROBE (1 << 1) struct moduleInfo { char * name; int shouldAutoprobe; 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 3c515", "3c515", 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 }, { "ATP", "atp", 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 }, { "EPIC 100", "epic100", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Eth 16i", "eth16i", 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 }, { "Lance", "lance", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NE2000 and compatible", "8390:ne", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NE2000 PCI", "8390:ne2k-pci", 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", "8390:smc-ultra", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "SMC Ultra 32", "8390:smc-ultra32", 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 }, { "ICP GDT RP Series", "gdth", 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 */ }; #define OPTIONS_SPECIFY (1) #define OPTIONS_DEFAULT (0) static char * driverOptions[] = { N_("Autoprobe"), N_("Specify options"), NULL }; 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; } unlink(path); if (mknod(path, type | 0600, makedev(major, minor))) { newtWinMessage(_("Error"), _("Ok"), _("mknod() failed: %s"), strerror(errno)); 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, rc; char ** driverNames; int * indices; int option = 0; for (i = 0; i < numDrivers; i++) { if (drivers[i].type == type) drCount++; } driverNames = alloca((drCount + 1) * sizeof(*drivers)); indices = alloca(drCount * sizeof(*indices)); drCount = 0; for (i = 0; i < numDrivers; i++) { if (drivers[i].type == type) { if (defaultDriver == (drivers + i)) option = drCount; driverNames[drCount] = drivers[i].name; indices[drCount++] = i; } } driverNames[drCount] = NULL; rc = newtWinMenu(_("Load module"), _("Which driver should I try?"), 30, 0, 20, 6, driverNames, &option, _("Ok"), _("Back"), NULL); if (rc == 2) { return INST_CANCEL; } *drvptr = drivers + indices[option]; logMessage("picked driver %s", (*drvptr)->name); 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(_("Error"), _("Ok"), _("bad arguments 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 rmObj = 0; int clearWindow = 0; if (testing) return 0; objName = alloca(strlen(modName) + 15 + strlen(MODULES_PATH)); strcpy(objName, MODULES_PATH); strcat(objName, modName); strcat(objName, ".o"); 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); return rc; } } if (type == DRIVER_SCSI) { winStatus(35, 3, "SCSI", "Scanning SCSI bus..."); clearWindow = 1; if (expert) ioctl(0, VT_ACTIVATE, 4); } if (runProgram(RUN_LOG, "/bin/insmod", argv)) { free(argv); logMessage("insmod failed!"); if (clearWindow) newtPopWindow(); if (expert) ioctl(0, VT_ACTIVATE, 1); 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 (expert) ioctl(0, VT_ACTIVATE, 1); 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; } static int getOptions(const char * name, int * argcp, char *** argvp, int skipPrompts) { int miscParameters; char buf[2000]; struct moduleInfo * mod; int numOptions, col, i, rc; struct moduleOptions * option; char * chptr, * start; int choice = OPTIONS_DEFAULT; /* if (skipPrompts), use defaults */ struct newtWinEntry * entries; char ** values; 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); choice = OPTIONS_DEFAULT; } 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); choice = OPTIONS_SPECIFY; } rc = newtWinMenu(_("Module Options"), buf, 55, 5, 15, 6, driverOptions, &choice, _("Ok"), _("Back"), NULL); if (rc == 2) 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; } numOptions = 0; col = 0; if (mod) { option = mod->options; while (option->arg) numOptions++, option++; } entries = alloca(sizeof(*entries) * (numOptions + 2)); values = alloca(sizeof(*values) * (numOptions + 2)); if (mod) { option = mod->options; numOptions = 0; while (option->arg) { entries[numOptions].text = _(option->desc); entries[numOptions].value = values + numOptions; values[numOptions] = option->arg; entries[numOptions].flags = 0; numOptions++, option++; } } if (mod) { entries[numOptions].text = _("Miscellaneous options:"); } else { entries[numOptions].text = _("Module options:"); } miscParameters = numOptions; entries[numOptions].value = values + numOptions; values[numOptions] = NULL; entries[numOptions].flags = 0; numOptions++; entries[numOptions].text = (void *) entries[numOptions].value = NULL; rc = newtWinEntries(_("Module Parameters"), _("Module options:"), 40, 0, 10, 20, entries, _("Ok"), _("Back"), NULL); if (mod) { i = *argcp; (*argcp) += numOptions; (*argvp) = realloc(*argvp, (*argcp + 1) * sizeof(char *)); numOptions = 0; option = mod->options; while (option->arg) { if (strcmp(*entries[numOptions].value, option->arg) && strlen(*entries[numOptions].value)) (*argvp)[i++] = *entries[numOptions].value; else free(*entries[numOptions].value); numOptions++, option++; } (*argcp) = i; } chptr = *entries[miscParameters].value; 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 = *entries[miscParameters].value; 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; 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_OTHER; item->minor = DRIVER_MINOR_NONE; } 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 * modname, char * fsname, struct driversLoaded ** drlist) { char buf[2048]; int rc; int fd; char target[50]; if ((fd = open("/proc/filesystems", O_RDONLY)) < 0) { newtWinMessage(_("Error"), _("Ok"), _("Cannot open /proc/filesystems: %d"), strerror(errno)); return INST_ERROR; } rc = read(fd, buf, sizeof(buf) - 1); buf[rc] = '\0'; sprintf(target, "\t%s\n", fsname); if (strstr(buf, target)) return 0; rc = loadModule(modname, DRIVER_FS, DRIVER_MINOR_NONE, drlist); return rc; }