home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 February
/
CHIP_2_98.iso
/
misc
/
src
/
install
/
devices.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-09
|
37KB
|
1,412 lines
#include <alloca.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <newt.h>
#include <popt.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
#include <zlib.h>
#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;
}