/* * install.c * * This is the first half of the install. It does just enough to get the * second half going. It, and everything it needs, has to fit on one floppy * along with a kernel and modules. Needless to say, it's a bit tight. * * Erik Troan (ewt@redhat.com) * * Copyright 1997 Red Hat Software * * This software may be freely redistributed under the terms of the GNU * 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 #include #include #include #include /* for ntohl */ #include #include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "fs.h" #include "install.h" #include "kbd.h" #include "kickstart.h" #include "log.h" #include "methods.h" #include "mono.h" #include "net.h" #include "newt.h" #include "perror.h" #include "run.h" #include "windows.h" #include "pcmcia-probing/pcmcia-probe.h" #define KS_NONE 0 #define KS_FLOPPY 1 #define KS_BOOTP 2 int testing = 0; int expert = 0; int kickstart = 0; int debug = 1; /* librpm.a provides this */ int cpioInstallArchive(gzFile stream, void * mappings, int numMappings, void * cb, void * cbData, char ** failedFile); char * welcomeText = "Welcome to Red Hat Linux!\n" "\n" "This installation process is outlined in detail in the Official Red " "Hat Linux Installation Guide available from Red Hat Software. If you have " "access to this manual, you should read the installation section before " "continuing.\n\n" "If you have purchased Official Red Hat Linux, be sure to register your " "purchase through our web site, http://www.redhat.com." ; void welcome(void) { if (!testing && !kickstart) newtWinMessage("Red Hat Linux", "Ok", welcomeText); } void mountFloppy() { if (!testing) { logMessage("mounting ext2 fs on floppy"); doMount("fd0", "/tmp/bootdisk", "ext2", 1, 0); logMessage("floppy filesystem mounted on /tmp/bootdisk"); } } #if 0 void showmtab(void) { char buf[5000]; int fd, i; fd = open("/proc/mounts", O_RDONLY); if (fd < 0) { newtWinMessage("Error", "Ok", perrorstr("open /proc/mounts")); return; } i = read(fd, buf, sizeof(buf) - 1); if (i < 1) { close(fd); newtWinMessage("Error", "Ok", perrorstr("read /proc/mounts")); return; } close(fd); buf[i] = '\0'; newtWinMessage("/proc/mounts", "Ok", buf); } #endif int expandPcmciaArchive() { gzFile stream; char * failedFile; int rc; stream = gzopen("/tmp/image/pcmcia.cgz", "r"); if (!stream) { logMessage("gzopen failed to read pcmcia.cgz: %s", strerror(errno)); return INST_ERROR; } rc = cpioInstallArchive(stream, NULL, 0, NULL, NULL, &failedFile); if (rc) { logMessage("cpio expansion failed on file %s, error %d\n", failedFile, rc); gzclose(stream); return INST_ERROR; } gzclose(stream); return 0; } #ifdef __i386__ int setupPCMCIA(char ** arg) { int rc; struct driversLoaded * dl = NULL; int status; char * probeOutput; static char pcic[20]; if (expert) { rc = newtWinChoice("PCMCIA support", "No", "Yes", "Do you need PCMCIA support?"); if (rc != 1) return 0; } /* just probe and if pcmcia controller exists we load support automatically */ probeOutput = pcmciaProbeController(); if (probeOutput == NULL) return 0; rc = loadFloppyRoot(NULL, "PCMCIA support requires a second disk. Please remove " "the boot disk currently in your drive and replace it with " "the Red Hat Supplementary Install disk."); if (rc) return 0; if (testing) { sleep(2); return 0; } winStatus(35, 3, "PCMCIA", "Loading PCMCIA support..."); chdir("/modules"); unlink("53c7,8xx.o.gz"); unlink("3c59x.o.gz"); unlink("cdrom.o.gz"); unlink("aztcd.o.gz"); unlink("cdu31a.o.gz"); unlink("cm206.o.gz"); unlink("de4x5.o.gz"); unlink("sbpcd.o.gz"); unlink("sjcd.o.gz"); unlink("sonycd535.o.gz"); unlink("optcd.o.gz"); unlink("gscd.o.gz"); unlink("aic7xxx.o.gz"); unlink("eata_dma.o.gz"); unlink("eata_pio.o.gz"); unlink("pas_16.o.gz"); unlink("ultrastor.o.gz"); unlink("u14-34f.o.gz"); unlink("g_NCR5380.o.gz"); unlink("mcd.o.gz"); unlink("mcdx.o.gz"); unlink("isp16.o.gz"); unlink("apricot.o.gz"); unlink("eexpress.o.gz"); unlink("eepro100.o.gz"); unlink("ncr53c8xx.o.gz"); chdir("/"); expandPcmciaArchive(); newtPopWindow(); logMessage("pcmcia probe returned: %s", probeOutput); if (strstr(probeOutput, "TCIC")) { strcpy(pcic, "tcic"); } else strcpy(pcic, "i82365"); logMessage("pcmcia pcic type: %s", pcic); winStatus(40, 3, "PCMCIA", "Starting PCMCIA services..."); loadModule("pcmcia_core", DRIVER_PCMCIA, DRIVER_MINOR_NONE, &dl); loadModule(pcic, DRIVER_PCMCIA, DRIVER_MINOR_NONE, &dl); loadModule("ds", DRIVER_PCMCIA, DRIVER_MINOR_NONE, &dl); *arg = pcic; if (!fork()) { if (!fork()) { execl("/sbin/cardmgr", "/sbin/cardmgr", NULL); exit(-1); } exit(-1); } wait(&status); /* if cardmgr a chance to get going */ sleep(5); newtPopWindow(); return 0; } #endif void doSuspend(void) { pid_t pid; int status; if (testing) { newtFinished(); exit(1); } else if (access("/bin/sh", X_OK)) { return; } newtSuspend(); if (!(pid = fork())) { printf("\n\nType to return to the install program.\n\n"); execl("/bin/sh", "-/bin/sh", NULL); perror("error execing /bin/sh"); sleep(5); exit(1); } waitpid(pid, &status, 0); newtResume(); } void main(int argc, char ** argv) { char ** argptr, * arg; struct installMethod * method; int rc; char * pcmciaArg = NULL; int isRescue = 0; int isSerial; int force = 0; struct stat sb; char * childArgs[20]; struct netInterface intf; struct netConfig netc; struct driversLoaded * dl = NULL; char * ksPath; char * file, * ksFile = NULL; char * server; char * ksMode = NULL; poptContext optCon; struct poptOption optionTable[] = { { "expert", '\0', POPT_ARG_NONE, &expert, 0 }, { "force", '\0', POPT_ARG_NONE, &force, 0 }, { "kickstart", '\0', POPT_ARG_STRING, &ksMode, 0 }, { "ks", '\0', POPT_ARG_STRING, &ksMode, 0 }, { "rescue", '\0', POPT_ARG_NONE, &isRescue, 0 }, { "test", '\0', POPT_ARG_NONE, &testing, 0 }, { 0, 0, 0, 0, 0 } }; memset(&intf, 0, sizeof(intf)); memset(&netc, 0, sizeof(netc)); optCon = poptGetContext(NULL, argc, argv, optionTable, 0); if ((rc = poptGetNextOpt(optCon)) < -1) { fprintf(stderr, "bad option %s: %s\n", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); exit(1); } if ((arg = poptGetArg(optCon))) { fprintf(stderr, "unexpected argument: %s\n", arg); exit(1); } if (ksMode) { if (!strcmp(ksMode, "floppy")) kickstart = KS_FLOPPY; else if (!strcmp(ksMode, "bootp")) kickstart = KS_BOOTP; else { fprintf(stderr, "unknown kickstart option %s\n", ksMode); exit(1); } } if (!testing && !force && (getpid() > 50)) { fprintf(stderr, "you're running me on a live system! that's "); fprintf(stderr, "incredibly stupid.\n"); exit(1); } openLog(); /* see if we're on a serial console -- if so, don't setup a keymap */ if (fstat(0, &sb)) { logMessage("error stat'ing stdin: %s", strerror(errno)); return; } if (!S_ISCHR(sb.st_mode)) { logMessage("stdin isn't a character device!!! ack!"); return; } isSerial = (major(sb.st_rdev) == 4 && minor(sb.st_dev) >= 64) || (major(sb.st_rdev) == 5 && minor(sb.st_dev) >= 64); if (!isRescue) logMessage("welcome to the Red Hat install " "(first stage, version " VERSION " built " __DATE__ " " __TIME__")"); if (!kickstart) setenv("NEWT_MONO", "1", 1); newtInit(); newtCls(); newtSetSuspendCallback(doSuspend); newtDrawRootText(0, 0, "Welcome to Red Hat Linux"); setColorState(); newtFinished(); newtInit(); newtCls(); newtDrawRootText(0, 0, "Welcome to Red Hat Linux"); if (!isRescue) welcome(); newtPushHelpLine(NULL); #ifndef __sparc__ /* kickstart installs do this later */ if (!isSerial && !kickstart) setupKeyboard(NULL); #endif /* kickstart from floppy needs to be handled before PCMCIA */ if (kickstart == KS_FLOPPY) { if (devMakeInode("fd0", "/tmp/fd0")) kickstart = 0; else if (doMount("/tmp/fd0", "/tmp/ks", "msdos", 1, 0)) { newtWinMessage("Error", "Ok", "I could not mount the boot floppy."); kickstart = 0; } else if (access("/tmp/ks/ks.cfg", R_OK)) { newtWinMessage("Error", "Ok", "Cannot find ks.cfg on boot floppy."); kickstart = 0; } else { int infd = -1, outfd = -1; char buf[4096]; int i; if ((outfd = open("/tmp/ks.cfg", O_CREAT | O_RDWR | 0666)) < 0 || (infd = open("/tmp/ks/ks.cfg", O_RDONLY)) < 0) { newtWinMessage("Error", "Ok", "Error opening files for " "kickstart copy: %s\n", strerror(errno)); kickstart = 0; } else { while ((i = read(infd, buf, sizeof(buf))) > 0) { if (write(outfd, buf, i) != i) break; } if (infd >= 0) close(infd); if (outfd >= 0) close(outfd); if (!i) { ksFile = alloca(30); strcpy(ksFile, "/tmp/ks.cfg"); if (ksReadCommands(ksFile)) kickstart = 0; } else { newtWinMessage("Error", "Ok", "Error copying kickstart file from floppy."); kickstart = 0; } } umount("/tmp/ks"); devRemoveInode("/tmp/fd0"); } } #ifdef __i386__ /* this blocks on kickstart installs, but there is nothing to be done about it */ do { rc = setupPCMCIA(&pcmciaArg); } while (rc); #endif if (isRescue) { do { rc = floppyRoot(NULL, &netc, &intf, &dl); } while (rc); } else if (kickstart == KS_BOOTP) { if ((bringUpNetworking(&intf, &netc, &dl))) { kickstart = 0; } else if (!(server = getenv("BOOTP_SERVER"))) { newtWinMessage("Kickstart Error", "Ok", "No kickstart " "configuration file server can be found."); kickstart = 0; } else { if (!(file = getenv("BOOTP_BOOTFILE")) || !strlen(file)) file = "/kickstartdir/"; ksPath = alloca(strlen(server) + strlen(file) + strlen(netc.hostname) + 50); strcpy(ksPath, server); strcat(ksPath, ":"); strcat(ksPath, file); if (ksPath[strlen(ksPath) - 1] == '/') { ksPath[strlen(ksPath) - 1] = '\0'; file = alloca(30); sprintf(file, "%d.%d.%d.%d-kickstart", (ntohl(intf.ip) & 0xFF000000) >> 24, (ntohl(intf.ip) & 0x00FF0000) >> 16, (ntohl(intf.ip) & 0x0000FF00) >> 8, (ntohl(intf.ip) & 0x000000FF) >> 0); } else { file = strrchr(ksPath, '/'); if (!file) { file = ksPath; ksPath = "/"; } else { *file++ = '\0'; } } logMessage("ks server: %s file: %s", ksPath, file); loadFilesystem("nfs", &dl); if ((rc = doMount(ksPath, "/tmp/ks", "nfs", 1, 0))) { newtWinMessage("Error", "Ok", "I could not mount the kickstart path %s.\n", ksPath); kickstart = 0; } else { ksFile = alloca(strlen(file) + 20); sprintf(ksFile, "/tmp/ks/%s", file); if (ksReadCommands(ksFile)) kickstart = 0; } } } if (!isRescue) while ((rc = chooseInstallMethod(&method, &netc, &intf, &dl))); logMessage("method selection completed"); if (intf.isConfigured) { writeNetInterfaceConfig("/tmp", &intf); writeNetConfig("/tmp", &netc, &intf, 1); } if (dl) writeModuleConf("/tmp", dl, 0); logMessage("state saved to /tmp"); newtFinished(); closeLog(); if (testing) exit(0); argptr = childArgs; *argptr++ = "/usr/bin/runinstall2"; if (isRescue) *argptr++ = "--rescue"; else { *argptr++ = "--method"; *argptr++ = method->abbrev; } if (expert) *argptr++ = "--expert"; if (pcmciaArg) { *argptr++ = "--pcmcia"; *argptr++ = pcmciaArg; } if (kickstart) { *argptr++ = "--ks"; *argptr++ = ksFile; } *argptr++ = NULL; execv(childArgs[0], childArgs); rc = errno; openLog(); logMessage("error in exec of second stage loader :-("); logMessage("\terror:%s", strerror(rc)); while (1) ; exit(0); }