summaryrefslogtreecommitdiffstats
path: root/loader2/loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'loader2/loader.c')
-rw-r--r--loader2/loader.c1157
1 files changed, 1157 insertions, 0 deletions
diff --git a/loader2/loader.c b/loader2/loader.c
new file mode 100644
index 000000000..fb8d6b08e
--- /dev/null
+++ b/loader2/loader.c
@@ -0,0 +1,1157 @@
+/*
+ * loader.c
+ *
+ * This is the installer loader. Its job is to somehow load the rest
+ * of the installer into memory and run it. This may require setting
+ * up some devices and networking, etc. The main point of this code is
+ * to stay SMALL! Remember that, live by that, and learn to like it.
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1997 - 2002 Red Hat, Inc.
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <popt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/fb.h>
+
+#include "loader.h"
+#include "loadermisc.h" /* JKFIXME: functions here should be split out */
+#include "log.h"
+#include "lang.h"
+#include "kbd.h"
+#include "windows.h"
+
+/* module stuff */
+#include "modules.h"
+#include "moduleinfo.h"
+#include "moduledeps.h"
+#include "modstubs.h"
+
+/* hardware stuff */
+#include "firewire.h"
+#include "pcmcia.h"
+#include "usb.h"
+
+/* install method stuff */
+#include "method.h"
+#include "cdinstall.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/probe.h"
+#include "../isys/stubs.h"
+
+/* maximum number of extra arguments that can be passed to the second stage */
+#define MAX_EXTRA_ARGS 128
+
+static int newtRunning = 0;
+
+
+/* JKFIXME: just temporarily here. need to move to header files for
+ * each install method */
+#ifdef INCLUDE_LOCAL
+char * mountCdromImage(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags);
+char * mountHardDrive(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags);
+#endif
+#ifdef INCLUDE_NETWORK
+char * mountNfsImage(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags);
+char * mountUrlImage(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags);
+#endif
+
+static struct installMethod installMethods[] = {
+#if defined(INCLUDE_LOCAL)
+ { N_("Local CDROM"), 0, CLASS_CDROM, mountCdromImage },
+#endif
+#if defined(INCLUDE_NETWORK)
+ { N_("NFS image"), 1, CLASS_NETWORK, mountNfsImage },
+ { "FTP", 1, CLASS_NETWORK, mountUrlImage },
+ { "HTTP", 1, CLASS_NETWORK, mountUrlImage },
+#endif
+#if 0
+#if defined(INCLUDE_LOCAL)
+ { N_("Hard drive"), 0, CLASS_HD, mountHardDrive },
+#endif
+#endif
+};
+static int numMethods = sizeof(installMethods) / sizeof(struct installMethod);
+
+/* JKFIXME: bad hack for second stage modules without module-info */
+struct moduleBallLocation * secondStageModuleLocation;
+
+
+int setupRamdisk(void) {
+ gzFile f;
+ static int done = 0;
+
+ if (done) return 0;
+
+ done = 1;
+
+ f = gunzip_open("/etc/ramfs.img");
+ if (f) {
+ char buf[10240];
+ int i, j = 0;
+ int fd;
+
+ fd = open(RAMDISK_DEVICE, O_RDWR);
+ logMessage("copying file to fd %d", fd);
+
+ while ((i = gunzip_read(f, buf, sizeof(buf))) > 0) {
+ j += write(fd, buf, i);
+ }
+
+ logMessage("wrote %d bytes", j);
+ close(fd);
+ gunzip_close(f);
+ }
+
+ if (doPwMount(RAMDISK_DEVICE, "/tmp/ramfs", "ext2", 0, 0, NULL, NULL))
+ logMessage("failed to mount ramfs image");
+
+ return 0;
+}
+
+
+void doSuspend(void) {
+ newtFinished();
+ exit(1);
+}
+
+void startNewt(int flags) {
+ if (!newtRunning) {
+ char *buf = sdupprintf(_("Welcome to %s"), PRODUCTNAME);
+ newtInit();
+ newtCls();
+ newtDrawRootText(0, 0, buf);
+ free(buf);
+
+ newtPushHelpLine(_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen "));
+
+ newtRunning = 1;
+ if (FL_TESTING(flags))
+ newtSetSuspendCallback((void *) doSuspend, NULL);
+ }
+}
+
+void stopNewt(void) {
+ if (newtRunning) newtFinished();
+ newtRunning = 0;
+}
+
+static void spawnShell(int flags) {
+ pid_t pid;
+ int fd;
+
+ if (FL_SERIAL(flags) || FL_NOSHELL(flags)) {
+ logMessage("not spawning a shell");
+ return;
+ }
+
+ fd = open("/dev/tty2", O_RDWR);
+ if (fd < 0) {
+ logMessage("cannot open /dev/tty2 -- no shell will be provided");
+ return;
+ } else if (access("/bin/sh", X_OK)) {
+ logMessage("cannot open shell - /bin/sh doesn't exist");
+ return;
+ }
+
+ if (!(pid = fork())) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL)) {
+ logMessage("could not set new controlling tty");
+ }
+
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTSTP, SIG_DFL);
+
+ setenv("LD_LIBRARY_PATH",
+ "/lib:/usr/lib:/usr/X11R6/lib:/mnt/usr/lib:"
+ "/mnt/sysimage/lib:/mnt/sysimage/usr/lib", 1);
+
+ execl("/bin/sh", "-/bin/sh", NULL);
+ logMessage("exec of /bin/sh failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ close(fd);
+
+ return;
+}
+
+void loadUpdates(struct knownDevices *kd, int flags) {
+ int done = 0;
+ int rc;
+
+ startNewt(flags);
+
+ do {
+ rc = newtWinChoice(_("Updates Disk"), _("OK"), _("Cancel"),
+ _("Insert your updates disk and press "
+ "\"OK\" to continue."));
+
+ if (rc == 2) return;
+
+ /* JKFIXME: handle updates from floppy or cd */
+ return;
+#if 0
+ logMessage("UPDATES floppy device is %s", floppyDevice);
+
+ devMakeInode(floppyDevice, "/tmp/floppy");
+ if (doPwMount("/tmp/floppy", "/tmp/update-disk", "ext2", 1, 0, NULL,
+ NULL)) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to mount floppy disk."));
+ } else {
+ /* Copy everything to /tmp/updates so .so files don't get run
+ from /dev/floppy. We could (and probably should) get smarter
+ about this at some point. */
+ winStatus(40, 3, _("Updates"), _("Reading anaconda updates..."));
+ if (!copyDirectory("/tmp/update-disk", "/tmp/updates")) done = 1;
+ newtPopWindow();
+ umount("/tmp/update-disk");
+ }
+#endif
+ } while (!done);
+
+ return;
+}
+
+static void checkForHardDrives(struct knownDevices * kd, int flags) {
+ int i;
+
+ for (i = 0; i < kd->numKnown; i++)
+ if (kd->known[i].class == CLASS_HD) break;
+
+ if (i != kd->numKnown)
+ return;
+
+ startNewt(flags);
+ i = newtWinChoice(_("Warning"), _("Yes"), _("No"),
+ _("No hard drives have been found. You probably need "
+ "to manually choose device drivers for the "
+ "installation to succeed. Would you like to "
+ "select drivers now?"));
+ if (i != 2) flags |= LOADER_FLAGS_ISA;
+
+ if (((access("/proc/bus/devices", R_OK) &&
+ access("/proc/openprom", R_OK) &&
+ access("/proc/iSeries", R_OK)) ||
+ FL_ISA(flags) || FL_NOPROBE(flags)) && !FL_KICKSTART(flags)) {
+ /* JKFIXME: do a manual device load */
+ }
+
+ return;
+}
+
+static int detectHardware(moduleInfoSet modInfo,
+ char *** modules, int flags) {
+ struct device ** devices, ** device;
+ char ** modList;
+ int numMods;
+ char *driver;
+
+ logMessage("probing buses");
+
+ devices = probeDevices(CLASS_UNSPEC,
+ BUS_PCI | BUS_SBUS,
+ PROBE_ALL);
+
+ logMessage("finished bus probing");
+
+ if (devices == NULL) {
+ *modules = NULL;
+ return LOADER_OK;
+ }
+
+ numMods = 0;
+ for (device = devices; *device; device++) numMods++;
+
+ if (!numMods) {
+ *modules = NULL;
+ return LOADER_OK;
+ }
+
+ modList = malloc(sizeof(*modList) * (numMods + 1));
+ numMods = 0;
+
+ for (device = devices; *device; device++) {
+ driver = (*device)->driver;
+ if (strcmp (driver, "ignore") && strcmp (driver, "unknown")
+ && strcmp (driver, "disabled")) {
+ modList[numMods++] = strdup(driver);
+ }
+
+ freeDevice (*device);
+ }
+
+ modList[numMods] = NULL;
+ *modules = modList;
+
+ free(devices);
+
+ return LOADER_OK;
+}
+
+static int agpgartInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ struct device ** devices, *p;
+ int i;
+
+ if (FL_TESTING(flags)) return 0;
+
+ logMessage("looking for video cards requiring agpgart module");
+
+ devices = probeDevices(CLASS_VIDEO, BUS_UNSPEC, PROBE_ALL);
+
+ if (!devices) {
+ logMessage("no video cards found");
+ return 0;
+ }
+
+ /* loop thru cards, see if we need agpgart */
+ for (i=0; devices[i]; i++) {
+ p = devices[i];
+ logMessage("found video card controller %s", p->driver);
+
+ /* HACK - need to have list of cards which match!! */
+ if (!strcmp(p->driver, "Card:Intel 810") ||
+ !strcmp(p->driver, "Card:Intel 815")) {
+ logMessage("found %s card requiring agpgart, loading module",
+ p->driver+5);
+
+ if (mlLoadModuleSetLocation("agpgart", modLoaded, modDeps,
+ modInfo, flags,
+ secondStageModuleLocation)) {
+ logMessage("failed to insert agpgart module");
+ return 1;
+ } else {
+ /* only load it once! */
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* This loads the necessary parallel port drivers for printers so that
+ kudzu can autodetect and setup printers in post install*/
+static void initializeParallelPort(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ /* JKFIXME: this can be used on other arches too... */
+#if !defined (__i386__)
+ return;
+#endif
+ if (FL_NOPARPORT(flags)) return;
+
+ logMessage("loading parallel port drivers...");
+ if (mlLoadModuleSetLocation("parport_pc", modLoaded, modDeps,
+ modInfo, flags,
+ secondStageModuleLocation)) {
+ logMessage("failed to load parport_pc module");
+ return;
+ }
+}
+
+int busProbe(moduleInfoSet modInfo, moduleList modLoaded, moduleDeps modDeps,
+ int justProbe, struct knownDevices * kd, int flags) {
+ int i;
+ char ** modList;
+ char modules[1024];
+
+ if (FL_NOPROBE(flags)) return 0;
+
+ if (!access("/proc/bus/pci/devices", R_OK) ||
+ !access("/proc/openprom", R_OK)) {
+ /* autodetect whatever we can */
+ if (detectHardware(modInfo, &modList, flags)) {
+ logMessage("failed to scan pci bus!");
+ return 0;
+ } else if (modList && justProbe) {
+ for (i = 0; modList[i]; i++)
+ printf("%s\n", modList[i]);
+ } else if (modList) {
+ *modules = '\0';
+
+ for (i = 0; modList[i]; i++) {
+ if (i) strcat(modules, ":");
+ strcat(modules, modList[i]);
+ }
+
+ mlLoadModuleSet(modules, modLoaded, modDeps, modInfo, flags);
+
+ kdFindScsiList(kd, 0);
+ kdFindNetList(kd, 0);
+ } else
+ logMessage("found nothing");
+ }
+
+ return 0;
+}
+
+
+
+/* JKFIXME: move all of this hardware setup stuff to a new file */
+static void scsiSetup(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags,
+ struct knownDevices * kd) {
+ mlLoadModuleSet("sd_mod:sr_mod", modLoaded, modDeps, modInfo, flags);
+}
+
+static void ideSetup(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags,
+ struct knownDevices * kd) {
+
+ /* This is fast enough that we don't need a screen to pop up */
+ mlLoadModuleSet("ide-cd", modLoaded, modDeps, modInfo, flags);
+
+ /* JKFIXME: I removed a kdFindIde() call here... it seems bogus */
+}
+
+
+
+/* parses /proc/cmdline for any arguments which are important to us.
+ * NOTE: in test mode, can specify a cmdline with --cmdline
+ */
+static int parseCmdLineFlags(int flags, char * cmdLine, char * extraArgs[]) {
+ int fd;
+ char buf[500];
+ int len;
+ char ** argv;
+ int argc;
+ int numExtraArgs = 0;
+ int i;
+
+ /* if we have any explicit cmdline (probably test mode), we don't want
+ * to parse /proc/cmdline */
+ if (!cmdLine) {
+ if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) return flags;
+ len = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (len <= 0) return flags;
+
+ buf[len] = '\0';
+ cmdLine = buf;
+ }
+
+ if (poptParseArgvString(cmdLine, &argc, (const char ***) &argv))
+ return flags;
+
+ for (i=0; i < argc; i++) {
+ if (!strcasecmp(argv[i], "expert"))
+ flags |= (LOADER_FLAGS_EXPERT | LOADER_FLAGS_MODDISK |
+ LOADER_FLAGS_ASKMETHOD);
+ else if (!strcasecmp(argv[i], "askmethod"))
+ flags |= LOADER_FLAGS_ASKMETHOD;
+ else if (!strcasecmp(argv[i], "noshell"))
+ flags |= LOADER_FLAGS_NOSHELL;
+ else if (!strcasecmp(argv[i], "mediacheck"))
+ flags |= LOADER_FLAGS_MEDIACHECK;
+ else if (!strcasecmp(argv[i], "nousbstorage"))
+ flags |= LOADER_FLAGS_NOUSBSTORAGE;
+ else if (!strcasecmp(argv[i], "nousb"))
+ flags |= LOADER_FLAGS_NOUSB;
+ else if (!strcasecmp(argv[i], "nofirewire"))
+ flags |= LOADER_FLAGS_NOIEEE1394;
+ else if (!strcasecmp(argv[i], "noprobe"))
+ flags |= LOADER_FLAGS_NOPROBE;
+ else if (!strcasecmp(argv[i], "nopcmcia"))
+ flags |= LOADER_FLAGS_NOPCMCIA;
+ else if (!strcasecmp(argv[i], "text"))
+ flags |= LOADER_FLAGS_TEXT;
+ else if (!strcasecmp(argv[i], "updates"))
+ flags |= LOADER_FLAGS_UPDATES;
+ else if (!strcasecmp(argv[i], "isa"))
+ flags |= LOADER_FLAGS_ISA;
+ else if (!strcasecmp(argv[i], "dd"))
+ flags |= LOADER_FLAGS_MODDISK;
+ else if (!strcasecmp(argv[i], "driverdisk"))
+ flags |= LOADER_FLAGS_MODDISK;
+ else if (!strcasecmp(argv[i], "rescue"))
+ flags |= LOADER_FLAGS_RESCUE;
+ else if (!strcasecmp(argv[i], "nopass"))
+ flags |= LOADER_FLAGS_NOPASS;
+ else if (!strcasecmp(argv[i], "serial"))
+ flags |= LOADER_FLAGS_SERIAL;
+ else if (!strncasecmp(argv[i], "debug=", 6))
+ setLogLevel(strtol(argv[i] + 6, (char **)NULL, 10));
+ /*JKFIXME: add back kickstart stuff */
+ else if (!strncasecmp(argv[i], "ksdevice=", 9))
+ /* JKFIXME: *ksDevice = argv[i] + 9; */
+ argv[i] + 9;
+ else if (!strncasecmp(argv[i], "display=", 8))
+ setenv("DISPLAY", argv[i] + 8, 1);
+ /* JKFIXME: handle lang= somehow */
+ else if (numExtraArgs < (MAX_EXTRA_ARGS - 1)) {
+ /* go through and append args we just want to pass on to */
+ /* the anaconda script, but don't want to represent as a */
+ /* LOADER_FLAG_XXX since loader doesn't care about these */
+ /* particular options. */
+ if (!strncasecmp(argv[i], "resolution=", 11) ||
+ !strncasecmp(argv[i], "lowres", 6) ||
+ !strncasecmp(argv[i], "skipddc", 7) ||
+ !strncasecmp(argv[i], "nomount", 7)) {
+ int arglen;
+
+ arglen = strlen(argv[i])+3;
+ extraArgs[numExtraArgs] = (char *) malloc(arglen*sizeof(char));
+ snprintf(extraArgs[numExtraArgs], arglen, "--%s", argv[i]);
+ numExtraArgs = numExtraArgs + 1;
+
+ if (numExtraArgs > (MAX_EXTRA_ARGS - 2)) {
+ logMessage("Too many command line arguments (128), "
+ "rest will be dropped.");
+ }
+ }
+ }
+ }
+
+ /* NULL terminates the array of extra args */
+ extraArgs[numExtraArgs] = NULL;
+
+ return flags;
+}
+
+
+/* determine if we are using a framebuffer console. return 1 if so */
+static int checkFrameBuffer() {
+ int fd;
+ int rc = 0;
+ struct fb_fix_screeninfo fix;
+
+ if ((fd = open("/dev/fb0", O_RDONLY)) == -1) {
+ return 0;
+ }
+
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) >= 0) {
+ rc = 1;
+ }
+ close(fd);
+ return rc;
+}
+
+/* look for available memory. note: won't ever report more than the
+ * 900 megs or so supported by the -BOOT kernel due to not using e820 */
+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';
+
+ 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;
+}
+
+/* make sure they have enough ram */
+static void checkForRam(int flags) {
+ if (totalMemory() < MIN_RAM) {
+ char *buf;
+ buf = sdupprintf(_("You do not have enough RAM to install %s "
+ "on this machine."), PRODUCTNAME);
+ startNewt(flags);
+ newtWinMessage(_("Error"), _("OK"), buf);
+ free(buf);
+ stopNewt();
+ exit(0);
+ }
+}
+
+/* fsm for the basics of the loader. */
+static char *doLoaderMain(char * location,
+ struct knownDevices * kd,
+ moduleInfoSet modInfo,
+ moduleList modLoaded,
+ moduleDeps modDeps,
+ int flags) {
+ enum { STEP_LANG, STEP_KBD, STEP_METHOD, STEP_DRIVER,
+ STEP_URL, STEP_DONE } step;
+ char * url = NULL;
+ int dir = 1;
+ int rc, i;
+
+ char * installNames[10]; /* 10 install methods will be enough for anyone */
+ int numValidMethods = 0;
+ int validMethods[10];
+ int methodNum;
+
+ char *lang = NULL;
+ char * keymap = NULL;
+ char * kbdtype = NULL;
+
+ /* JKFIXME: if this were the old code, we'd do checking about local
+ * vs network install methods here. do we still want to do that or
+ * just nuke that code? */
+ for (i = 0; i < numMethods; i++) {
+ installNames[numValidMethods] = _(installMethods[i].name);
+ validMethods[numValidMethods++] = i;
+ }
+
+ installNames[numValidMethods] = NULL;
+
+ /* check to see if we have a Red Hat Linux CD. If we have one, then
+ * we can fast-path the CD and not make people answer questions in
+ * text mode. */
+ /* JKFIXME: what should we do about rescue mode here? */
+ if (!FL_ASKMETHOD(flags) && !FL_KICKSTART(flags)) {
+ /* JKFIXME: this might not work right... */
+ url = findRedHatCD(location, kd, modInfo, modLoaded, modDeps, flags);
+ if (url) return url;
+ }
+
+ startNewt(flags);
+
+ step = STEP_LANG;
+
+ while (step != STEP_DONE) {
+ switch(step) {
+ case STEP_LANG:
+ chooseLanguage(&lang, flags);
+ /* JKFIXME: default lang stuff so that we only sometimes pass lang? */
+ step = STEP_KBD;
+ dir = 1;
+ break;
+ case STEP_KBD:
+ rc = chooseKeyboard(&keymap, &kbdtype, flags);
+ if (rc == LOADER_NOOP) {
+ if (dir == -1)
+ step = STEP_LANG;
+ else
+ step = STEP_METHOD;
+ break;
+ }
+
+ if (rc == LOADER_BACK) {
+ step = STEP_LANG;
+ dir = -1;
+ } else {
+ step = STEP_METHOD;
+ dir = 1;
+ }
+
+ break;
+
+ case STEP_METHOD:
+ rc = newtWinMenu(FL_RESCUE(flags) ? _("Rescue Method") :
+ _("Installation Method"),
+ FL_RESCUE(flags) ?
+ _("What type of media contains the rescue "
+ "image?") :
+ _("What type of media contains the packages to "
+ "be installed?"),
+ 30, 10, 20, 6, installNames, &methodNum,
+ _("OK"), _("Back"), NULL);
+ if (rc && rc != 1) {
+ step = STEP_KBD;
+ dir = -1;
+ } else {
+ step = STEP_DRIVER;
+ dir = 1;
+ }
+ break;
+
+ case STEP_DRIVER: {
+ int found = 0;
+
+ /* JKFIXME: this is the nifty cool new step */
+ for (i = 0; i < kd->numKnown; i++) {
+ if (installMethods[validMethods[methodNum]].deviceType ==
+ kd->known[i].class)
+ found = 1;
+ }
+
+ if (found) {
+ step = STEP_URL;
+ dir = 1;
+ break;
+ }
+
+ /* JKFIXME: pop up driver stuff */
+ logMessage("would have gone to ask about a driver... but the code's not written, so falling back ;-)");
+ step = STEP_METHOD;
+ dir = -1;
+ break;
+ }
+
+ case STEP_URL:
+ logMessage("starting to STEP_URL");
+ url = installMethods[validMethods[methodNum]].mountImage(
+ installMethods + validMethods[methodNum],
+ location, kd, modInfo, modLoaded,
+ &modDeps, flags);
+ logMessage("got url %s", url);
+ if (!url) {
+ step = STEP_METHOD;
+ dir = -1;
+ } else {
+ step = STEP_DONE;
+ dir = 1;
+ }
+ break;
+
+
+ default:
+ break;
+ }
+ }
+
+ return url;
+}
+
+int main(int argc, char ** argv) {
+ int flags = 0;
+ int haveKon = 0; /* JKFIXME: this should be conditionalized... */
+ struct stat sb;
+ int rc, i;
+ char * arg;
+
+ char twelve = 12;
+ char * extraArgs[MAX_EXTRA_ARGS];
+
+ struct knownDevices kd;
+ moduleInfoSet modInfo;
+ moduleList modLoaded;
+ moduleDeps modDeps;
+
+ char *url = NULL;
+
+ char ** argptr, ** tmparg;
+ char * anacondaArgs[50];
+ int useRHupdates = 0;
+
+ char * cmdLine = NULL;
+ char * ksFile = NULL;
+ int testing = 0;
+ int probeOnly; /* JKFIXME: this option can probably die */
+ int mediacheck = 0;
+ poptContext optCon;
+ struct poptOption optionTable[] = {
+ { "cmdline", '\0', POPT_ARG_STRING, &cmdLine, 0 },
+ { "ksfile", '\0', POPT_ARG_STRING, &ksFile, 0 },
+ { "probe", '\0', POPT_ARG_NONE, &probeOnly, 0 },
+ { "test", '\0', POPT_ARG_NONE, &testing, 0 },
+ { "mediacheck", '\0', POPT_ARG_NONE, &mediacheck, 0},
+ { 0, 0, 0, 0, 0 }
+ };
+
+
+ /* JKFIXME: very very bad hack */
+ secondStageModuleLocation = malloc(sizeof(struct moduleBallLocation));
+ secondStageModuleLocation->path = strdup("/mnt/runtime/modules/modules.cgz");
+
+
+
+ /* JKFIXME: need to do multiplex command stuff for insmod, etc here */
+ if (!strcmp(argv[0] + strlen(argv[0]) - 6, "insmod"))
+ return ourInsmodCommand(argc, argv);
+ if (!strcmp(argv[0] + strlen(argv[0]) - 8, "modprobe"))
+ return ourInsmodCommand(argc, argv);
+ if (!strcmp(argv[0] + strlen(argv[0]) - 5, "rmmod"))
+ return combined_insmod_main(argc, argv);
+
+ /* The fstat checks disallows serial console if we're running through
+ a pty. This is handy for Japanese. */
+ fstat(0, &sb);
+ if (major(sb.st_rdev) != 3 && major(sb.st_rdev) != 136) {
+ if (ioctl (0, TIOCLINUX, &twelve) < 0)
+ flags |= LOADER_FLAGS_SERIAL;
+ }
+
+
+ if (!(FL_TESTING(flags))) {
+ int fd;
+
+ fd = open("/tmp/modules.conf", O_WRONLY | O_CREAT, 0666);
+ if (fd < 0) {
+ logMessage("error creating /tmp/modules.conf: %s\n",
+ strerror(errno));
+ } else {
+ /* HACK */
+#ifdef __sparc__
+ write(fd, "alias parport_lowlevel parport_ax\n", 34);
+#else
+ write(fd, "alias parport_lowlevel parport_pc\n", 34);
+#endif
+ close(fd);
+ }
+ }
+
+
+ optCon = poptGetContext(NULL, argc, (const char **) 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 = (char *) poptGetArg(optCon))) {
+ fprintf(stderr, "unexpected argument: %s\n", arg);
+ exit(1);
+ }
+
+ if (testing) flags |= LOADER_FLAGS_TESTING;
+ if (mediacheck) flags |= LOADER_FLAGS_MEDIACHECK;
+
+ if (checkFrameBuffer() == 1) haveKon = 0;
+
+ /* JKFIXME: I do NOT like this... it also looks kind of bogus */
+#if defined(__s390__) && !defined(__s390x__)
+ flags |= LOADER_FLAGS_NOSHELL | LOADER_FLAGS_NOUSB;
+#endif
+
+ openLog(FL_TESTING(flags));
+ if (!FL_TESTING(flags))
+ openlog("loader", 0, LOG_LOCAL0);
+
+ extraArgs[0] = NULL;
+ flags = parseCmdLineFlags(flags, cmdLine, extraArgs);
+
+ if (FL_SERIAL(flags) && !getenv("DISPLAY"))
+ flags |= LOADER_FLAGS_TEXT;
+
+ checkForRam(flags);
+
+ arg = FL_TESTING(flags) ? "./module-info" : "/modules/module-info";
+ modInfo = newModuleInfoSet();
+
+ if (readModuleInfo(arg, modInfo, NULL, 0)) {
+ fprintf(stderr, "failed to read %s\n", arg);
+ sleep(5);
+ exit(1);
+ }
+
+ kd = kdInit();
+ mlReadLoadedList(&modLoaded);
+ modDeps = mlNewDeps();
+ mlLoadDeps(&modDeps, "/modules/modules.dep");
+
+ mlLoadModuleSet("cramfs:vfat:nfs:loop", modLoaded, modDeps,
+ modInfo, flags);
+
+ /* now let's do some initial hardware-type setup */
+ ideSetup(modLoaded, modDeps, modInfo, flags, &kd);
+ scsiSetup(modLoaded, modDeps, modInfo, flags, &kd);
+
+ /* Note we *always* do this. If you could avoid this you could get
+ a system w/o USB keyboard support, which would be bad. */
+ usbInitialize(modLoaded, modDeps, modInfo, flags);
+
+ /* now let's initialize any possible firewire. fun */
+ firewireInitialize(modLoaded, modDeps, modInfo, flags);
+
+ /* JKFIXME: this is where we used to setFloppyDevice and do KS_FLOPPY */
+
+ /* JKFIXME: this is kind of a different way to handle pcmcia... I think
+ * it's more correct, although it will require a little bit of kudzu
+ * hacking */
+ pcmciaInitialize(modLoaded, modDeps, modInfo, flags);
+
+ kdFindIdeList(&kd, 0);
+ kdFindScsiList(&kd, 0);
+ kdFindNetList(&kd, 0);
+
+ /* explicitly read this to let libkudzu know we want to merge
+ * in future tables rather than replace the initial one */
+ pciReadDrivers("/modules/pcitable");
+
+ if ((access("/proc/bus/pci/devices", R_OK) &&
+ access("/proc/openprom", R_OK) &&
+ access("/proc/iSeries", R_OK)) || FL_MODDISK(flags)) {
+ startNewt(flags);
+ /* JKFIXME: do the driver disk thing here for an isa machine. bah. */
+ }
+
+ busProbe(modInfo, modLoaded, modDeps, probeOnly, &kd, flags);
+
+ /* JKFIXME: all sorts of crap to handle kickstart sources now... */
+
+ /* JKFIXME: telnetd */
+
+ url = doLoaderMain("/mnt/source", &kd, modInfo, modLoaded, modDeps, flags);
+
+ if (!FL_TESTING(flags)) {
+ unlink("/usr");
+ symlink("/mnt/runtime/usr", "/usr");
+ unlink("/lib");
+ symlink("/mnt/runtime/lib", "/lib");
+ if (!access("/mnt/runtime/lib64", X_OK)) {
+ unlink("/lib64");
+ symlink("/mnt/runtime/lib64", "/lib64");
+ }
+
+ /* JKFIXME: need to pull in the second stage modules and use
+ * them to update module-info, pcitable, etc just like with
+ * driver disks */
+ }
+
+ logMessage("getting ready to spawn shell now");
+
+ spawnShell(flags); /* we can attach gdb now :-) */
+
+ /* setup the second stage modules; don't over-ride any already existing
+ * modules because that would be rude
+ */
+ {
+ mlLoadDeps(&modDeps, "/mnt/runtime/modules/modules.dep");
+ pciReadDrivers("/modules/pcitable");
+ readModuleInfo("/mnt/runtime/modules/module-info", modInfo,
+ secondStageModuleLocation, 0);
+ }
+
+ /* JKFIXME: kickstart devices crap... probably kind of bogus now though */
+
+
+ /* we might have already loaded these, but trying again doesn't hurt */
+ ideSetup(modLoaded, modDeps, modInfo, flags, &kd);
+ scsiSetup(modLoaded, modDeps, modInfo, flags, &kd);
+ busProbe(modInfo, modLoaded, modDeps, 0, &kd, flags);
+
+ checkForHardDrives(&kd, flags);
+
+ if (FL_UPDATES(flags))
+ loadUpdates(&kd, flags);
+
+ /* look for cards which require the agpgart module */
+ agpgartInitialize(modLoaded, modDeps, modInfo, flags);
+
+ mlLoadModuleSetLocation("raid0:raid1:raid5:msdos:ext3:reiserfs:jfs:xfs:lvm-mod",
+ modLoaded, modDeps, modInfo, flags,
+ secondStageModuleLocation);
+
+ initializeParallelPort(modLoaded, modDeps, modInfo, flags);
+
+ usbInitializeMouse(modLoaded, modDeps, modInfo, flags);
+
+ /* we only want to use RHupdates on nfs installs. otherwise, we'll
+ * use files on the first iso image and not be able to umount it */
+ if (!strncmp(url, "nfs:", 4)) {
+ logMessage("NFS install method detected, will use RHupdates/");
+ useRHupdates = 1;
+ } else {
+ useRHupdates = 0;
+ }
+
+ if (useRHupdates)
+ setenv("PYTHONPATH", "/tmp/updates:/mnt/source/RHupdates", 1);
+ else
+ setenv("PYTHONPATH", "/tmp/updates", 1);
+
+ argptr = anacondaArgs;
+
+ if (!access("/tmp/updates/anaconda", X_OK))
+ *argptr++ = "/tmp/updates/anaconda";
+ else if (useRHupdates && !access("/mnt/source/RHupdates/anaconda", X_OK))
+ *argptr++ = "/mnt/source/RHupdates/anaconda";
+ else
+ *argptr++ = "/usr/bin/anaconda";
+
+ logMessage("Running anaconda script %s", *(argptr-1));
+
+ *argptr++ = "-m";
+ if (strncmp(url, "ftp:", 4)) {
+ *argptr++ = url;
+ } else {
+ int fd;
+
+ fd = open("/tmp/method", O_CREAT | O_TRUNC | O_RDWR, 0600);
+ write(fd, url, strlen(url));
+ write(fd, "\r", 1);
+ close(fd);
+ *argptr++ = "@/tmp/method";
+ }
+
+ /* add extra args - this potentially munges extraArgs */
+ tmparg = extraArgs;
+ while (*tmparg) {
+ char *idx;
+
+ logMessage("adding extraArg %s", *tmparg);
+ idx = strchr(*tmparg, '=');
+ if (idx && ((idx-*tmparg) < strlen(*tmparg))) {
+ *idx = '\0';
+ *argptr++ = *tmparg;
+ *argptr++ = idx+1;
+ } else {
+ *argptr++ = *tmparg;
+ }
+
+ tmparg++;
+ }
+
+ if (FL_RESCUE(flags)) {
+ startNewt(flags);
+
+ /* JKFIXME: this seems broken... we should just ask these questions
+ * earlier for rescue mode and do the fast path check later */
+#if 0
+ if (!lang) {
+ int rc;
+
+ do {
+ chooseLanguage(&lang, flags);
+ defaultLang = 0;
+ rc = chooseKeyboard (&keymap, &kbdtype, flags);
+ } while ((rc) && (rc != LOADER_NOOP));
+ }
+#endif
+ *argptr++ = "--rescue";
+ } else {
+ if (FL_SERIAL(flags))
+ *argptr++ = "--serial";
+ if (FL_TEXT(flags))
+ *argptr++ = "-T";
+ if (FL_EXPERT(flags))
+ *argptr++ = "--expert";
+
+ if (FL_KICKSTART(flags)) {
+ *argptr++ = "--kickstart";
+ *argptr++ = ksFile;
+ }
+
+ /* JKFIXME: obviously this needs to come back... */
+#if 0
+ if (!lang)
+ lang = getenv ("LC_ALL");
+
+ if (lang && !defaultLang && !FL_NOPASS(flags)) {
+ *argptr++ = "--lang";
+ *argptr++ = lang;
+ }
+
+ if (keymap && !FL_NOPASS(flags)) {
+ *argptr++ = "--keymap";
+ *argptr++ = keymap;
+ }
+
+ if (kbdtype && !FL_NOPASS(flags)) {
+ *argptr++ = "--kbdtype";
+ *argptr++ = kbdtype;
+ }
+#endif
+
+ for (i = 0; i < modLoaded->numModules; i++) {
+ struct moduleInfo * mi;
+ char * where;
+
+ if (!modLoaded->mods[i].path) continue;
+
+ mi = findModuleInfo(modInfo, modLoaded->mods[i].name);
+ if (!mi) continue;
+ if (mi->major == DRIVER_NET)
+ where = "net";
+ else if (mi->major == DRIVER_SCSI)
+ where = "scsi";
+ else
+ continue;
+
+ *argptr++ = "--module";
+ *argptr = alloca(80);
+ sprintf(*argptr, "%s:%s:%s", modLoaded->mods[i].path, where,
+ modLoaded->mods[i].name);
+
+ argptr++;
+ }
+ }
+
+ *argptr = NULL;
+
+ stopNewt();
+ closeLog();
+
+ if (!FL_TESTING(flags)) {
+ char *buf = sdupprintf(_("Running anaconda, the %s system installer - please wait...\n"), PRODUCTNAME);
+ printf("%s", buf);
+ execv(anacondaArgs[0], anacondaArgs);
+ perror("exec");
+ }
+
+ return 1;
+}