#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" #ifdef __sparc__ #include "sbus-probing/sbusprobe.h" #endif #include "install.h" #define MODULES_PATH "/modules/" struct moduleDependency { char * name; char ** deps; }; static struct moduleDependency * moduleDepList = NULL; 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 } } ; struct moduleOptions parportPcOptions[] = { { "io=", N_("Base IO port:"), "0x378" }, { "irq=", N_("IRQ level:"), "7" }, { 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 }, { "parport", 1, NULL, 0, NULL }, { "parport_pc", 1, parportPcOptions, 0, "irq=7" }, { "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 }, { "vfat", 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 checkSCSIDev(struct driver * dev); #ifndef DISABLE_NETWORK static int checkEthernetDev(struct driver * dev); static int checkPlipDev(struct driver * dev); static int checkTokenRingDev(struct driver * dev); #endif static struct driver drivers[] = { #ifndef DISABLE_NETWORK #ifndef __sparc__ { "3com 3c509", "3c509", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c501", "3c501", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c503", "3c503", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c505", "3c505", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c507", "3c507", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "3com 3c515", "3c515", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #endif { "3com 3c59x (Vortex)", "3c59x", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #ifndef __sparc__ { "3com 3c90x (Boomerang)", "3c59x", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Allied Telesis AT1700", "at1700", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Ansel Communication AC3200", "ac3200", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "AMD PC/Net 32", "pcnet32", 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", "e2100", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Compaq Netelligent", "tlan", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #endif { "Digital 425,434,435,450,500", "de4x5", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #ifndef __sparc__ { "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 }, { "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", "hp-plus", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "ICL EtherTeam 16i", "eth16i", 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 }, { "Mylex LNE390", "lne390", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #endif #ifdef __sparc__ { "MyriCOM Gigabit Ethernet", "myri_sbus", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #endif #ifndef __sparc__ { "NE2000 and compatible", "ne", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NE2000 PCI", "ne2k-pci", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NE3210", "ne3210", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "NI 5010", "ni5010", 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 }, #endif /* !__sparc__ */ #ifdef __sparc__ { "Sun BigMac Ethernet", "sunbmac", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Sun Happy Meal Ethernet", "sunhme", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Sun Quad Ethernet", "sunqe", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #endif #ifndef __sparc__ { "RealTek RTL8129/8139","rtl8139", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Racal-Interlan ES3210", "es3210", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "RedCreek PCI45 LAN","rcpci45", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "SMC 83c170 EPIC/100", "epic100", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "SMC 9000 series", "smc9194", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "SMC Ultra", "smc-ultra", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "SMC Ultra 32", "smc-ultra32", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "Token Ring", "ibmtr", 0, checkTokenRingDev, DRIVER_NET, DRIVER_MINOR_TR }, { "VIA Rhine", "via-rhine", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, { "WD8003, WD8013 and compatible", "wd", 0, checkEthernetDev, DRIVER_NET, DRIVER_MINOR_ETHERNET }, #endif /* !__sparc__ */ #endif /* DISABLE_NETWORK */ #ifndef __sparc__ { "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 }, #endif /* !__sparc__ */ { "Adaptec 2740, 2840, 2940", "aic7xxx", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, #ifndef __sparc__ { "AdvanSys Adapters", "advansys", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Always IN2000", "in2000", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "AMD SCSI", "AM53C974", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "AMI MegaRAID", "megaraid", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "BusLogic Adapters", "BusLogic", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Compaq Smart-2/P RAID Controller", "cpqarray", 0, NULL, 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 Disk Array Controller", "gdth", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Iomega PPA3 (parallel port Zip)", "ppa", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, { "Mylex DAC960", "DAC960", 0, NULL, 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 }, #endif /* !__sparc__ */ { "NCR 53C8xx PCI", "ncr53c8xx", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, #ifndef __sparc__ { "Perceptive Solutions PCI-2000", "pci2000", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, #endif #ifdef __sparc__ { "Performance Technologies ISP", "qlogicpti", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, #endif #ifndef __sparc__ { "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 }, #endif /* !__sparc__ */ #ifdef __sparc__ { "Sun SparcSTORAGE Array", "fc4:soc:pluto", 0, checkSCSIDev, DRIVER_SCSI, DRIVER_MINOR_NONE }, #endif #ifndef __sparc__ { "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 }, #endif /* !__sparc__ */ { "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 }, #ifndef __sparc__ { "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", 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 }, #endif /* !__sparc__ */ { "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); const char * getModuleDescription(char * module) { struct driver * d; for (d = drivers; d->name; d++) if (strstr(d->modules, module)) return d->name; return module; } int devMakeInode(char * name, char * path) { int i; int major, minor; int type; char *ptr; char *dir; 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 if (!strncmp(name, "rd/", 3)) { /* dac 960 "/rd/cXdXXpX". It can have 8 controllers, 32 drives per controller and 7 partitions per drive. */ char *c, *d, *p; type = S_IFBLK; /* Copy "XdXXpX". Get controller #. */ c = alloca (strlen (&name [4]) + 1); strcpy (c, &name [4]); /* Get drive #. */ d = c; d++; d++; /* Get partition #. */ p = d; while (*p != '\0' && *p != 'p') p++; major = 48 + *c - '0'; if (*p == 'p') { /* Get partition #. */ *p++ = '\0'; minor = atoi (d) * 8 + *p - '0'; } else { minor = atoi (d) * 8; } } else if (!strncmp(name, "ida/", 4)) { /* Compaq Smart Array "ida/c0d0{p1} */ type = S_IFBLK; major = 72; /* controller */ minor = (name[7] - '0') * 16; /* disk */ if (strlen(name) > 8) /* partition */ minor += atoi(name + 9); } 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; } /* make a directory for this inode if needed. */ ptr = path; i = 0; while (*ptr) if (*ptr++ == '/') i++; if (i > 2) { dir = alloca(strlen(path) + 1); strcpy(dir, path); ptr = dir + (strlen(path) - 1); while (*ptr != '/') *ptr-- = '\0'; mkdir(dir, 0755); } 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; } #ifdef __sparc__ int start_openprom(void) { static int started = 0; if (started) return 0; started = 1; return intLoadModule("openprom", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL, 1, ""); } #endif int loadDeviceDriver(enum driverTypes type, struct driversLoaded ** drlist, int flags) { 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 = ""; int argc; char ** argv; int ksFindMore; struct poptOption ksOptions[] = { { "continue", '\0', POPT_ARG_NONE, &ksFindMore, 0 }, { "missingok", '\0', POPT_ARG_NONE, &ksFailOkay, 0 }, { "opts", '\0', POPT_ARG_STRING, &ksOpts, 0 }, { 0, 0, 0, 0, 0 } }; #ifdef __sparc__ int numSBUSAvail = 0; struct sbusDevice **sbusdevs; #endif 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); #if defined(__i386__) || defined(__sparc__) || defined(__alpha__) if (pciType != PCI_UNSET) { logMessage("pci probing for %s devices", typeName); numAvail = pciProbeDevice(pciType, &devs); logMessage("pci probe found %d %s devices", numAvail, typeName); # ifdef __sparc__ start_openprom(); logMessage("sbus probing for %s devices", typeName); numSBUSAvail = sbusProbeDevice(pciType, &sbusdevs); logMessage("sbus probe found %d %s devices", numSBUSAvail, typeName); if (numSBUSAvail <= 0) numSBUSAvail = 0; else { if (numAvail <= 0) { numAvail = numSBUSAvail; devs = (struct pciDevice **)sbusdevs; } else { probedDev = (struct pciDevice **)malloc((numAvail + numSBUSAvail) * sizeof (struct pciDevice *)); if (!probedDev) numSBUSAvail = 0; else { memcpy (probedDev, sbusdevs, numSBUSAvail * sizeof (struct pciDevice *)); memcpy (probedDev + numSBUSAvail, devs, numAvail * sizeof (struct pciDevice *)); numAvail += numSBUSAvail; free (devs); free (sbusdevs); devs = probedDev; } } } # endif /* SPARC */ } #else numAvail = 0; #endif if (!ksGetCommand(KS_CMD_NOPROBE, NULL, &argc, &argv)) { flags |= DEVICE_NOPROBE; foundOne = 0; } #if defined(__i386__) || defined(__sparc__) || defined(__alpha__) if (numAvail > 0 && !(flags & DEVICE_NOPROBE)) { lastDriver = devs + numAvail; probedDev = devs; for (j = 0; j < numAvail; j++) { char *module_name; 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; } module_name = (*probedDev)->module[0]; # ifdef __sparc__ /* Hack for sparc64, where de4x5 is the only Digital module supported and covers all PCI DEC cards */ if (!strcmp(module_name, "tulip")) module_name = "de4x5"; # endif for (i = 0; i < numDrivers; i++) { if (!strcmp(drivers[i].modules, (*probedDev)->module[0])) break; } if (numDrivers == i) { logMessage("module %s not in install table", module_name); } 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 && !(flags & DEVICE_NOPAUSE)) newtWinMessage(_("Probe"), _("Ok"), _("A %s card has been found on your system."), drivers[i].name); foundOne = 1; } } } } for (j = 0; j < numAvail; j++) { # ifdef __sparc__ if (j < numSBUSAvail) sbusFreeDevice((struct sbusDevice *)devs[j]); else # endif /* __sparc__ */ pciFreeDevice(devs[j]); } free(devs); } #endif /* defined(__i386__) || defined(__sparc__) || defined(__alpha__)*/ 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) { logMessage("in device handler\n"); while (!ksGetCommand(KS_CMD_DEVICE, ksArgv, &ksArgc, &ksArgv) && !foundOne) { ksFailOkay = 0; ksOpts = NULL; ksFindMore = 0; 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); logMessage("type %s device%s", ksType, ksDevice); if (!ksType || !ksType || poptGetArg(optCon)) { newtWinMessage(_("Error"), _("Ok"), _("bad arguments to kickstart device command")); poptFreeContext(optCon); continue; } if (strcasecmp(ksType, typeName)) continue; 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) { if (!ksFindMore) foundOne = 1; } else { if (!ksFailOkay) break; /* out of while ksGetCmd() loop */ } } poptFreeContext(optCon); } } if (foundOne) return 0; if (flags & DEVICE_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 doLoadModule(char * name, enum driverTypes type, int minor, struct driversLoaded ** drlist, int skipPrompts, char *** modStack) { struct moduleDependency * depInfo; char ** dep; int rc; struct driversLoaded * dl; if (drlist) dl = *drlist; else dl = NULL; while (dl && strcmp(dl->module, name)) { dl = dl->next; } if (dl) return 0; depInfo = moduleDepList; while (depInfo && depInfo->name && strcmp(depInfo->name, name)) depInfo++; if (depInfo && depInfo->name && depInfo->deps) { dep = depInfo->deps; while (*dep) { if ((rc = doLoadModule(*dep, DRIVER_PREREQ, minor, drlist, skipPrompts, modStack))) return rc; dep++; } } if ((rc = intLoadModule(name, type, minor, drlist, skipPrompts, NULL))) return rc; return 0; } static int loadDeviceModule(struct driver * driver, struct driversLoaded ** drlist, int skipPrompts, char * args) { char ** modStack; int rc; char * modStackSpace[50]; modStack = modStackSpace; *modStack = NULL; if ((rc = doLoadModule(driver->modules, driver->type, driver->minor, drlist, skipPrompts, &modStack))) { while (*modStack) removeModule(*modStack), modStack--; return rc; } /* don't do this check for autoprobed devices */ if (!skipPrompts && driver->okay && !driver->okay(driver)) { while (*modStack) removeModule(*modStack), modStack--; 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) { char ** modStack; char * modStackSpace[50]; int rc; modStack = modStackSpace; *modStack = NULL; if ((rc = doLoadModule(modName, type, minor, drlist, 1, &modStack))) /* module insertion failure - back out the deps */ while (*modStack) removeModule(*modStack), modStack--; return rc; /* old 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; int i, fd; 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 (testing) return 0; */ if (type == DRIVER_SCSI) { winStatus(50, 3, "SCSI", "Scanning %s SCSI bus...", getModuleDescription(modName)); 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; } /* this is a hack to make plip go - it needs the IRQ */ /* it scans the irq= line from argv and writes it to procfs */ if (!strncmp(modName, "parport_pc", 10)) { for (i = 0, chptr = argv[0]; i < argc; i++, chptr = argv[i]) if (!strncmp(chptr, "irq=", 4)) { chptr += 4; logMessage("writing to /proc/parport/0/irq"); if ((fd = open("/proc/parport/0/irq", O_WRONLY)) < 0) break; write (fd, chptr, 1); close(fd); break; } } 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 = NEWT_FLAG_SCROLL; 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 = NEWT_FLAG_SCROLL; numOptions++; entries[numOptions].text = (void *) entries[numOptions].value = NULL; rc = newtWinEntries(_("Module Parameters"), _("Module options:"), 40, 0, 10, 20, entries, _("Ok"), _("Back"), NULL); if (rc == 2) /* This is gross */ return getOptions(name, argcp, argvp, skipPrompts); 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; } #ifdef __sparc__ int readProcModules(enum driverTypes type, struct driversLoaded ** drlist) { char buf[255]; FILE * f; char * p; int i; struct driversLoaded * item = NULL; if (testing) return 0; f = fopen("/proc/modules", "r"); if (!f) { return INST_ERROR; } while (fgets(buf, sizeof(buf) - 1, f)) { p = strchr (buf, ' '); if (!p) return INST_ERROR; *p = 0; for (i = 0; drivers[i].name; i++) if (drivers[i].type == type) if (!strcmp(drivers[i].modules, buf)) { item = allocDL(drlist); item->module = strdup(buf); item->argv = NULL; item->argc = 0; item->persistFlags = 0; item->type = type; item->minor = DRIVER_MINOR_NONE; } } fclose(f); return 0; } #endif 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; } #if defined(__i386__) || defined(__alpha__) fprintf(f, "alias parport_lowlevel parport_pc\n"); #endif #if defined(__i386__) fprintf(f, "pre-install pcmcia_core /etc/rc.d/init.d/pcmcia start\n"); #endif #ifdef __sparc__ fprintf(f, "alias parport_lowlevel parport_ax\n"); #endif fclose(f); return 0; } static int checkSCSIDev(struct driver * dev) { return scsiDeviceAvailable(); } #ifndef DISABLE_NETWORK 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); } #endif /* 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]; char ** modStack; char * modStackSpace[50]; /* I always want to see the filesystem loading in testing mode */ if (!testing) { 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; } modStack = modStackSpace; *modStack = NULL; if ((rc = doLoadModule(modname, DRIVER_FS, DRIVER_MINOR_NONE, drlist, 1, &modStack))) /* module insertion failure - back out the deps */ while (*modStack) removeModule(*modStack), modStack--; return rc; } int loadModuleDep(char * path) { int fd; char * buf; struct stat sb; char * start, * end, * chptr; int i, numLines; fd = open(path, O_RDONLY); if (fd < 0) { logMessage("error opening %s: %s", path, strerror(errno)); return INST_ERROR; } fstat(fd, &sb); buf = alloca(sb.st_size + 1); read(fd, buf, sb.st_size); buf[sb.st_size] = '\0'; close(fd); start = buf; numLines = 0; while (start) { numLines++; start = strchr(start + 1, '\n'); } moduleDepList = malloc(sizeof(*moduleDepList) * numLines); start = buf; numLines = 0; 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 */ moduleDepList[numLines].name = strdup(start); i = strlen(chptr) / 3; moduleDepList[numLines].deps = malloc(sizeof(char **) * i); start = chptr, i = 0; while (start && *start) { chptr = strchr(start, ' '); if (chptr) *chptr = '\0'; moduleDepList[numLines].deps[i++] = strdup(start); if (chptr) start = chptr + 1; else start = NULL; while (start && *start && isspace(*start)) start++; } moduleDepList[numLines].deps = realloc(moduleDepList[numLines].deps, sizeof(char **) * (i + 1)); moduleDepList[numLines].deps[i] = NULL; numLines++; start = end + 1; } moduleDepList = realloc(moduleDepList, sizeof(*moduleDepList) * (numLines + 1)); moduleDepList[numLines].name = (void *) moduleDepList[numLines].deps = NULL; return 0; }