home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 1998 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 <alloca.h>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netinet/in.h> /* for ntohl */
- #include <popt.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mount.h>
- #include <sys/stat.h>
- #include <sys/sysmacros.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <zlib.h>
-
- #include "devices.h"
- #include "fs.h"
- #include "install.h"
- #include "otherinsmod.h"
- #include "intl.h"
- #include "kbd.h"
- #include "kickstart.h"
- #include "lang.h"
- #include "log.h"
- #include "methods.h"
- #include "net.h"
- #include "newt.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
- #define KS_FILE 3
-
- int testing = 0;
- int expert = 0;
- int kickstart = 0;
- int debug = 1;
- char * ksFile;
-
- /* hack */
- int rmmod_main(int argc, char ** argv);
-
- /* librpm.a provides this */
- int cpioInstallArchive(gzFile stream, void * mappings,
- int numMappings, void * cb, void * cbData,
- char ** failedFile);
-
- void welcome(void) {
- if (!testing && !kickstart) {
- newtWinMessage("Red Hat Linux", _("Ok"),
- _("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 mountFloppy() {
- if (!testing) {
- logMessage("mounting ext2 fs on floppy");
- doMount("fd0", "/tmp/bootdisk", "ext2", 1, 0);
- logMessage("floppy filesystem mounted on /tmp/bootdisk");
- }
- }
-
- 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 direction) {
- int rc;
- struct driversLoaded * dl = NULL;
- int status;
- char * probeOutput;
- static char pcic[20];
-
- /* just probe and if pcmcia controller exists we load support
- automatically */
- probeOutput = pcmciaProbeController();
- if (probeOutput == NULL) {
- if (direction < 0) return INST_CANCEL;
- return INST_OKAY;
- }
-
- logMessage("pcmcia probe returned: %s", probeOutput);
-
- if (strstr(probeOutput, "TCIC")) {
- strcpy(pcic, "tcic");
- } else
- strcpy(pcic, "i82365");
- logMessage("pcmcia pcic type: %s", pcic);
-
- /* go ahead and tell the rest of the install we found a
- PCMCIA controller */
- *arg = pcic;
-
- do {
- rc = newtWinTernary(_("PCMCIA Support"), _("Yes"), _("No"), _("Back"),
- _("Do you need to use PCMCIA devices during the "
- "install? Answer no to this question if only "
- "need PCMCIA support after the install. You do "
- "not need install-time PCMCIA support if you "
- "are installing Red Hat Linux on a laptop with "
- "a build-in CDROM drive."));
-
- if (rc == 2) return INST_OKAY;
- if (rc == 3) return INST_CANCEL;
-
- /* The parameters are just to make floppyRoot() fit as a prepareImage
- method */
- rc = floppyRoot(NULL, NULL, NULL, 0, NULL);
- } while (rc);
-
- winStatus(35, 3, "PCMCIA", _("Loading PCMCIA support..."));
-
- expandPcmciaArchive();
-
- newtPopWindow();
-
- 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);
-
- 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 <exit> 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 doKickstart(struct intfInfo * intf, struct netInfo * netc,
- struct driversLoaded ** dl) {
- char * file;
- char * ksPath;
- int rc;
-
- if (kickstart == KS_BOOTP) {
- if ((bringUpNetworking(intf, netc, dl, 1))) {
- kickstart = 0;
- } else if (!(intf->set & INTFINFO_HAS_BOOTSERVER)) {
- newtWinMessage(_("Kickstart Error"), _("Ok"), _("No kickstart "
- "configuration file server can be found."));
- kickstart = 0;
- } else {
- if (!(intf->set & INTFINFO_HAS_BOOTFILE)) {
- file = "/kickstart/";
- logMessage("bootp: no bootfile received");
- } else {
- file = intf->bootFile;
- }
-
- ksPath = malloc(strlen(file) + strlen(netc->hostname) + 70);
- strcpy(ksPath, inet_ntoa(intf->bootServer));
- strcat(ksPath, ":");
- strcat(ksPath, file);
-
- if (ksPath[strlen(ksPath) - 1] == '/') {
- ksPath[strlen(ksPath) - 1] = '\0';
- file = malloc(30);
- sprintf(file, "%s-kickstart", inet_ntoa(intf->ip));
- } else {
- file = strrchr(ksPath, '/');
- if (!file) {
- file = ksPath;
- ksPath = "/";
- } else {
- *file++ = '\0';
- }
- }
-
- logMessage("ks server: %s file: %s", ksPath, file);
-
- loadFilesystem("nfs", "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 = malloc(strlen(file) + 20);
- sprintf(ksFile, "/tmp/ks/%s", file);
-
- if (ksReadCommands(ksFile))
- kickstart = 0;
- }
- }
- }
-
- if (kickstart)
- chooseLanguage();
- }
-
- int main(int argc, char ** argv) {
- char ** argptr, * arg;
- struct installMethod * method;
- int rc;
- char * pcmciaArg = NULL;
- int isSerial;
- int force = 0;
- struct stat sb;
- char * childArgs[20];
- struct intfInfo intf;
- struct netInfo netc;
- struct driversLoaded * dl = NULL;
- char * ksMode = NULL;
- int stage, direction;
- char * keymap = NULL;
- poptContext optCon;
- int cont = 0;
- int forceSupp = 0;
- struct poptOption optionTable[] = {
- { "expert", '\0', POPT_ARG_NONE, &expert, 0 },
- { "force", '\0', POPT_ARG_NONE, &force, 0 },
- { "forcesupp", '\0', POPT_ARG_NONE, &forceSupp, 0 },
- { "kickstart", '\0', POPT_ARG_STRING, &ksMode, 0 },
- { "ks", '\0', POPT_ARG_STRING, &ksMode, 0 },
- { "test", '\0', POPT_ARG_NONE, &testing, 0 },
- { 0, 0, 0, 0, 0 }
- };
-
- if (!strcmp(argv[0] + strlen(argv[0]) - 6, "insmod")) {
- return ourInsmodCommand(argc, argv);
- } else if (!strcmp(argv[0] + strlen(argv[0]) - 5, "rmmod")) {
- return rmmod_main(argc, argv);
- } else if (!strcmp(argv[0], "install-continue")) {
- cont = 1;
- }
-
- 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 (testing) {
- kickstart = KS_FILE;
- ksFile = ksMode;
- } else 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(testing);
-
- /* 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 1;
- }
-
- if (!S_ISCHR(sb.st_mode)) {
- logMessage("stdin isn't a character device!!! ack!");
- return 1;
- }
-
- isSerial = (major(sb.st_rdev) == 4 && minor(sb.st_dev) >= 64) ||
- (major(sb.st_rdev) == 5 && minor(sb.st_dev) >= 64);
-
- logMessage("welcome to the Red Hat install "
- "(first stage, version " VERSION " built " __DATE__ " "
- __TIME__")");
-
- newtInit();
- newtCls();
- newtSetSuspendCallback(doSuspend);
- newtDrawRootText(0, 0, _("Welcome to Red Hat Linux"));
-
- newtPushHelpLine(_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen "));
-
- /* kickstart from floppy needs to be handled before PCMCIA */
- if (!cont && 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");
- }
- } else if (cont && kickstart == KS_FLOPPY) {
- /* continue install after language re-exec - all data was lost */
- ksFile = strdup("/tmp/ks.cfg");
-
- if (ksReadCommands(ksFile))
- kickstart = 0;
- } else if (kickstart == KS_FILE) {
- rc = 0;
- while (!rc) ;
- if (ksReadCommands(ksFile))
- kickstart = 0;
- }
-
- direction = 1;
- if (cont)
- stage = 1;
- else
- stage = 0;
-
- do {
- switch (stage) {
- case 0:
- if (!kickstart) {
- welcome();
- /* kickstart installs do this later */
- chooseLanguage();
- }
- newtFinished();
- argv[0] = "install-continue";
- execv(testing ? "./install" : "/sbin/install", argv);
- break;
-
- case 1:
- setDefaultLanguage(1);
- #if defined(__i386__) || defined(__alpha__)
- if (isSerial || kickstart) {
- direction = 1, stage++;
- break;
- }
- rc = setupKeyboard(&keymap);
- direction = (rc == INST_CANCEL) ? -1 : 1;
- #endif
- stage += direction;
- break;
-
- case 2:
- #if defined(__i386__)
- rc = setupPCMCIA(&pcmciaArg, direction);
- direction = (rc == INST_CANCEL) ? -1 : 1;
- #endif
- stage += direction;
- break;
-
- case 3:
- doKickstart(&intf, &netc, &dl);
- stage += direction;
- break;
-
- case 4:
- rc = chooseInstallMethod(forceSupp, &method, &netc, &intf, &dl);
- direction = (rc == INST_CANCEL) ? -1 : 1;
- stage += direction;
- break;
- }
- } while (stage < 5);
-
- logMessage("method selection completed");
-
- /* FIXME: is this a decent test? */
- if (intf.set) {
- 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";
- *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(testing);
- logMessage("error in exec of second stage loader :-(");
- logMessage("\terror:%s", strerror(rc));
-
- while (1) ;
-
- return 0;
- }
-