#include #include #include #include #include #include #include #include #include #include #include "dns.h" #include "fs.h" #include "hd.h" #include "intl.h" #include "install.h" #include "kickstart.h" #include "log.h" #include "methods.h" #include "net.h" #include "windows.h" /* This was split into two pieces to keep the initial install program small */ static int nfsPrepare(struct installMethod * method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl); static int cdromPrepare(struct installMethod * method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl); static int nfsGetSetup(char ** hostptr, char ** dirptr); int floppyRoot(struct installMethod * method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl); static int totalMemory(void); /* in K */ #define CDROM_METHOD_NUM 0 #define NFS_METHOD_NUM 1 /* We have a loop a bit later which translates the 'Local CDROM' language */ static struct installMethod methods[] = { { "Local CDROM", "cdrom", 0, cdromPrepare, NULL, NULL, NULL, NULL, NULL }, { "NFS image", "nfs", 0, nfsPrepare, NULL, NULL, NULL, NULL, NULL }, { "hard drive", "hd", 0, floppyRoot, NULL, NULL, NULL, NULL, NULL }, { "FTP", "ftp", 0, floppyRoot, NULL, NULL, NULL, NULL, NULL }, { "SMB image", "smb", 0, floppyRoot, NULL, NULL, NULL, NULL, NULL }, #if 0 { "SCSI Tape Install", "tape", 0, floppyRoot, NULL, NULL, NULL, NULL, NULL }, #endif } ; static int numMethods = sizeof(methods) / sizeof(struct installMethod); #define LOAD_BLOCK_COUNT 16 static int loadRamdisk(char * todev, char * fromdev, int blocks, char * label) { newtComponent form, scale; char * topath, * frompath; char buf[LOAD_BLOCK_COUNT * 1024]; int rc = 0; int i; int to, from; if (blocks % LOAD_BLOCK_COUNT) { logMessage("internal error: blocks in loadRamdisk() must be " "divisible by %d!!", LOAD_BLOCK_COUNT); return 1; } topath = alloca(strlen(todev) + 8); sprintf(topath, "/tmp/%s", todev); frompath = alloca(strlen(fromdev) + 8); sprintf(frompath, "/tmp/%s", fromdev); if (devMakeInode(todev, topath)) return 1; if (devMakeInode(fromdev, frompath)) { unlink(topath); return 1; } to = open(topath, O_WRONLY); if (to < 0) { logMessage("failed to open %s: %s", topath, strerror(errno)); unlink(topath); unlink(frompath); return 1; } from = open(frompath, O_RDONLY); if (from < 0) { logMessage("failed to open %s: %s", frompath, strerror(errno)); unlink(topath); unlink(frompath); return 1; } unlink(frompath); unlink(topath); logMessage("copying %d blocks from %s to %s", blocks, fromdev, todev); newtCenteredWindow(60, 5, "Loading"); form = newtForm(NULL, NULL, 0); newtFormAddComponent(form, newtLabel(1, 1, label)); scale = newtScale(1, 3, 58, blocks / LOAD_BLOCK_COUNT); newtFormAddComponent(form, scale); newtDrawForm(form); newtRefresh(); for (i = 0; i < (blocks / LOAD_BLOCK_COUNT) && !rc; i++) { newtScaleSet(scale, i); newtRefresh(); if (read(from, buf, sizeof(buf)) != sizeof(buf)) { logMessage("error reading from device: %s", strerror(errno)); rc = 1; } else { if (write(to, buf, sizeof(buf)) != sizeof(buf)) { logMessage("error writing to device: %s", strerror(errno)); rc = 1; } } } newtPopWindow(); newtFormDestroy(form); close(from); close(to); return rc; } static int totalMemory(void) { int fd; int bytesRead; char buf[4096]; char * chptr, * start; int total = 0; fd = open("/proc/meminfo", O_RDONLY); if (fd < 0) { logMessage("failed to open /proc/meminfo: %s", strerror(errno)); return 0; } bytesRead = read(fd, buf, sizeof(buf) - 1); if (bytesRead < 0) { logMessage("failed to read from /proc/meminfo: %s", strerror(errno)); close(fd); return 0; } close(fd); buf[bytesRead] = '\0'; chptr = buf; while (*chptr && !total) { if (*chptr != '\n' || strncmp(chptr + 1, "MemTotal:", 9)) { chptr++; continue; } start = ++chptr ; while (*chptr && *chptr != '\n') chptr++; *chptr = '\0'; logMessage("found total memory tag: \"%s\"", start); while (!isdigit(*start) && *start) start++; if (!*start) { logMessage("no number appears after MemTotal tag"); return 0; } chptr = start; while (*chptr && isdigit(*chptr)) { total = (total * 10) + (*chptr - '0'); chptr++; } } logMessage("%d kB are available", total); return total; } static int installMethodWindow(struct installMethod ** method) { char * methodList[10]; static int methodNum = 0; int i, rc; for (i = 0; i < numMethods; i++) { methodList[i] = _(methods[i].name); } methodList[i] = NULL; rc = newtWinMenu(_("Installation Method"), _("What type of media contains " "the packages to be installed?"), 30, 5, 5, 7, methodList, &methodNum, _("Ok"), _("Back"), NULL); if (rc == 2) return INST_CANCEL; *method = methods + methodNum; return 0; } int chooseInstallMethod(struct installMethod ** method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl) { int rc; if (kickstart) { if (!ksGetCommand(KS_CMD_NFS, NULL, NULL, NULL)) { *method = methods + NFS_METHOD_NUM; return (*method)->prepareImage((*method), netc, intf, dl); } else if (!ksGetCommand(KS_CMD_CDROM, NULL, NULL, NULL)) { *method = methods + CDROM_METHOD_NUM; return (*method)->prepareImage((*method), netc, intf, dl); } else { logMessage("No kickstart method was specified."); kickstart = 0; } } do { rc = installMethodWindow(method); if (rc) return rc; if ((*method)->prepareImage) { rc = (*method)->prepareImage((*method), netc, intf, dl); if (rc == INST_ERROR) return rc; } } while (rc); return 0; } /* We could use newtWinEntries() here, if we didn't like those clever callbacks */ static int nfsGetSetup(char ** hostptr, char ** dirptr) { newtComponent form, okay, cancel, answer, text; newtComponent siteLabel, dirLabel; newtGrid buttons, entryArea, grid; struct nfsMountCallbackInfo cbInfo; char * reflowedText; int width, height; if (*hostptr) { cbInfo.serverVal = *hostptr; cbInfo.netpathVal = *dirptr; } else { cbInfo.serverVal = ""; cbInfo.netpathVal = ""; } form = newtForm(NULL, NULL, 0); buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL); reflowedText = newtReflowText( _("Please enter the following information:\n" "\n" " o the name or IP number of your NFS server\n" " o the directory on that server containing\n" " Linux Mandrake for your architecture"), 60, 10, 10, &width, &height); text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, reflowedText); free(reflowedText); entryArea = newtCreateGrid(2, 2); siteLabel = newtLabel(-1, -1, _("NFS server name:")); newtGridSetField(entryArea, 0, 0, NEWT_GRID_COMPONENT, siteLabel, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); dirLabel = newtLabel(-1, -1, _("Mandrake directory:")); newtGridSetField(entryArea, 0, 1, NEWT_GRID_COMPONENT, dirLabel, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); cbInfo.server = newtEntry(-1, -1, cbInfo.serverVal, 24, &cbInfo.serverVal, NEWT_ENTRY_SCROLL); newtComponentAddCallback(cbInfo.server, nfsMountCallback, &cbInfo); cbInfo.netpath = newtEntry(-1, -1, cbInfo.netpathVal, 24, &cbInfo.netpathVal, NEWT_ENTRY_SCROLL); cbInfo.mntpoint = NULL; newtGridSetField(entryArea, 1, 0, NEWT_GRID_COMPONENT, cbInfo.server, 1, 0, 0, 0, 0, 0); newtGridSetField(entryArea, 1, 1, NEWT_GRID_COMPONENT, cbInfo.netpath, 1, 0, 0, 0, 0, 0); grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 0, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, entryArea, 0, 1, 0, 1, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX); newtGridWrappedWindow(grid, _("NFS Setup")); newtGridFree(grid, 1); newtFormAddComponents(form, text, cbInfo.server, cbInfo.netpath, okay, cancel, dirLabel, siteLabel, NULL); answer = newtRunForm(form); if (answer == cancel) { newtFormDestroy(form); newtPopWindow(); return INST_CANCEL; } if (*hostptr) free(*hostptr); if (*dirptr) free(*dirptr); *hostptr = strdup(cbInfo.serverVal); *dirptr = strdup(cbInfo.netpathVal); newtFormDestroy(form); newtPopWindow(); return 0; } static int cdromPrepare(struct installMethod * method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl) { char * cddev; int rc; if (!kickstart) rc = newtWinChoice(_("Note"), _("Ok"), ("Back"), _("Insert your Mandrake CD into your CD drive now")); if (rc == 2) return INST_CANCEL; while (1) { /* this autoprobes already, so we don't need to do anything special for the kickstart :-) */ rc = setupCDdevice(&cddev, dl); if (rc) return rc; if ((rc = loadFilesystem("isofs", "iso9660", dl))) return rc; rc = doMount(cddev, "/tmp/rhimage", "iso9660", 1, 0); if (rc) { removeCDmodule(dl); newtWinMessage(_("Error"), _("Ok"), _("I could not mount a CD on device /dev/%s"), cddev); return INST_CANCEL; } if (access("/tmp/rhimage/RedHat", R_OK)) { umount("/tmp/rhimage"); removeCDmodule(dl); newtWinMessage(_("Error"), _("Ok"), _("That CDROM device does " "not seem to contain a Mandrake CDROM.")); return INST_CANCEL; } break; } if (!access("/tmp/rhimage/RedHat/instimage/lib", X_OK)) { unlink("/tmp/rhimage/RedHat/instimage/lib"); symlink("/tmp/rhimage/RedHat/instimage/lib", "/lib"); } if (!access("/tmp/rhimage/RedHat/instimage/usr/bin", X_OK)) { unlink("/tmp/rhimage/RedHat/instimage/usr/bin"); symlink("/tmp/rhimage/RedHat/instimage/usr/bin", "/usr/bin"); } if (!access("/tmp/rhimage/RedHat/instimage/usr/etc", X_OK)) { unlink("/tmp/rhimage/RedHat/instimage/usr/etc"); symlink("/tmp/rhimage/RedHat/instimage/usr/etc", "/usr/etc"); } return 0; } static int nfsPrepare(struct installMethod * method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl) { char * host = NULL, * dir = NULL; char * buf; enum { NFS_STEP_NET, NFS_STEP_INFO, NFS_STEP_MOUNT, NFS_STEP_DONE } step = NFS_STEP_NET; int rc; int ksArgc; char ** ksArgv; poptContext optCon; int direction = 1; struct poptOption ksNfsOptions[] = { { "server", '\0', POPT_ARG_STRING, &host, 0 }, { "dir", '\0', POPT_ARG_STRING, &dir, 0 }, { 0, 0, 0, 0, 0 } }; if (kickstart) { /* FIXME: there must be a better test to use here */ if (!intf->set || !netc->set) if (bringUpNetworking(intf, netc, dl, 1)) return INST_ERROR; ksGetCommand(KS_CMD_NFS, NULL, &ksArgc, &ksArgv); optCon = poptGetContext(NULL, ksArgc, ksArgv, ksNfsOptions, 0); if ((rc = poptGetNextOpt(optCon)) < -1) { newtWinMessage(_("nfs command"), _("Ok"), _("bad argument to kickstart nfs command %s: %s"), poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); } if (!host || !dir) { newtWinMessage(_("nfs command"), _("Ok"), _("nfs command incomplete")); } else { step = NFS_STEP_MOUNT; } } while (step != NFS_STEP_DONE) { switch (step) { case NFS_STEP_NET: rc = bringUpNetworking(intf, netc, dl, direction); if (rc) return rc; direction = 1; step = NFS_STEP_INFO; break; case NFS_STEP_INFO: if (!host && (intf->set & INTFINFO_HAS_BOOTSERVER)) host = mygethostbyaddr(inet_ntoa(intf->bootServer)); if (!dir && (intf->set & INTFINFO_HAS_BOOTFILE)) dir = strdup(intf->bootFile); rc = nfsGetSetup(&host, &dir); if (rc == INST_CANCEL) { step = NFS_STEP_NET; direction = -1; } else if (rc == INST_ERROR) return INST_ERROR; else step = NFS_STEP_MOUNT; break; case NFS_STEP_MOUNT: if (!strlen(host) || !strlen(dir)) rc = INST_ERROR; else { buf = malloc(strlen(host) + strlen(dir) + 10); strcpy(buf, host); strcat(buf, ":"); strcat(buf, dir); if ((rc = loadFilesystem("nfs", "nfs", dl))) return rc; rc = doMount(buf, "/tmp/rhimage", "nfs", 1, 0); free(buf); } if (rc) { step = NFS_STEP_INFO; newtWinMessage(_("Error"), _("Ok"), _("I could not mount that directory from the server")); } else { if (access("/tmp/rhimage/RedHat", R_OK)) { step = NFS_STEP_INFO; newtWinMessage(_("Error"), _("Ok"), _("That directory does not seem to contain " "a Mandrake installation tree.")); umount("/tmp/rhimage"); } else step = NFS_STEP_DONE; } break; case NFS_STEP_DONE: break; } } if (!kickstart) { free(host); free(dir); } if (!access("/tmp/rhimage/RedHat/instimage/lib", X_OK)) { unlink("/tmp/rhimage/RedHat/instimage/lib"); symlink("/tmp/rhimage/RedHat/instimage/lib", "/lib"); } if (!access("/tmp/rhimage/RedHat/instimage/usr/bin", X_OK)) { unlink("/tmp/rhimage/RedHat/instimage/usr/bin"); symlink("/tmp/rhimage/RedHat/instimage/usr/bin", "/usr/bin"); } if (!access("/tmp/rhimage/RedHat/instimage/usr/etc", X_OK)) { unlink("/tmp/rhimage/RedHat/instimage/usr/etc"); symlink("/tmp/rhimage/RedHat/instimage/usr/etc", "/usr/etc"); } return 0; } int floppyRoot(struct installMethod * method, struct netInfo * netc, struct intfInfo * intf, struct driversLoaded ** dl) { int rc; do { rc = newtWinChoice(_("Supplemental Disk"), _("Ok"), _("Back"), _("This install method requires a second disk. Please remove " "the boot disk currently in your drive and replace it with " "the Mandrake Supplementary Install disk.")); if (rc == 2) return INST_CANCEL; rc = loadFloppyRoot(method); } while (rc); return 0; } int loadFloppyRoot(struct installMethod * method) { static int isMounted = 0; int rc; if (isMounted) return 0; if (!access("/usr/bin/runinstall2", R_OK)) { isMounted = 1; return 0; } if (testing) return 0; while (doMount("fd0", "/tmp/image", "ext2", 1, 0) || access("/tmp/image/usr/bin/runinstall2", R_OK)) { /* in case the mount succeeded */ umount("/tmp/image"); rc = newtWinChoice(_("Supplemental Disk"), _("Ok"), _("Cancel"), _("I failed to mount the floppy. Please insert the " "Mandrake Supplementary Install disk, or choose " "Cancel to pick a different installation process.")); if (rc == 2) return INST_CANCEL; } if (totalMemory() > 8000) { umount("/tmp/image"); loadRamdisk("ram2", "fd0", 1440, "Loading supplemental disk..."); if (doMount("ram2", "/tmp/image", "ext2", 1, 0)) { errorWindow("Error mounting ramdisk. This shouldn't " "happen, and I'm rebooting your system now."); exit(1); } } symlink("/tmp/image/lib", "/lib"); symlink("/tmp/image/etc", "/etc"); symlink("/tmp/image/usr/bin", "/usr/bin"); symlink("/tmp/image/usr/etc", "/usr/etc"); isMounted = 1; return 0; }