diff options
-rw-r--r-- | isys/Makefile | 2 | ||||
-rw-r--r-- | isys/eddsupport.c | 311 | ||||
-rw-r--r-- | isys/eddsupport.h | 9 | ||||
-rw-r--r-- | isys/isys.c | 23 | ||||
-rw-r--r-- | isys/isys.py | 12 | ||||
-rw-r--r-- | kickstart.py | 6 | ||||
-rw-r--r-- | loader2/Makefile | 2 | ||||
-rw-r--r-- | loader2/hdinstall.c | 81 | ||||
-rw-r--r-- | loader2/hdinstall.h | 1 | ||||
-rw-r--r-- | loader2/kickstart.c | 4 | ||||
-rw-r--r-- | loader2/loader.c | 7 |
11 files changed, 449 insertions, 9 deletions
diff --git a/isys/Makefile b/isys/Makefile index 6937955c3..f0b536cd0 100644 --- a/isys/Makefile +++ b/isys/Makefile @@ -5,7 +5,7 @@ CFLAGS = -ffunction-sections -I$(PYTHONINCLUDE) -I.. -Wall -Os -g -DHAVE_NFS -D OBJECTS = nfsmount.o nfsmount_clnt.o nfsmount_xdr.o imount.o getmacaddr.o \ smp.o devnodes.o cpio.o uncpio.o dasd.o \ lang.o isofs.o dns.o linkdetect.o pdc.o hpt.o silraid.o vio.o \ - ethtool.o getipaddr.o wireless.o + ethtool.o getipaddr.o wireless.o eddsupport.o SOBJECTS = $(patsubst %.o,%.lo,$(OBJECTS)) SOURCES = $(patsubst %.o,%.c,$(OBJECTS)) isys.c LOADLIBES = -lresolv -lpci -lpopt -lpump -lext2fs -lz -lbterm -lbogl -lwlite -lkudzu -lpci -lselinux diff --git a/isys/eddsupport.c b/isys/eddsupport.c new file mode 100644 index 000000000..72280c945 --- /dev/null +++ b/isys/eddsupport.c @@ -0,0 +1,311 @@ +/* + * eddsupport.c - handling of mapping disk drives in Linux to disk drives + * according to the BIOS using the edd kernel module + * + * Copyright 2004 Dell, Inc., Red Hat, Inc. + * + * Rezwanul_Kabir@Dell.com + * Jeremy Katz <katzj@redhat.com> + * + * This software may be freely redistributed under the terms of the GNU + * general public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/reboot.h> +#include <sys/types.h> +#include <linux/types.h> + +#include <kudzu/kudzu.h> + + +#include "eddsupport.h" +#include "isys.h" + + + +#define EDD_DIR "/sys/firmware/edd" +#define SIG_FILE "mbr_signature" +#define MBRSIG_OFFSET 0x1b8 + +#define HASH_TABLE_SIZE 17 + +struct diskMapEntry{ + uint32_t key; + char *diskname; + struct diskMapEntry *next; +}; + +struct diskMapTable { + struct diskMapEntry **table; + int tableSize; +}; + +static struct diskMapTable *mbrSigToName = NULL; +static int diskHashInit = 0; + + + +static struct diskMapTable* initializeHashTable(int); +static int insertHashItem(struct diskMapTable *, struct diskMapEntry *); +static struct diskMapEntry* lookupHashItem(struct diskMapTable *, uint32_t); +static int addToHashTable(struct diskMapTable *, uint32_t , char *); +static struct device ** createDiskList(); +static int mapBiosDisks(struct diskMapTable * , const char *); +static int readDiskSig(char *, uint32_t *); +static struct diskMapTable* uniqueSignatureExists(struct device **); +static int readMbrSig(char *, uint32_t *); + +/* This is the top level function that creates a disk list present in the + * system, checks to see if unique signatures exist on the disks at offset + * 0x1b8. If a unique signature exists then it will map BIOS disks to their + * corresponding hd/sd device names. Otherwise, we'll avoid mapping drives. + */ + +int probeBiosDisks() { + struct device ** devices = NULL; + struct diskMapTable *diskSigToName; + + devices = createDiskList(); + if(!devices){ + fprintf(stderr, "No disks!\n"); + return -1; + } + + if(!(diskSigToName = uniqueSignatureExists(devices))) { + fprintf(stderr, "WARNING: Unique disk signatures don't exist\n"); + return -1; + } else { + if(!mapBiosDisks(diskSigToName, EDD_DIR)){ + fprintf(stderr, "WARNING: couldn't map BIOS disks\n"); + return -1; + } + } + return 0; +} + + +static struct device ** createDiskList(){ + return probeDevices (CLASS_HD, BUS_UNSPEC, PROBE_ALL); +} + +static struct diskMapTable * uniqueSignatureExists(struct device **devices) { + uint32_t current_sig, headsig; + struct device **devhead, **devlist; + int i; + struct diskMapTable *hashTable; + + hashTable = initializeHashTable(HASH_TABLE_SIZE); + if(!hashTable){ + fprintf(stderr, "Error initializing diskSigToName table\n"); + return NULL; + } + + for (devhead = devices, i = 0; (*devhead) != NULL; devhead++, i++) { + if (readDiskSig((*devhead)->device, &headsig) < 0) { + return NULL; + } + + for (devlist = devhead + 1; (*devlist) != NULL; devlist++) { + if (readDiskSig((*devlist)->device, ¤t_sig) < 0) + return NULL; + + if (headsig == current_sig) + return NULL; + } + + if(!addToHashTable(hashTable, headsig, (*devhead)->device)) + return NULL; + } + + return hashTable; +} + + +static int readDiskSig(char *device, uint32_t *disksig) { + int fd, rc; + + if (devMakeInode(device, "/tmp/biosdev")){ + return -1; + } + + fd = open("/tmp/biosdev", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Error opening devce %s: %s\n ", device, + strerror(errno)); + return -1; + } + + rc = lseek(fd, MBRSIG_OFFSET, SEEK_SET); + if (rc < 0){ + close(fd); + + fprintf(stderr, "Error seeking to MBRSIG_OFFSET in %s: %s\n", + device, strerror(errno)); + return -1; + } + + rc = read(fd, disksig, sizeof(uint32_t)); + if (rc < sizeof(uint32_t)) { + close(fd); + + fprintf(stderr, "Failed to read signature from %s\n", device); + return -1; + } + + unlink("/tmp/biosdev"); + return 0; +} + +static int mapBiosDisks(struct diskMapTable* hashTable,const char *path) { + DIR *dirHandle; + struct dirent *entry; + char * sigFileName; + uint32_t mbrSig, biosNum; + struct diskMapEntry *hashItem; + + dirHandle = opendir(path); + if(!dirHandle){ + fprintf(stderr, "Failed to open directory %s: %s\n", path, + strerror(errno)); + return 0; + } + + mbrSigToName = initializeHashTable(HASH_TABLE_SIZE); + if(!mbrSigToName){ + fprintf(stderr, "Error initializing mbrSigToName table\n"); + return 0; + } + + while ((entry = readdir(dirHandle)) != NULL) { + if(!strncmp(entry->d_name,".",1) || !strncmp(entry->d_name,"..",2)) { + continue; + } + sscanf((entry->d_name+9), "%x", &biosNum); + + sigFileName = malloc(strlen(path) + strlen(entry->d_name) + 20); + sprintf(sigFileName, "%s/%s/%s", path, entry->d_name, SIG_FILE); + if (readMbrSig(sigFileName, &mbrSig) == 0) { + hashItem = lookupHashItem(hashTable, mbrSig); + if (!hashItem) + return 0; + if(!addToHashTable(mbrSigToName, (uint32_t)biosNum, + hashItem->diskname)) + return 0; + } + } + closedir(dirHandle); + return 1; +} + + +static int readMbrSig(char *filename, uint32_t *int_sig){ + FILE* fh; + + fh = fopen(filename,"r"); + if(fh == NULL) { + fprintf(stderr, "Error opening mbr_signature file %s: %s\n", filename, + strerror(errno)); + return -1; + } + fseek(fh, 0, SEEK_SET); + if (fscanf(fh, "%x", int_sig) != 1) { + fprintf(stderr, "Error reading %s\n", filename); + fclose(fh); + return -1; + } + + fclose(fh); + return 0; +} + + +static struct diskMapTable* initializeHashTable(int size) { + struct diskMapTable *hashTable; + + hashTable = malloc(sizeof(struct diskMapTable)); + hashTable->tableSize = size; + hashTable->table = malloc(sizeof(struct diskMapEntry *) * size); + memset(hashTable->table,0,(sizeof(struct diskMapEntry *) * size)); + return hashTable; +} + + +static int insertHashItem(struct diskMapTable *hashTable, + struct diskMapEntry *hashItem) { + int index; + + index = (hashItem->key) % (hashTable->tableSize); + + if(hashTable->table[index] == NULL){ + hashTable->table[index] = hashItem; + return index; + } else { + hashItem->next = hashTable->table[index]; + hashTable->table[index] = hashItem; + return index; + } +} + + +static struct diskMapEntry * lookupHashItem(struct diskMapTable *hashTable, + uint32_t itemKey) { + int index; + struct diskMapEntry *hashItem; + + index = itemKey % (hashTable->tableSize); + for (hashItem = hashTable->table[index]; + (hashItem != NULL) && (hashItem->key != itemKey); + hashItem = hashItem->next) { + ; + } + return hashItem; +} + + +static int addToHashTable(struct diskMapTable *hashTable, + uint32_t itemKey, char *diskName) { + int index; + struct diskMapEntry *diskSigToNameEntry; + + diskSigToNameEntry = malloc(sizeof(struct diskMapEntry)); + diskSigToNameEntry->next = NULL; + diskSigToNameEntry->key = itemKey; + diskSigToNameEntry->diskname = diskName; + + if ((index = insertHashItem(hashTable, diskSigToNameEntry)) < 0){ + fprintf(stderr, "Unable to insert item\n"); + return 0; + } else { + return 1; + } +} + + +char * getBiosDisk(char *biosStr) { + uint32_t biosNum; + + if (diskHashInit == 0) { + probeBiosDisks(); + diskHashInit = 1; + } + + if (mbrSigToName == NULL) + return NULL; + + sscanf(biosStr,"%x",&biosNum); + return lookupHashItem(mbrSigToName, biosNum)->diskname; +} diff --git a/isys/eddsupport.h b/isys/eddsupport.h new file mode 100644 index 000000000..b7a390f43 --- /dev/null +++ b/isys/eddsupport.h @@ -0,0 +1,9 @@ +#ifndef EDDSUPPORT_H +#define EDDSUPPORT_H + +int probeBiosDisks(); +char* getBiosDisk(char *); + +#endif + + diff --git a/isys/isys.c b/isys/isys.c index d16538871..164e5ea2e 100644 --- a/isys/isys.c +++ b/isys/isys.c @@ -49,6 +49,7 @@ #include "lang.h" #include "getmacaddr.h" #include "wireless.h" +#include "eddsupport.h" #ifndef CDROMEJECT #define CDROMEJECT 0x5309 @@ -111,6 +112,8 @@ static PyObject * doGetMacAddress(PyObject * s, PyObject * args); static PyObject * doGetIPAddress(PyObject * s, PyObject * args); static PyObject * doResetFileContext(PyObject * s, PyObject * args); static PyObject * isWireless(PyObject * s, PyObject * args); +static PyObject * doProbeBiosDisks(PyObject * s, PyObject * args); +static PyObject * doGetBiosDisk(PyObject * s, PyObject * args); static PyMethodDef isysModuleMethods[] = { { "ejectcdrom", (PyCFunction) doEjectCdrom, METH_VARARGS, NULL }, @@ -168,6 +171,8 @@ static PyMethodDef isysModuleMethods[] = { { "getIPAddress", (PyCFunction) doGetIPAddress, METH_VARARGS, NULL}, { "resetFileContext", (PyCFunction) doResetFileContext, METH_VARARGS, NULL }, { "isWireless", (PyCFunction) isWireless, METH_VARARGS, NULL }, + { "biosDiskProbe", (PyCFunction) doProbeBiosDisks, METH_VARARGS,NULL}, + { "getbiosdisk",(PyCFunction) doGetBiosDisk, METH_VARARGS,NULL}, { NULL } } ; @@ -1435,3 +1440,21 @@ static PyObject * start_bterm(PyObject * s, PyObject * args) { return Py_BuildValue("i", isysStartBterm()); } + +static PyObject * doProbeBiosDisks(PyObject * s, PyObject * args) { + if (!PyArg_ParseTuple(args, "")) return NULL; + + + return Py_BuildValue("i", probeBiosDisks()); +} + +static PyObject * doGetBiosDisk(PyObject * s, PyObject * args) { + char *mbr_sig; + char *diskname; + + if (!PyArg_ParseTuple(args, "s", &mbr_sig)) return NULL; + + diskname = getBiosDisk(mbr_sig); + return Py_BuildValue("s", diskname); + +} diff --git a/isys/isys.py b/isys/isys.py index 4a2fd59a0..3a850f553 100644 --- a/isys/isys.py +++ b/isys/isys.py @@ -1,10 +1,11 @@ # -# isys.py - installer utilitiy functions and glue for C module +# isys.py - installer utility functions and glue for C module # # Matt Wilson <msw@redhat.com> # Erik Troan <ewt@redhat.com> +# Jeremy Katz <katzj@redhat.com> # -# Copyright 2001 Red Hat, Inc. +# Copyright 2001 - 2004 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # library public license. @@ -724,6 +725,13 @@ def resetFileContext(fn): def startBterm(): return _isys.startBterm() +def doProbeBiosDisks(): + return _isys.biosDiskProbe() + +def doGetBiosDisk(mbrSig): + return _isys.getbiosdisk(mbrSig) + + printObject = _isys.printObject bind_textdomain_codeset = _isys.bind_textdomain_codeset isVioConsole = _isys.isVioConsole diff --git a/kickstart.py b/kickstart.py index a3b783c24..f25274ec8 100644 --- a/kickstart.py +++ b/kickstart.py @@ -1138,7 +1138,7 @@ class KickstartBase(BaseInstallClass): 'type=', 'fstype=', 'asprimary', 'noformat', 'start=', 'end=', 'badblocks', 'recommended', - 'ondrive=']) + 'ondrive=', 'onbiosdisk=' ]) for n in args: (str, arg) = n @@ -1152,6 +1152,10 @@ class KickstartBase(BaseInstallClass): onPart = arg elif str == '--ondisk' or str == '--ondrive': disk = arg + elif str == '--onbiosdisk': + disk = isys.doGetBiosDisk(arg) + if disk is None: + raise KickstartValueError, "Specified BIOS disk %s cannot be determined" %(arg,) elif str == '--bytes-per-inode': fsopts = ['-i', arg] # XXX this doesn't do anything right now diff --git a/loader2/Makefile b/loader2/Makefile index 0fae6a689..e628454ec 100644 --- a/loader2/Makefile +++ b/loader2/Makefile @@ -16,7 +16,7 @@ GUNZIP = -lz BINS = loader HWOBJS = pcmcia.o usb.o firewire.o hardware.o -METHOBJS = method.o cdinstall.o hdinstall.o nfsinstall.o urlinstall.o +METHOBJS = method.o cdinstall.o hdinstall.o nfsinstall.o urlinstall.o OBJS = log.o moduleinfo.o loadermisc.o modules.o moduledeps.o windows.o \ lang.o kbd.o modstubs.o driverdisk.o selinux.o \ md5.o mediacheck.o kickstart.o driverselect.o \ diff --git a/loader2/hdinstall.c b/loader2/hdinstall.c index 5da43a983..31d9b4c87 100644 --- a/loader2/hdinstall.c +++ b/loader2/hdinstall.c @@ -40,7 +40,7 @@ #include "../isys/imount.h" #include "../isys/isys.h" - +#include "../isys/eddsupport.h" /* pull in second stage image for hard drive install */ @@ -447,14 +447,17 @@ char * mountHardDrive(struct installMethod * method, void setKickstartHD(struct loaderData_s * loaderData, int argc, char ** argv, int * flagsPtr) { - char *partition, *dir; + char *biospart, *partition, *dir, *p; poptContext optCon; int rc; + struct poptOption ksHDOptions[] = { + { "biospart", '\0', POPT_ARG_STRING, &biospart, 0 }, { "partition", '\0', POPT_ARG_STRING, &partition, 0 }, { "dir", '\0', POPT_ARG_STRING, &dir, 0 }, { 0, 0, 0, 0, 0 } }; + logMessage("kickstartFromHD"); optCon = poptGetContext(NULL, argc, (const char **) argv, ksHDOptions, 0); @@ -468,6 +471,24 @@ void setKickstartHD(struct loaderData_s * loaderData, int argc, return; } + if (biospart) { + char * dev; + + p = strchr(biospart,'p'); + if(!p){ + logMessage("Bad argument for --biospart"); + return; + } + *p = '\0'; + dev = getBiosDisk(biospart); + if (dev == NULL) { + logMessage("Unable to location BIOS partition %s", biospart); + return; + } + partition = malloc(strlen(dev) + strlen(p) + 2); + sprintf(partition, "%s%s", dev, p); + } + loaderData->method = strdup("hd"); loaderData->methodData = calloc(sizeof(struct hdInstallData *), 1); if (partition) @@ -518,3 +539,59 @@ int kickstartFromHD(char *kssrc, int flags) { return 0; } + + +int kickstartFromBD(char *kssrc, int flags) { + int rc; + char *p, *q = NULL, *r = NULL, *tmpstr, *ksdev, *kspath, *biosksdev; + + logMessage("getting kickstart file from biosdrive"); + + /* format is ks=bd:[device]:/path/to/ks.cfg */ + /* split of pieces */ + tmpstr = strdup(kssrc); + p = strchr(tmpstr, ':'); + if (p) + q = strchr(p+1, ':'); + + if (!p || !q) { + logMessage("Format of command line is ks=bd:device:/path/to/ks.cfg"); + free(tmpstr); + return 1; + } + + *q = '\0'; + kspath = q+1; + + r = strchr(p+1,'p'); + if(!r){ + logMessage("Format of biosdisk is 80p1"); + free(tmpstr); + return 1; + } + + *r = '\0'; + biosksdev = getBiosDisk((p + 1)); + if(!biosksdev){ + startNewt(flags); + newtWinMessage(_("Error"), _("OK"), + _("Cannot find hard drive for BIOS disk %s"), + p + 1); + return 1; + } + + + ksdev = malloc(strlen(biosksdev) + 3); + sprintf(ksdev, "%s%s", biosksdev, r + 1); + logMessage("Loading ks from device %s on path %s", ksdev, kspath); + if ((rc=getKickstartFromBlockDevice(ksdev, kspath))) { + if (rc == 3) { + startNewt(flags); + newtWinMessage(_("Error"), _("OK"), + _("Cannot find kickstart file on hard drive.")); + } + return 1; + } + + return 0; +} diff --git a/loader2/hdinstall.h b/loader2/hdinstall.h index c4277a41e..5f4293e3f 100644 --- a/loader2/hdinstall.h +++ b/loader2/hdinstall.h @@ -16,5 +16,6 @@ char * mountHardDrive(struct installMethod * method, moduleInfoSet modInfo, moduleList modLoaded, moduleDeps * modDepsPtr, int flags); int kickstartFromHD(char *kssrc, int flags); +int kickstartFromBD(char *kssrc, int flags); #endif diff --git a/loader2/kickstart.c b/loader2/kickstart.c index 20dc733d6..1d3d3b81e 100644 --- a/loader2/kickstart.c +++ b/loader2/kickstart.c @@ -330,6 +330,10 @@ void getKickstartFile(struct loaderData_s * loaderData, int * flagsPtr) { if (kickstartFromHD(c, *flagsPtr)) return; loaderData->ksFile = strdup("/tmp/ks.cfg"); + } else if (!strncmp(c, "ks=bd:", 6)) { + if (kickstartFromBD(c, *flagsPtr)) + return; + loaderData->ksFile = strdup("/tmp/ks.cfg"); } else if (!strncmp(c, "ks=cdrom", 8)) { if (kickstartFromCD(c, *flagsPtr)) return; diff --git a/loader2/loader.c b/loader2/loader.c index 28ec832da..44163fb56 100644 --- a/loader2/loader.c +++ b/loader2/loader.c @@ -80,6 +80,7 @@ #include "../isys/isys.h" #include "../isys/stubs.h" #include "../isys/lang.h" +#include "../isys/eddsupport.h" /* maximum number of extra arguments that can be passed to the second stage */ #define MAX_EXTRA_ARGS 128 @@ -1168,6 +1169,7 @@ int main(int argc, char ** argv) { memset(&loaderData, 0, sizeof(loaderData)); + extraArgs[0] = NULL; flags = parseCmdLineFlags(flags, &loaderData, cmdLine); @@ -1195,8 +1197,8 @@ int main(int argc, char ** argv) { if (isVioConsole()) setenv("TERM", "vt100", 1); - mlLoadModuleSet("cramfs:vfat:nfs:loop:isofs:floppy", modLoaded, modDeps, - modInfo, flags); + mlLoadModuleSet("cramfs:vfat:nfs:loop:isofs:floppy:edd", + modLoaded, modDeps, modInfo, flags); /* now let's do some initial hardware-type setup */ ideSetup(modLoaded, modDeps, modInfo, flags); @@ -1253,6 +1255,7 @@ int main(int argc, char ** argv) { getDDFromSource(&loaderData, loaderData.ddsrc, flags); } + /* JKFIXME: loaderData->ksFile is set to the arg from the command line, * and then getKickstartFile() changes it and sets FL_KICKSTART. * kind of weird. */ |