- updates the code to agree with current anaconda API - adds dlabel functionality - also adds some stub calls to set modprobe behaviour --- loader/driverdisk.c | 333 +++++++++++++++++++++++++++++++++++++++++++++------ loader/driverdisk.h | 20 +++ loader/loader.c | 37 ++++++ loader/loader.h | 2 + 4 files changed, 355 insertions(+), 37 deletions(-) diff --git a/loader/driverdisk.c b/loader/driverdisk.c index 5f8d43c..f718684 100644 --- a/loader/driverdisk.c +++ b/loader/driverdisk.c @@ -30,6 +30,12 @@ #include <unistd.h> #include <glib.h> +#include <blkid/blkid.h> + +#include <glob.h> +#include <rpm/rpmlib.h> +#include <sys/utsname.h> + #include "copy.h" #include "loader.h" #include "log.h" @@ -48,6 +54,8 @@ #include "nfsinstall.h" #include "urlinstall.h" +#include "rpmextract.h" + #include "../isys/isys.h" #include "../isys/imount.h" #include "../isys/eddsupport.h" @@ -55,37 +63,175 @@ /* boot flags */ extern uint64_t flags; -static char * driverDiskFiles[] = { "modinfo", "modules.dep", - "modules.cgz", "modules.alias", NULL }; +/* modprobe DD mode */ +int modprobeDDmode() +{ + FILE *f = fopen("/etc/depmod.d/ddmode.conf", "w"); + if(f){ + struct utsname unamedata; + if(uname(&unamedata)){ + fprintf(f, " pblacklist /lib/modules\n"); + } + else{ + fprintf(f, " pblacklist /lib/modules/%s\n", unamedata.release); + } + + fclose(f); + } + + return f==NULL; +} + +int modprobeNormalmode() +{ + unlink("/etc/depmod.d/ddmode.conf"); + + /* run depmod to refresh modules db */ + if(system("depmod -a")){ + /* FIXME: depmod didn't run */ + } + + return 0; +} + +/* RPM extraction dependency checks */ +int dlabelDeps(const char* depends, void *userptr) +{ + logMessage(DEBUGLVL, "Depends on: %s\n", depends); + return 0; +} + +int dlabelProvides(const char* dep, void *userptr) +{ + char *kernelver = (char*)userptr; + + logMessage(DEBUGLVL, "Provides: %s\n", dep); + + return strcmp(dep, kernelver); +} + +int dlabelFilter(const char* name, struct stat *fstat, void *userptr) +{ + int l = strlen(name); + + logMessage(DEBUGLVL, "Unpacking %s (%lluB)\n", name, fstat->st_size); + + /* we want firmware files */ + if(!strncmp("lib/firmware/", name, 13)) return 0; + + if(l<3) return 1; + l-=3; + + /* and we want only .ko files */ + if(strncmp(".ko", name+l, 3)) return 1; + + /* TODO we are unpacking kernel module, read it's description */ + + return 0; +} + +char* moduleDescription(const char* modulePath) +{ + char *command = rstrscat(NULL, "modinfo --description '", modulePath, "'", NULL); + FILE *f = popen(command, "r"); + if(f==NULL) return NULL; + + char *description = malloc(sizeof(char)*256); + int size = fread(description, 1, 255, f); + if(size==0){ + free(description); + return NULL; + } + description[size-1]=0; /* strip the trailing newline */ + pclose(f); + + free(command); + return description; +} + +int globErrFunc(const char *epath, int eerrno) +{ + return 0; +} + +int dlabelUnpackRPMDir(char* rpmdir, char* destination) +{ + char *kernelver; + struct utsname unamedata; + char *oldcwd; + char *globpattern; + int rc; + + /* get current working directory */ + oldcwd = getcwd(NULL, 0); + + /* set the cwd to destination */ + if(chdir(destination)){ + free(oldcwd); + return 1; + } + + /* get running kernel version */ + if(uname(&unamedata)){ + kernelver = rstrscat(NULL, "kernel-modules-", "unknown", NULL); + } + else{ + kernelver = rstrscat(NULL, "kernel-modules-", unamedata.release, NULL); + } + logMessage(DEBUGLVL, "Kernel version: %s\n", kernelver); + + globpattern = rstrscat(NULL, rpmdir, "/*.rpm", NULL); + glob_t globres; + char** globitem; + if(!glob(globpattern, GLOB_NOSORT|GLOB_NOESCAPE, globErrFunc, &globres)){ + /* iterate over all rpm files */ + globitem = globres.gl_pathv; + while(globres.gl_pathc>0 && globitem!=NULL){ + explodeRPM(*globitem, dlabelFilter, dlabelProvides, dlabelDeps, kernelver); + } + globfree(&globres); + /* end of iteration */ + } + free(globpattern); + + /* restore CWD */ + if(chdir(oldcwd)){ + /* FIXME: too bad.. */ + } + + /* cleanup */ + free(kernelver); + free(oldcwd); + return rc; +} + + +static char * driverDiskFiles[] = { "repodata", NULL }; static int verifyDriverDisk(char *mntpt) { char ** fnPtr; char file[200]; struct stat sb; - for (fnPtr = driverDiskFiles; *fnPtr; fnPtr++) { - sprintf(file, "%s/%s", mntpt, *fnPtr); - if (access(file, R_OK)) { - logMessage(ERROR, "cannot find %s, bad driver disk", file); - return LOADER_BACK; - } - } - - /* check for both versions */ + /* check for dd descriptor */ sprintf(file, "%s/rhdd", mntpt); if (access(file, R_OK)) { - logMessage(DEBUGLVL, "not a new format driver disk, checking for old"); - sprintf(file, "%s/rhdd-6.1", mntpt); - if (access(file, R_OK)) { - logMessage(ERROR, "can't find either driver disk identifier, bad " - "driver disk"); - } + logMessage(ERROR, "can't find driver disk identifier, bad " + "driver disk"); + return LOADER_BACK; } /* side effect: file is still mntpt/ddident */ stat(file, &sb); if (!sb.st_size) return LOADER_BACK; + for (fnPtr = driverDiskFiles; *fnPtr; fnPtr++) { + sprintf(file, "%s/%s/%s", mntpt, getProductArch(), *fnPtr); + if (access(file, R_OK)) { + logMessage(ERROR, "cannot find %s, bad driver disk", file); + return LOADER_BACK; + } + } return LOADER_OK; } @@ -101,25 +247,20 @@ static void copyErrorFn (char *msg) { /* this copies the contents of the driver disk to a ramdisk and loads * the moduleinfo, etc. assumes a "valid" driver disk mounted at mntpt */ static int loadDriverDisk(struct loaderData_s *loaderData, char *mntpt) { - moduleInfoSet modInfo = loaderData->modInfo; - char file[200], dest[200]; + /* FIXME moduleInfoSet modInfo = loaderData->modInfo; */ + char file[200], dest[200], src[200]; char *title; char *fwdir = NULL; struct moduleBallLocation * location; struct stat sb; static int disknum = 0; - int version = 1; int fd, ret; - /* check for both versions */ - sprintf(file, "%s/rhdd", mntpt); + /* check for new version */ + sprintf(file, "%s/rhdd3", mntpt); if (access(file, R_OK)) { - version = 0; - sprintf(file, "%s/rhdd-6.1", mntpt); - if (access(file, R_OK)) { - /* this can't happen, we already verified it! */ - return LOADER_BACK; - } + /* this can't happen, we already verified it! */ + return LOADER_BACK; } stat(file, &sb); title = malloc(sb.st_size + 1); @@ -131,23 +272,35 @@ static int loadDriverDisk(struct loaderData_s *loaderData, char *mntpt) { title[sb.st_size] = '\0'; close(fd); - sprintf(file, "/tmp/DD-%d", disknum); + sprintf(file, DD_RPMS, disknum); mkdirChain(file); + mkdirChain(DD_MODULES); + mkdirChain(DD_FIRMWARE); if (!FL_CMDLINE(flags)) { startNewt(); winStatus(40, 3, _("Loading"), _("Reading driver disk")); } - sprintf(dest, "/tmp/DD-%d", disknum); - copyDirectory(mntpt, dest, copyWarnFn, copyErrorFn); - location = malloc(sizeof(struct moduleBallLocation)); location->title = strdup(title); - location->version = version; - checked_asprintf(&location->path, "/tmp/DD-%d/modules.cgz", disknum); - checked_asprintf(&fwdir, "/tmp/DD-%d/firmware", disknum); + checked_asprintf(&location->path, DD_MODULES); + checked_asprintf(&fwdir, DD_FIRMWARE); + + sprintf(dest, DD_RPMS, disknum); + sprintf(src, "%s/rpms/%s", mntpt, getProductArch()); + copyDirectory(src, dest, copyWarnFn, copyErrorFn); + + /* unpack packages from dest into location->path */ + if(dlabelUnpackRPMDir(dest, DD_EXTRACTED)){ + /* TODO error handler */ + } + + /* run depmod to refresh modules db */ + if(system("depmod -a")){ + /* FIXME: depmod didn't run */ + } if (!access(fwdir, R_OK|X_OK)) { add_fw_search_dir(loaderData, fwdir); @@ -156,8 +309,11 @@ static int loadDriverDisk(struct loaderData_s *loaderData, char *mntpt) { } free(fwdir); - sprintf(file, "%s/modinfo", mntpt); - readModuleInfo(file, modInfo, location, 1); + /* TODO generate and read module info + * + * sprintf(file, "%s/modinfo", mntpt); + * readModuleInfo(file, modInfo, location, 1); + */ if (!FL_CMDLINE(flags)) newtPopWindow(); @@ -623,3 +779,106 @@ static void getDDFromDev(struct loaderData_s * loaderData, char * dev) { umount("/tmp/drivers"); unlink("/tmp/drivers"); } + +/* + * Utility functions to maintain linked-list of device names + * */ + +struct ddlist* ddlist_add(struct ddlist *list, const char* device) +{ + struct ddlist* item; + + item = (struct ddlist*)malloc(sizeof(struct ddlist)); + if(item==NULL){ + return list; + } + + item->device = strdup(device); + item->next = list; + + return item; +} + +int ddlist_free(struct ddlist *list) +{ + struct ddlist *next; + int count = 0; + + while(list!=NULL){ + next = list->next; + free(list->device); + free(list); + list = next; + count++; + } + + return count; +} + + +/* + * Look for partition with specific label (part of #316481) + */ +struct ddlist* findDriverDiskByLabel(void) +{ + char *ddLabel = "OEMDRV"; + struct ddlist *ddDevice = NULL; + blkid_cache bCache; + + int res; + blkid_dev_iterate bIter; + blkid_dev bDev; + + if(blkid_get_cache(&bCache, NULL)<0){ + logMessage(ERROR, _("Cannot initialize cache instance for blkid")); + return NULL; + } + if((res = blkid_probe_all(bCache))<0){ + logMessage(ERROR, _("Cannot probe devices in blkid: %d"), res); + return NULL; + } + + bIter = blkid_dev_iterate_begin(bCache); + blkid_dev_set_search(bIter, "LABEL", ddLabel); + while((res = blkid_dev_next(bIter, &bDev))!=0){ + bDev = blkid_verify(bCache, bDev); + if(!bDev) + continue; + logMessage(DEBUGLVL, _("Adding driver disc %s to the list of available DDs."), blkid_dev_devname(bDev)); + ddDevice = ddlist_add(ddDevice, blkid_dev_devname(bDev)); + /*blkid_free_dev(bDev); -- probably taken care of by the put cache call.. it is not exposed in the API */ + } + blkid_dev_iterate_end(bIter); + + blkid_put_cache(bCache); + + return ddDevice; +} + +int loadDriverDiskFromPartition(struct loaderData_s *loaderData, char* device) +{ + int rc; + + logMessage(INFO, "trying to mount %s", device); + if (doPwMount(device, "/tmp/drivers", "auto", "ro", NULL)) { + logMessage(ERROR, _("Failed to mount driver disk.")); + return -1; + } + + rc = verifyDriverDisk("/tmp/drivers"); + if (rc == LOADER_BACK) { + logMessage(ERROR, _("Driver disk is invalid for this " + "release of %s."), getProductName()); + umount("/tmp/drivers"); + return -2; + } + + rc = loadDriverDisk(loaderData, "/tmp/drivers"); + umount("/tmp/drivers"); + if (rc == LOADER_BACK) { + return -3; + } + + return 0; +} + diff --git a/loader/driverdisk.h b/loader/driverdisk.h index e6e919d..3e442fb 100644 --- a/loader/driverdisk.h +++ b/loader/driverdisk.h @@ -24,6 +24,11 @@ #include "modules.h" #include "moduleinfo.h" +#define DD_RPMS "/tmp/DD-%d" +#define DD_EXTRACTED "/tmp/DD" +#define DD_MODULES "/tmp/DD/lib/modules" +#define DD_FIRMWARE "/tmp/DD/lib/firmware" + extern char *ddFsTypes[]; int loadDriverFromMedia(int class, struct loaderData_s *loaderData, @@ -39,4 +44,19 @@ void useKickstartDD(struct loaderData_s * loaderData, int argc, void getDDFromSource(struct loaderData_s * loaderData, char * src); +int loadDriverDiskFromPartition(struct loaderData_s *loaderData, char* device); + +struct ddlist { + char* device; + struct ddlist* next; +}; + +struct ddlist* ddlist_add(struct ddlist *list, const char* device); +int ddlist_free(struct ddlist *list); + +struct ddlist* findDriverDiskByLabel(void); + +int modprobeNormalmode(); +int modprobeDDmode(); + #endif diff --git a/loader/loader.c b/loader/loader.c index cd3e178..3159513 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -959,6 +959,10 @@ static void parseCmdLineFlags(struct loaderData_s * loaderData, else if (!strcasecmp(argv[i], "dd") || !strcasecmp(argv[i], "driverdisk")) flags |= LOADER_FLAGS_MODDISK; + else if (!strcasecmp(argv[i], "dlabel=on")) + flags |= LOADER_FLAGS_AUTOMODDISK; + else if (!strcasecmp(argv[i], "dlabel=off")) + flags &= ~LOADER_FLAGS_AUTOMODDISK; else if (!strcasecmp(argv[i], "rescue")) flags |= LOADER_FLAGS_RESCUE; else if (!strcasecmp(argv[i], "nopass")) @@ -1785,6 +1789,7 @@ int main(int argc, char ** argv) { struct loaderData_s loaderData; char *path; + struct ddlist *dd, *dditer; gchar *cmdLine = NULL, *ksFile = NULL, *virtpcon = NULL; gboolean testing = FALSE, mediacheck = FALSE; @@ -1882,6 +1887,12 @@ int main(int argc, char ** argv) { flags |= LOADER_FLAGS_NOSHELL; #endif + /* XXX if RHEL, enable the AUTODD feature by default, + * but we should come with more general way how to control this */ + if(!strncmp(getProductName(), "Red Hat", 7)){ + flags |= LOADER_FLAGS_AUTOMODDISK; + } + openLog(FL_TESTING(flags)); if (!FL_TESTING(flags)) openlog("loader", 0, LOG_LOCAL0); @@ -1946,6 +1957,26 @@ int main(int argc, char ** argv) { /* FIXME: this is a bit of a hack */ loaderData.modInfo = modInfo; + /* Setup depmod & modprobe so we can load multiple DDs */ + modprobeDDmode(); + + if(FL_AUTOMODDISK(flags)){ + /* Load all autodetected DDs */ + logMessage(INFO, "Trying to detect vendor driver discs"); + dd = findDriverDiskByLabel(); + dditer = dd; + while(dditer){ + if(loadDriverDiskFromPartition(&loaderData, dditer->device)){ + logMessage(ERROR, "Automatic driver disk loader failed for %s.", dditer->device); + } + else{ + logMessage(INFO, "Automatic driver disk loader succeeded for %s.", dditer->device); + } + dditer = dditer->next; + } + ddlist_free(dd); + } + if (FL_MODDISK(flags)) { startNewt(); loadDriverDisks(DEVICE_ANY, &loaderData); @@ -1955,6 +1986,9 @@ int main(int argc, char ** argv) { logMessage(INFO, "found /dd.img, loading drivers"); getDDFromSource(&loaderData, "path:/dd.img"); } + + /* Reset depmod & modprobe to normal mode and get the rest of drivers*/ + modprobeNormalmode(); /* this allows us to do an early load of modules specified on the * command line to allow automating the load order of modules so that @@ -2139,6 +2173,9 @@ int main(int argc, char ** argv) { tmparg++; } + if (FL_AUTOMODDISK(flags)) + *argptr++ = "--dlabel"; + if (FL_NOIPV4(flags)) *argptr++ = "--noipv4"; diff --git a/loader/loader.h b/loader/loader.h index ebf3766..ca6404f 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -70,6 +70,7 @@ #define LOADER_FLAGS_HAVE_CMSCONF (((uint64_t) 1) << 37) #define LOADER_FLAGS_NOKILL (((uint64_t) 1) << 38) #define LOADER_FLAGS_KICKSTART_SEND_SERIAL (((uint64_t) 1) << 39) +#define LOADER_FLAGS_AUTOMODDISK (((uint64_t) 1) << 40) #define FL_TESTING(a) ((a) & LOADER_FLAGS_TESTING) #define FL_TEXT(a) ((a) & LOADER_FLAGS_TEXT) @@ -107,6 +108,7 @@ #define FL_HAVE_CMSCONF(a) ((a) & LOADER_FLAGS_HAVE_CMSCONF) #define FL_NOKILL(a) ((a) & LOADER_FLAGS_NOKILL) #define FL_KICKSTART_SEND_SERIAL(a) ((a) & LOADER_FLAGS_KICKSTART_SEND_SERIAL) +#define FL_AUTOMODDISK(a) ((a) & LOADER_FLAGS_AUTOMODDISK) void startNewt(void); void stopNewt(void); -- 1.6.4.4 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list