summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--loader2/Makefile120
-rw-r--r--loader2/cdinstall.c137
-rw-r--r--loader2/cdinstall.h14
-rw-r--r--loader2/dietstubs.c166
-rw-r--r--loader2/driverdisk.c32
-rw-r--r--loader2/firewire.c87
-rw-r--r--loader2/firewire.h7
-rw-r--r--loader2/ftp.c525
-rw-r--r--loader2/ftp.h25
-rw-r--r--loader2/init.c833
-rw-r--r--loader2/kbd.c194
-rw-r--r--loader2/kbd.h6
-rw-r--r--loader2/lang.c328
-rw-r--r--loader2/lang.h18
-rw-r--r--loader2/loader.c1157
-rw-r--r--loader2/loader.h77
-rw-r--r--loader2/loadermisc.c116
-rw-r--r--loader2/loadermisc.h12
-rw-r--r--loader2/log.c98
-rw-r--r--loader2/log.h14
-rw-r--r--loader2/method.c359
-rw-r--r--loader2/method.h32
-rw-r--r--loader2/mkctype.c57
-rw-r--r--loader2/modstubs.c160
-rw-r--r--loader2/modstubs.h8
-rw-r--r--loader2/moduledeps.c133
-rw-r--r--loader2/moduledeps.h15
-rw-r--r--loader2/moduleinfo.c254
-rw-r--r--loader2/moduleinfo.h51
-rw-r--r--loader2/modules.c595
-rw-r--r--loader2/modules.h43
-rw-r--r--loader2/net.c704
-rw-r--r--loader2/net.h27
-rw-r--r--loader2/nfsinstall.c209
-rw-r--r--loader2/otherinsmod.c161
-rw-r--r--loader2/pcmcia.c29
-rw-r--r--loader2/pcmcia.h7
-rw-r--r--loader2/urlinstall.c255
-rw-r--r--loader2/urls.c417
-rw-r--r--loader2/urls.h26
-rw-r--r--loader2/usb.c129
-rw-r--r--loader2/usb.h9
-rw-r--r--loader2/windows.c66
-rw-r--r--loader2/windows.h12
44 files changed, 7724 insertions, 0 deletions
diff --git a/loader2/Makefile b/loader2/Makefile
new file mode 100644
index 000000000..3c8fa3192
--- /dev/null
+++ b/loader2/Makefile
@@ -0,0 +1,120 @@
+include ../Makefile.inc
+
+# JKFIXME: this should go somewhere common. I need to know about diet in
+# a few locations. and we should really just always use diet
+# should we use diet on this arch?
+ifeq (i386, $(ARCH))
+USEDIET=1
+endif
+ifeq (ppc, $(ARCH))
+USEDIET=1
+endif
+
+# JKFIXME: switch to use system libslang and libnewt with msw's wcwidth()
+SLANGLIB = ../minislang/libslang.a
+NEWTLIB = ../mininewt/libnewt.a
+ISYSLIB = ../isys/libisys.a
+GUNZIP = -lz
+MODULELINKAGE :=-lmodutils -lmodutilutil -lmodutilobj
+
+BINS = init
+
+HWOBJS = pcmcia.o usb.o firewire.o
+METHOBJS = method.o cdinstall.o nfsinstall.o urlinstall.o
+OBJS = log.o moduleinfo.o loadermisc.o modules.o moduledeps.o windows.o \
+ lang.o kbd.o modules.o modstubs.o \
+ $(HWOBJS) $(METHOBJS)
+LOADEROBJS = loader.o loader-pcmcia.o
+NETOBJS = net.o urls.o telnet.o telnetd.o
+NETOBJS = net.o urls.o ftp.o
+PCMCIAOBJS = pcmcia.o $(NETOBJS)
+SOURCES = $(subst .o,.c,$(OBJS)) loader.c
+
+HWLIBS = -lkudzu_loader -lpci
+
+DEBUG = -ggdb
+COPTS = $(DEBUG) -Wall -DVERSION='"$(VERSION)"'
+CFLAGS = $(COPTS) -Os -ffunction-sections -D_GNU_SOURCE=1 -D_FILE_OFFSET_BITS=64 -DHAVE_LIBIO_H -DPRODUCTNAME='$(PRODUCTNAME)'
+STATIC = -static
+
+
+ifeq (1, $(USEDIET))
+CFLAGS += -DGZLIB=1
+DIET=diet
+REALCC=gcc
+CC=$(DIET) $(REALCC)
+# JKFIXME: this also goes away when we go to system {newt,slang}
+SLANGLIB = ../minislang/libslang-diet.a
+NEWTLIB = ../mininewt/libnewt-diet.a
+ISYSLIB = ../isys/libisys-diet.a
+GUNZIP = ../isys/gzlib/libgunzip-diet.a
+endif
+
+ifeq (i386, $(ARCH))
+BINS += loader
+OBJS += dietstubs.o ctype.o
+COPTS += -DUSE_LOGDEV
+ISYSLIB += -lrpc
+endif
+
+all: $(BINS)
+
+init: init.o
+ $(CC) $(STATIC) $(COPTS) $(LDFLAGS) -o $@ init.o
+
+init.o: init.c
+ $(CC) $(COPTS) -c -o init.o init.c
+
+mkctype: mkctype.c
+ $(REALCC) $(COPTS) -o mkctype mkctype.c
+
+ctype.c: mkctype
+ ./mkctype > ctype.c
+
+loader.o: loader.c
+ $(CC) -DINCLUDE_LOCAL -DINCLUDE_NETWORK $(CFLAGS) -o $@ -c $<
+
+loader-local.o: loader.c
+ $(CC) -DINCLUDE_LOCAL $(CFLAGS) -o $@ -c $<
+
+loader-net.o: loader.c
+ $(CC) -DINCLUDE_NETWORK $(CFLAGS) -o $@ -c $<
+
+loader-pcmcia.o: loader.c
+ $(CC) -DINCLUDE_PCMCIA -DINCLUDE_LOCAL -DINCLUDE_NETWORK \
+ $(CFLAGS) -o $@ -c $<
+
+loader: loader.o $(OBJS) $(NETOBJS)
+ $(CC) -g $(STATIC) -o $@ $^ -lpopt \
+ $(HWLIBS) $(ISYSLIB) \
+ $(MODULELINKAGE) $(GUNZIP) \
+ -lpump $(NEWTLIB) $(SLANGLIB) $(KONOBJS)
+
+loader-local: loader-local.o $(OBJS)
+ $(CC) -g $(STATIC) -o $@ $^ -lpopt \
+ $(HWLIBS) $(ISYSLIB) \
+ $(MODULELINKAGE) $(GUNZIP) \
+ -L ../stubs $(NEWTLIB) $(SLANGLIB) $(KONOBJS)
+
+loader-network: loader-net.o $(OBJS) $(NETOBJS)
+ $(CC) -g $(STATIC) -o $@ $^ -lpopt \
+ $(HWLIBS) $(ISYSLIB) \
+ $(MODULELINKAGE) $(GUNZIP) \
+ -lpump -L ../stubs $(NEWTLIB) $(SLANGLIB) $(KONOBJS)
+
+loader-pcmcia: loader-pcmcia.o pcmcia.o popen.o $(OBJS) $(PCMCIAOBJS)
+ $(CC) -g $(STATIC) -o $@ loader-pcmcia.o $(OBJS) \
+ $(PCMCIAOBJS) -lcardmgr_loader -lprobe_loader popen.o \
+ -lpopt \
+ $(HWLIBS) $(ISYSLIB) \
+ $(MODULELINKAGE) $(GUNZIP) \
+ -lpump -lresolv $(NEWTLIB) $(SLANGLIB) $(KONOBJS)
+
+
+
+clean:
+ rm -f *.o *~ .depend init ctype.c mkctype \
+ loader loader-pcmcia loader-local loader-network
+
+depend:
+ $(CPP) $(CFLAGS) -DHAVE_CONFIG_H -M $(SOURCES) > .depend
diff --git a/loader2/cdinstall.c b/loader2/cdinstall.c
new file mode 100644
index 000000000..8271e5bfc
--- /dev/null
+++ b/loader2/cdinstall.c
@@ -0,0 +1,137 @@
+/*
+ * cdinstall.c - code to set up cdrom installs
+ *
+ * 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 <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "log.h"
+#include "lang.h"
+#include "modules.h"
+#include "method.h"
+#include "cdinstall.h"
+
+#include "../isys/probe.h"
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+
+/* JKFIXME: this needs implementing. can probably just be copied from
+ * queryMediaCheck() in loader/loader.c. although it will need splitting
+ * out a little bit of setupCdrom into its own function */
+static void queryCDMediaCheck(char * dev, int flags) {
+ return;
+}
+
+/* set up a cdrom, nominally for installation
+ *
+ * location: where to mount the cdrom at JKFIXME: ignored
+ * flags: usual loader flags
+ * interactive: whether or not to prompt about questions/errors (1 is yes)
+ *
+ * side effect: found cdrom is mounted as /mnt/source. stage2 mounted
+ * as /mnt/runtime.
+ */
+char * setupCdrom(char * location,
+ struct knownDevices * kd,
+ moduleInfoSet modInfo,
+ moduleList modLoaded,
+ moduleDeps modDeps,
+ int flags,
+ int interactive) {
+ int i, rc;
+ int foundinvalid = 0;
+ char * buf;
+
+ /* JKFIXME: ASSERT -- we have a cdrom device when we get here */
+ do {
+ for (i = 0; i < kd->numKnown; i++) {
+ if (kd->known[i].class != CLASS_CDROM) continue;
+
+ logMessage("trying to mount device %s", kd->known[i].name);
+ devMakeInode(kd->known[i].name, "/tmp/cdrom");
+ if (!doPwMount("/tmp/cdrom", "/mnt/source", "iso9660", 1, 0,
+ NULL, NULL)) {
+ if (!access("/mnt/source/RedHat/base/stage2.img", R_OK)) {
+ rc = mountStage2("/mnt/source/RedHat/base/stage2.img");
+ /* if we failed, umount /mnt/source and keep going */
+ if (rc) {
+ umount("/mnt/source");
+ if (rc == -1) foundinvalid = 1;
+ continue;
+ }
+
+ /* do the media check */
+ queryCDMediaCheck(kd->known[i].name, flags);
+
+ buf = malloc(200);
+ sprintf(buf, "cdrom://%s/mnt/source", kd->known[i].name);
+ return buf;
+ }
+ unlink("/tmp/cdrom");
+ }
+ }
+
+ if (interactive) {
+ char * buf;
+ if (foundinvalid)
+ buf = sdupprintf(_("No %s CD was found which matches your "
+ "boot media. Please insert the %s CD "
+ "and press %s to retry."), PRODUCTNAME,
+ PRODUCTNAME, _("OK"));
+ else
+ buf = sdupprintf(_("The %s CD was not found in any of your "
+ "CDROM drives. Please insert the %s CD "
+ "and press %s to retry."), PRODUCTNAME,
+ PRODUCTNAME, _("OK"));
+
+ rc = newtWinChoice(_("CD Not Found"),
+ _("OK"), _("Back"), buf, _("OK"));
+ free(buf);
+ if (rc == 2) return NULL;
+ } else {
+ /* we can't ask them about it, so just return not found */
+ return NULL;
+ }
+ } while (1);
+ return NULL;
+}
+
+/* try to find a Red Hat CD non-interactively */
+char * findRedHatCD(char * location,
+ struct knownDevices * kd,
+ moduleInfoSet modInfo,
+ moduleList modLoaded,
+ moduleDeps modDeps,
+ int flags) {
+ return setupCdrom(location, kd, modInfo, modLoaded, modDeps, flags, 0);
+}
+
+
+
+/* look for a Red Hat CD and mount it. if we have problems, ask */
+char * mountCdromImage(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags) {
+
+ setupCdrom(location, kd, modInfo, modLoaded, *modDepsPtr, flags, 1);
+}
diff --git a/loader2/cdinstall.h b/loader2/cdinstall.h
new file mode 100644
index 000000000..ed30be0c8
--- /dev/null
+++ b/loader2/cdinstall.h
@@ -0,0 +1,14 @@
+#ifndef H_CDINSTALL
+#define H_CDINSTALL
+
+#include "../isys/probe.h"
+#include "modules.h"
+
+char * findRedHatCD(char * location,
+ struct knownDevices * kd,
+ moduleInfoSet modInfo,
+ moduleList modLoaded,
+ moduleDeps modDeps,
+ int flags);
+
+#endif
diff --git a/loader2/dietstubs.c b/loader2/dietstubs.c
new file mode 100644
index 000000000..dab88965f
--- /dev/null
+++ b/loader2/dietstubs.c
@@ -0,0 +1,166 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+struct glibc_stat {
+ long long st_dev;
+ unsigned short int __pad1;
+ long st_ino;
+ int st_mode;
+ int st_nlink;
+ int st_uid;
+ int st_gid;
+ long long st_rdev;
+ unsigned short int __pad2;
+ long st_size;
+ long st_blksize;
+ long st_blocks;
+ long st_atime;
+ unsigned long int __unused1;
+ long st_mtime;
+ unsigned long int __unused2;
+ long st_ctime;
+ unsigned long int __unused3;
+ unsigned long int __unused4;
+ unsigned long int __unused5;
+};
+
+static void stat_copy(struct stat * from, struct glibc_stat * to) {
+ to->st_dev = from->st_dev;
+ to->st_ino = from->st_ino;
+ to->st_mode = from->st_mode;
+ to->st_nlink = from->st_nlink;
+ to->st_uid = from->st_uid;
+ to->st_gid = from->st_gid;
+ to->st_rdev = from->st_rdev;
+ to->st_size = from->st_size;
+ to->st_blksize = from->st_blksize;
+ to->st_blocks = from->st_blocks;
+ to->st_atime = from->st_atime;
+ to->st_mtime = from->st_mtime;
+ to->st_ctime = from->st_ctime;
+}
+
+int __xstat (int __ver, __const char *__filename, struct glibc_stat * sb) {
+ struct stat s;
+ int rc = stat(__filename, &s);
+
+ if (!rc) stat_copy(&s, sb);
+
+ return rc;
+}
+
+int __lxstat (int __ver, __const char *__filename, struct glibc_stat * sb) {
+ struct stat s;
+ int rc = lstat(__filename, &s);
+
+ if (!rc) stat_copy(&s, sb);
+
+ return rc;
+}
+
+int __fxstat (int __ver, int fd, struct glibc_stat * sb) {
+ struct stat s;
+ int rc = fstat(fd, &s);
+
+ if (!rc) stat_copy(&s, sb);
+
+ return rc;
+}
+
+extern double strtod (__const char * __nptr, char ** __endptr);
+
+double __strtod_internal (__const char *__restrict __nptr,
+ char **__restrict __endptr, int __group) {
+ return strtod(__nptr, __endptr);
+}
+
+
+long int __strtol_internal(const char * nptr, char ** endptr,
+ int base, int group) {
+ return strtol(nptr, endptr, base);
+}
+
+unsigned long int __strtoul_internal (__const char *__restrict __nptr,
+ char **__restrict __endptr,
+ int __base, int __group) __THROW {
+ return strtoul(__nptr, __endptr, __base);
+}
+
+char * __strdup(const char * s) {
+ return strdup(s);
+}
+
+void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function) {
+ fprintf(stderr, "%s:%d assertion failed in %s()\n",
+ __file, __line, __function);
+ abort();
+}
+
+int _setjmp(jmp_buf buf) {
+ return setjmp(buf);
+}
+
+char * strcasestr(char * haystack1, char * needle1) {
+ char * haystack = strdup(haystack1);
+ char * needle = strdup(needle1);
+ char * chptr;
+
+ for (chptr = haystack; *chptr; chptr++) *chptr = toupper(*chptr);
+ for (chptr = needle; *chptr; chptr++) *chptr = toupper(*chptr);
+
+ chptr = strstr(needle, haystack);
+ if (!chptr) return NULL;
+
+ return (chptr - haystack) + haystack1;
+}
+
+int _IO_putc(char c, void * f) {
+ return putc(c, f);
+}
+
+int _IO_getc(void * f) {
+ return getc(f);
+}
+
+int __xmknod (int __ver, const char * path, unsigned int mode,
+ long long * dev) {
+ return mknod(path, mode, *dev);
+}
+
+
+/* this should print the name of the app, but how? probably in a global
+ somewhere (like env is) */
+void warn(char * format, ...) {
+ va_list args;
+ int err = errno;
+
+ va_start(args, format);
+
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, format, args);
+ fprintf(stderr, ": %s\n", strerror(err));
+
+ va_end(args);
+
+ errno = err;
+}
+
+int pwrite(int fd, const void *buf, size_t count, off_t offset) {
+ return __pwrite(fd, buf, count, offset);
+}
+
+void * __rawmemchr (void* s, int c) {
+ while (*(char *)s != c)
+ s++;
+ return s;
+}
+
+char * dcgettext (const char *domainname, const char *msgid, int category) {
+ return msgid;
+}
diff --git a/loader2/driverdisk.c b/loader2/driverdisk.c
new file mode 100644
index 000000000..10b60f6c5
--- /dev/null
+++ b/loader2/driverdisk.c
@@ -0,0 +1,32 @@
+/*
+ * driverdisk.c - driver disk functionality
+ *
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 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 <newt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "loader.h"
+#include "log.h"
+#include "loadermisc.h"
+#include "lang.h"
+
+
+/* Prompt for loading a driver from "media"
+ *
+ * class: type of driver to load.
+ */
+int loadDriverFromMedia(int class) {
+
+}
diff --git a/loader2/firewire.c b/loader2/firewire.c
new file mode 100644
index 000000000..ae8496afd
--- /dev/null
+++ b/loader2/firewire.c
@@ -0,0 +1,87 @@
+/*
+ * firewire.c - firewire probing/module loading functionality
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 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 <kudzu/kudzu.h>
+#include <newt.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "log.h"
+#include "modules.h"
+#include "windows.h"
+
+int firewireInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ struct device ** devices;
+ int i = 0;
+ int found = 0;
+
+ if (FL_NOIEEE1394(flags)) return 0;
+
+ devices = probeDevices(CLASS_FIREWIRE, BUS_PCI, PROBE_ALL);
+
+ if (!devices) {
+ logMessage("no firewire controller found");
+ return 0;
+ }
+
+ startNewt(flags);
+
+ /* JKFIXME: if we looked for all of them, we could batch this up and it
+ * would be faster */
+ for (i=0; devices[i]; i++) {
+ logMessage("found firewire controller %s", devices[i]->driver);
+
+ winStatus(40, 3, _("Loading"), _("Loading %s driver..."),
+ devices[0]->driver);
+
+ if (mlLoadModuleSet(devices[i]->driver, modLoaded, modDeps,
+ modInfo, flags)) {
+ logMessage("failed to insert firewire module");
+ } else {
+ found++;
+ }
+ newtPopWindow();
+ }
+
+ if (found == 0)
+ return 1;
+
+ /* JKFIXME: don't really want to pop the window until after the sleep */
+ /* sleep to wait for firewire to become stable. */
+ sleep(3);
+
+ logMessage("probing for firewire scsi devices");
+ devices = probeDevices(CLASS_SCSI, BUS_FIREWIRE, PROBE_ALL);
+
+ if (!devices) {
+ logMessage("no firewire scsi devices found");
+ return 0;
+ }
+
+ for (i=0;devices[i];i++) {
+ if ((devices[i]->detached == 0) && (devices[i]->driver != NULL)) {
+ logMessage("found firewire device using %s", devices[i]->device);
+ mlLoadModuleSet(devices[i]->driver, modLoaded, modDeps,
+ modInfo, flags);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/loader2/firewire.h b/loader2/firewire.h
new file mode 100644
index 000000000..311532104
--- /dev/null
+++ b/loader2/firewire.h
@@ -0,0 +1,7 @@
+#ifndef H_FIREWIRE
+#define H_FIREWIRE
+
+int firewireInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags);
+
+#endif
diff --git a/loader2/ftp.c b/loader2/ftp.c
new file mode 100644
index 000000000..8dede50ef
--- /dev/null
+++ b/loader2/ftp.c
@@ -0,0 +1,525 @@
+/*
+ * ftp.c - ftp code
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@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.
+ */
+
+
+
+#define HAVE_ALLOCA_H 1
+#define HAVE_NETINET_IN_SYSTM_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define USE_ALT_DNS 1
+
+#if HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
+#if HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#if HAVE_NETINET_IN_SYSTM_H
+# include <sys/types.h>
+# include <netinet/in_systm.h>
+#endif
+
+#if ! HAVE_HERRNO
+extern int h_errno;
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#define TIMEOUT_SECS 60
+#define BUFFER_SIZE 4096
+
+#ifndef IPPORT_FTP
+# define IPPORT_FTP 21
+#endif
+
+#if defined(USE_ALT_DNS) && USE_ALT_DNS
+#include "../isys/dns.h"
+#endif
+
+#include "ftp.h"
+
+static int ftpCheckResponse(int sock, char ** str);
+static int ftpCommand(int sock, char * command, ...);
+static int getHostAddress(const char * host, struct in_addr * address);
+
+static int ftpCheckResponse(int sock, char ** str) {
+ static char buf[BUFFER_SIZE + 1];
+ int bufLength = 0;
+ fd_set emptySet, readSet;
+ char * chptr, * start;
+ struct timeval timeout;
+ int bytesRead, rc = 0;
+ int doesContinue = 1;
+ char errorCode[4];
+
+ errorCode[0] = '\0';
+
+ do {
+ FD_ZERO(&emptySet);
+ FD_ZERO(&readSet);
+ FD_SET(sock, &readSet);
+
+ timeout.tv_sec = TIMEOUT_SECS;
+ timeout.tv_usec = 0;
+
+ rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout);
+ if (rc < 1) {
+ if (rc==0)
+ return FTPERR_BAD_SERVER_RESPONSE;
+ else
+ rc = FTPERR_UNKNOWN;
+ } else
+ rc = 0;
+
+ bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1);
+
+ bufLength += bytesRead;
+
+ buf[bufLength] = '\0';
+
+ /* divide the response into lines, checking each one to see if
+ we are finished or need to continue */
+
+ start = chptr = buf;
+
+ do {
+ while (*chptr != '\n' && *chptr) chptr++;
+
+ if (*chptr == '\n') {
+ *chptr = '\0';
+ if (*(chptr - 1) == '\r') *(chptr - 1) = '\0';
+ if (str) *str = start;
+
+ if (errorCode[0]) {
+ if (!strncmp(start, errorCode, 3) && start[3] == ' ')
+ doesContinue = 0;
+ } else {
+ strncpy(errorCode, start, 3);
+ errorCode[3] = '\0';
+ if (start[3] != '-') {
+ doesContinue = 0;
+ }
+ }
+
+ start = chptr + 1;
+ chptr++;
+ } else {
+ chptr++;
+ }
+ } while (*chptr);
+
+ if (doesContinue && chptr > start) {
+ memcpy(buf, start, chptr - start - 1);
+ bufLength = chptr - start - 1;
+ } else {
+ bufLength = 0;
+ }
+ } while (doesContinue && !rc);
+
+ if (*errorCode == '4' || *errorCode == '5') {
+ if (!strncmp(errorCode, "550", 3)) {
+ return FTPERR_FILE_NOT_FOUND;
+ }
+
+ return FTPERR_BAD_SERVER_RESPONSE;
+ }
+
+ if (rc) return rc;
+
+ return 0;
+}
+
+int ftpCommand(int sock, char * command, ...) {
+ va_list ap;
+ int len;
+ char * s;
+ char * buf;
+ int rc;
+
+ va_start(ap, command);
+ len = strlen(command) + 2;
+ s = va_arg(ap, char *);
+ while (s) {
+ len += strlen(s) + 1;
+ s = va_arg(ap, char *);
+ }
+ va_end(ap);
+
+ buf = alloca(len + 1);
+
+ va_start(ap, command);
+ strcpy(buf, command);
+ strcat(buf, " ");
+ s = va_arg(ap, char *);
+ while (s) {
+ strcat(buf, s);
+ strcat(buf, " ");
+ s = va_arg(ap, char *);
+ }
+ va_end(ap);
+
+ buf[len - 2] = '\r';
+ buf[len - 1] = '\n';
+ buf[len] = '\0';
+
+ if (write(sock, buf, len) != len) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if ((rc = ftpCheckResponse(sock, NULL)))
+ return rc;
+
+ return 0;
+}
+
+
+static int getHostAddress(const char * host, struct in_addr * address) {
+ if (isdigit(host[0])) {
+ if (!inet_aton(host, address)) {
+ return FTPERR_BAD_HOST_ADDR;
+ }
+ } else {
+ if (mygethostbyname((char *) host, address)) {
+ errno = h_errno;
+ return FTPERR_BAD_HOSTNAME;
+ }
+ }
+
+ return 0;
+}
+
+int ftpOpen(char * host, char * name, char * password, char * proxy,
+ int port) {
+ static int sock;
+ /*static char * lastHost = NULL;*/
+ struct in_addr serverAddress;
+ struct sockaddr_in destPort;
+ struct passwd * pw;
+ char * buf;
+ int rc;
+
+ if (port < 0) port = IPPORT_FTP;
+
+ if (!name)
+ name = "anonymous";
+
+ if (!password) {
+ password = "root@";
+ if (getuid()) {
+ pw = getpwuid(getuid());
+ if (pw) {
+ password = alloca(strlen(pw->pw_name) + 2);
+ strcpy(password, pw->pw_name);
+ strcat(password, "@");
+ }
+ }
+ }
+
+ if (proxy) {
+ buf = alloca(strlen(name) + strlen(host) + 5);
+ sprintf(buf, "%s@%s", name, host);
+ name = buf;
+ host = proxy;
+ }
+
+ if ((rc = getHostAddress(host, &serverAddress))) return rc;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (sock < 0) {
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ destPort.sin_family = AF_INET;
+ destPort.sin_port = htons(port);
+ destPort.sin_addr = serverAddress;
+
+ if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
+ close(sock);
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ /* ftpCheckResponse() assumes the socket is nonblocking */
+ if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
+ close(sock);
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ if ((rc = ftpCheckResponse(sock, NULL))) {
+ return rc;
+ }
+
+ if ((rc = ftpCommand(sock, "USER", name, NULL))) {
+ close(sock);
+ return rc;
+ }
+
+ if ((rc = ftpCommand(sock, "PASS", password, NULL))) {
+ close(sock);
+ return rc;
+ }
+
+ if ((rc = ftpCommand(sock, "TYPE", "I", NULL))) {
+ close(sock);
+ return rc;
+ }
+
+ return sock;
+}
+
+int ftpGetFileDesc(int sock, char * remotename) {
+ int dataSocket;
+ struct sockaddr_in dataAddress;
+ int i, j;
+ char * passReply;
+ char * chptr;
+ char * retrCommand;
+ int rc;
+
+ if (write(sock, "PASV\r\n", 6) != 6) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+ if ((rc = ftpCheckResponse(sock, &passReply)))
+ return FTPERR_PASSIVE_ERROR;
+
+ chptr = passReply;
+ while (*chptr && *chptr != '(') chptr++;
+ if (*chptr != '(') return FTPERR_PASSIVE_ERROR;
+ chptr++;
+ passReply = chptr;
+ while (*chptr && *chptr != ')') chptr++;
+ if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
+ *chptr-- = '\0';
+
+ while (*chptr && *chptr != ',') chptr--;
+ if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
+ chptr--;
+ while (*chptr && *chptr != ',') chptr--;
+ if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
+ *chptr++ = '\0';
+
+ /* now passReply points to the IP portion, and chptr points to the
+ port number portion */
+
+ dataAddress.sin_family = AF_INET;
+ if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
+ return FTPERR_PASSIVE_ERROR;
+ }
+ dataAddress.sin_port = htons((i << 8) + j);
+
+ chptr = passReply;
+ while (*chptr++) {
+ if (*chptr == ',') *chptr = '.';
+ }
+
+ if (!inet_aton(passReply, &dataAddress.sin_addr))
+ return FTPERR_PASSIVE_ERROR;
+
+ dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (dataSocket < 0) {
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ retrCommand = alloca(strlen(remotename) + 20);
+ sprintf(retrCommand, "RETR %s\r\n", remotename);
+ i = strlen(retrCommand);
+
+ if (write(sock, retrCommand, i) != i) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if (connect(dataSocket, (struct sockaddr *) &dataAddress,
+ sizeof(dataAddress))) {
+ close(dataSocket);
+ return FTPERR_FAILED_DATA_CONNECT;
+ }
+
+ if ((rc = ftpCheckResponse(sock, NULL))) {
+ close(dataSocket);
+ return rc;
+ }
+
+ return dataSocket;
+}
+
+int ftpGetFileDone(int sock) {
+ if (ftpCheckResponse(sock, NULL)) {
+ return FTPERR_BAD_SERVER_RESPONSE;
+ }
+
+ return 0;
+}
+
+const char *ftpStrerror(int errorNumber) {
+ switch (errorNumber) {
+ case FTPERR_BAD_SERVER_RESPONSE:
+ return ("Bad FTP server response");
+
+ case FTPERR_SERVER_IO_ERROR:
+ return("FTP IO error");
+
+ case FTPERR_SERVER_TIMEOUT:
+ return("FTP server timeout");
+
+ case FTPERR_BAD_HOST_ADDR:
+ return("Unable to lookup FTP server host address");
+
+ case FTPERR_BAD_HOSTNAME:
+ return("Unable to lookup FTP server host name");
+
+ case FTPERR_FAILED_CONNECT:
+ return("Failed to connect to FTP server");
+
+ case FTPERR_FAILED_DATA_CONNECT:
+ return("Failed to establish data connection to FTP server");
+
+ case FTPERR_FILE_IO_ERROR:
+ return("IO error to local file");
+
+ case FTPERR_PASSIVE_ERROR:
+ return("Error setting remote server to passive mode");
+
+ case FTPERR_FILE_NOT_FOUND:
+ return("File not found on server");
+
+ case FTPERR_UNKNOWN:
+ default:
+ return("FTP Unknown or unexpected error");
+ }
+}
+
+int httpGetFileDesc(char * hostname, int port, char * remotename) {
+ char * buf;
+ struct timeval timeout;
+ char headers[4096];
+ char * nextChar = headers;
+ int checkedCode;
+ struct in_addr serverAddress;
+ int sock;
+ int rc;
+ struct sockaddr_in destPort;
+ fd_set readSet;
+
+ if (port < 0) port = 80;
+
+ if ((rc = getHostAddress(hostname, &serverAddress))) return rc;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (sock < 0) {
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ destPort.sin_family = AF_INET;
+ destPort.sin_port = htons(port);
+ destPort.sin_addr = serverAddress;
+
+ if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
+ close(sock);
+ return FTPERR_FAILED_CONNECT;
+ }
+
+ buf = alloca(strlen(remotename) + strlen(hostname) + 25);
+ sprintf(buf, "GET %s HTTP/1.0\t\nHost: %s\r\n\r\n", remotename, hostname);
+ write(sock, buf, strlen(buf));
+
+ /* This is fun; read the response a character at a time until we:
+
+ 1) Get our first \r\n; which lets us check the return code
+ 2) Get a \r\n\r\n, which means we're done */
+
+ *nextChar = '\0';
+ checkedCode = 0;
+ while (!strstr(headers, "\r\n\r\n")) {
+ FD_ZERO(&readSet);
+ FD_SET(sock, &readSet);
+
+ timeout.tv_sec = TIMEOUT_SECS;
+ timeout.tv_usec = 0;
+
+ rc = select(sock + 1, &readSet, NULL, NULL, &timeout);
+ if (rc == 0) {
+ close(sock);
+ return FTPERR_SERVER_TIMEOUT;
+ } else if (rc < 0) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if (read(sock, nextChar, 1) != 1) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ nextChar++;
+ *nextChar = '\0';
+
+ if (nextChar - headers == sizeof(headers)) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ if (!checkedCode && strstr(headers, "\r\n")) {
+ char * start, * end;
+
+ checkedCode = 1;
+ start = headers;
+ while (!isspace(*start) && *start) start++;
+ if (!*start) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+ start++;
+
+ end = start;
+ while (!isspace(*end) && *end) end++;
+ if (!*end) {
+ close(sock);
+ return FTPERR_SERVER_IO_ERROR;
+ }
+
+ *end = '\0';
+ if (!strcmp(start, "404")) {
+ close(sock);
+ return FTPERR_FILE_NOT_FOUND;
+ } else if (strcmp(start, "200")) {
+ close(sock);
+ return FTPERR_BAD_SERVER_RESPONSE;
+ }
+
+ *end = ' ';
+ }
+ }
+
+ return sock;
+}
diff --git a/loader2/ftp.h b/loader2/ftp.h
new file mode 100644
index 000000000..2c7052312
--- /dev/null
+++ b/loader2/ftp.h
@@ -0,0 +1,25 @@
+#ifndef H_FTP
+#define H_FTP
+
+const char * ftpStrerror(int ftpErrno);
+
+#define FTPERR_BAD_SERVER_RESPONSE -1
+#define FTPERR_SERVER_IO_ERROR -2
+#define FTPERR_SERVER_TIMEOUT -3
+#define FTPERR_BAD_HOST_ADDR -4
+#define FTPERR_BAD_HOSTNAME -5
+#define FTPERR_FAILED_CONNECT -6
+#define FTPERR_FILE_IO_ERROR -7
+#define FTPERR_PASSIVE_ERROR -8
+#define FTPERR_FAILED_DATA_CONNECT -9
+#define FTPERR_FILE_NOT_FOUND -10
+#define FTPERR_UNKNOWN -100
+
+int ftpOpen(char * host, char * name, char * password, char * proxy, int port);
+int ftpGetFile(int sock, char * remotename, int dest);
+int ftpGetFileDesc(int sock, char * remotename);
+int ftpGetFileDone(int sock);
+
+int httpGetFileDesc(char * hostname, int port, char * remotename);
+
+#endif
diff --git a/loader2/init.c b/loader2/init.c
new file mode 100644
index 000000000..d31e9742f
--- /dev/null
+++ b/loader2/init.c
@@ -0,0 +1,833 @@
+/*
+ * init.c
+ *
+ * This is the install type init
+ *
+ * Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 - 2002 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.
+ *
+ */
+
+#if USE_MINILIBC
+#include "minilibc.h"
+#ifndef SOCK_STREAM
+# define SOCK_STREAM 1
+#endif
+#else
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/klog.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/swap.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/reboot.h>
+#include <termios.h>
+
+/* Need to tell loop.h what the actual dev_t type is. */
+#undef dev_t
+#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
+#define dev_t unsigned int
+#else
+#define dev_t unsigned short
+#endif
+#include <linux/loop.h>
+#undef dev_t
+#define dev_t dev_t
+
+#define syslog klogctl
+#endif
+
+struct unmountInfo {
+ char * name;
+ int mounted;
+ int loopDevice;
+ enum { FS, LOOP } what;
+} ;
+
+#include <linux/cdrom.h>
+
+#define KICK_FLOPPY 1
+#define KICK_BOOTP 2
+
+#ifndef MS_REMOUNT
+#define MS_REMOUNT 32
+#endif
+
+#define ENV_PATH 0
+#define ENV_LD_LIBRARY_PATH 1
+#define ENV_HOME 2
+#define ENV_TERM 3
+#define ENV_DEBUG 4
+
+char * env[] = {
+ "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sysimage/bin:"
+ "/mnt/sysimage/usr/bin:/mnt/sysimage/usr/sbin:/mnt/sysimage/sbin",
+ /* we set a nicer ld library path specifically for bash -- a full
+ one makes anaconda unhappy */
+ "LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib",
+ "HOME=/",
+ "TERM=linux",
+ "DEBUG=",
+ "TERMINFO=/etc/linux-terminfo",
+ "PYTHONPATH=/tmp/updates",
+ NULL
+};
+
+
+/*
+ * this needs to handle the following cases:
+ *
+ * 1) run from a CD root filesystem
+ * 2) run from a read only nfs rooted filesystem
+ * 3) run from a floppy
+ * 4) run from a floppy that's been loaded into a ramdisk
+ *
+ */
+
+int testing=0;
+
+void printstr(char * string) {
+ write(1, string, strlen(string));
+}
+
+void fatal_error(int usePerror) {
+/* FIXME */
+#if 0
+ if (usePerror)
+ perror("failed:");
+ else
+#endif
+ printf("failed.\n");
+
+ printf("\nI can't recover from this.\n");
+ if (testing) exit(0);
+#if !defined(__s390__) && !defined(__s390x__)
+ while (1) ;
+#endif
+}
+
+int doMke2fs(char * device, char * size) {
+ char * args[] = { "/usr/sbin/mke2fs", NULL, NULL, NULL };
+ int pid, status;
+
+ args[1] = device;
+ args[2] = size;
+
+ if (!(pid = fork())) {
+ /* child */
+ execve("/usr/sbin/mke2fs", args, env);
+ fatal_error(1);
+ }
+
+ wait4(-1, &status, 0, NULL);
+
+ return 0;
+}
+
+int hasNetConfiged(void) {
+ int rc;
+ int s;
+ struct ifconf configs;
+ struct ifreq devs[10];
+
+ #ifdef __i386__
+ return 0;
+ #endif
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ /* FIXME was perror*/
+ printf("error creating socket: %d\n", errno);
+ return 0;
+ } else {
+ /* this is just good enough to tell us if we have anything
+ configured */
+ configs.ifc_len = sizeof(devs);
+ configs.ifc_buf = (void *) devs;
+
+ rc = ioctl(s, SIOCGIFCONF, &configs);
+ if (rc < 0) {
+ /* FIXME was perror*/
+ printstr("SIOCGIFCONF");
+ return 0;
+ }
+ if (configs.ifc_len == 0) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+void doklog(char * fn) {
+ fd_set readset, unixs;
+ int in, out, i;
+ int log;
+ int s;
+ int sock = -1;
+ struct sockaddr_un sockaddr;
+ char buf[1024];
+ int readfd;
+
+ in = open("/proc/kmsg", O_RDONLY,0);
+ if (in < 0) {
+ /* FIXME: was perror */
+ printstr("open /proc/kmsg");
+ return;
+ }
+
+ out = open(fn, O_WRONLY, 0);
+ if (out < 0)
+ printf("couldn't open %s for syslog -- still using /tmp/syslog\n", fn);
+
+ log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644);
+ if (log < 0) {
+ /* FIXME: was perror */
+ printstr("error opening /tmp/syslog");
+ sleep(5);
+
+ close(in);
+ return;
+ }
+
+ /* if we get this far, we should be in good shape */
+
+ if (fork()) {
+ /* parent */
+ close(in);
+ close(out);
+ close(log);
+ return;
+ }
+ close(0);
+ close(1);
+ close(2);
+
+ dup2(1, log);
+
+#if defined(USE_LOGDEV)
+ /* now open the syslog socket */
+ sockaddr.sun_family = AF_UNIX;
+ strcpy(sockaddr.sun_path, "/dev/log");
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ printf("error creating socket: %d\n", errno);
+ sleep(5);
+ }
+ printstr("got socket\n");
+ if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) +
+ strlen(sockaddr.sun_path))) {
+ printf("bind error: %d\n", errno);
+ sleep(5);
+ }
+ printstr("bound socket\n");
+ chmod("/dev/log", 0666);
+ if (listen(sock, 5)) {
+ printf("listen error: %d\n", errno);
+ sleep(5);
+ }
+#endif
+
+ syslog(8, NULL, 1);
+
+ FD_ZERO(&unixs);
+ while (1) {
+ memcpy(&readset, &unixs, sizeof(unixs));
+
+ if (sock >= 0) FD_SET(sock, &readset);
+ FD_SET(in, &readset);
+
+ i = select(20, &readset, NULL, NULL, NULL);
+ if (i <= 0) continue;
+
+ if (FD_ISSET(in, &readset)) {
+ i = read(in, buf, sizeof(buf));
+ if (i > 0) {
+ if (out >= 0) write(out, buf, i);
+ write(log, buf, i);
+ }
+ }
+
+ for (readfd = 0; readfd < 20; ++readfd) {
+ if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
+ i = read(readfd, buf, sizeof(buf));
+ if (i > 0) {
+ if (out >= 0) {
+ write(out, buf, i);
+ write(out, "\n", 1);
+ }
+
+ write(log, buf, i);
+ write(log, "\n", 1);
+ } else if (i == 0) {
+ /* socket closed */
+ close(readfd);
+ FD_CLR(readfd, &unixs);
+ }
+ }
+ }
+
+ if (sock >= 0 && FD_ISSET(sock, &readset)) {
+ s = sizeof(sockaddr);
+ readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
+ if (readfd < 0) {
+ if (out >= 0) write(out, "error in accept\n", 16);
+ write(log, "error in accept\n", 16);
+ close(sock);
+ sock = -1;
+ } else {
+ FD_SET(readfd, &unixs);
+ }
+ }
+ }
+}
+
+int setupTerminal(int fd) {
+ struct winsize winsize;
+
+ if (ioctl(fd, TIOCGWINSZ, &winsize)) {
+ printf("failed to get winsize");
+ fatal_error(1);
+ }
+
+ winsize.ws_row = 24;
+ winsize.ws_col = 80;
+
+ if (ioctl(fd, TIOCSWINSZ, &winsize)) {
+ printf("failed to set winsize");
+ fatal_error(1);
+ }
+
+ env[ENV_TERM] = "TERM=vt100";
+
+ return 0;
+}
+
+void undoLoop(struct unmountInfo * fs, int numFs, int this);
+
+void undoMount(struct unmountInfo * fs, int numFs, int this) {
+ int len = strlen(fs[this].name);
+ int i;
+
+ if (!fs[this].mounted) return;
+ fs[this].mounted = 0;
+
+ /* unmount everything underneath this */
+ for (i = 0; i < numFs; i++) {
+ if (fs[i].name[len] == '/' &&
+ !strncmp(fs[this].name, fs[i].name, len)) {
+ if (fs[i].what == LOOP)
+ undoLoop(fs, numFs, i);
+ else
+ undoMount(fs, numFs, i);
+ }
+ }
+
+ printf("\t%s", fs[this].name);
+ /* don't need to unmount /tmp. it is busy anyway. */
+ if (!testing) {
+ if (umount2(fs[this].name, 0) < 0) {
+ printf(" umount failed (%d)", errno);
+ } else {
+ printf(" done");
+ }
+ }
+ printf("\n");
+}
+
+void undoLoop(struct unmountInfo * fs, int numFs, int this) {
+ int i;
+ int fd;
+
+ if (!fs[this].mounted) return;
+ fs[this].mounted = 0;
+
+ /* find the device mount */
+ for (i = 0; i < numFs; i++) {
+ if (fs[i].what == FS && (fs[i].loopDevice == fs[this].loopDevice))
+ break;
+ }
+
+ if (i < numFs) {
+ /* the device is mounted, unmount it (and recursively, anything
+ * underneath) */
+ undoMount(fs, numFs, i);
+ }
+
+ unlink("/tmp/loop");
+ mknod("/tmp/loop", 0600 | S_IFBLK, (7 << 8) | fs[this].loopDevice);
+ printf("\tdisabling /dev/loop%d", fs[this].loopDevice);
+ if ((fd = open("/tmp/loop", O_RDONLY, 0)) < 0) {
+ printf(" failed to open device: %d", errno);
+ } else {
+ if (!testing && ioctl(fd, LOOP_CLR_FD, 0))
+ printf(" LOOP_CLR_FD failed: %d", errno);
+ close(fd);
+ }
+
+ printf("\n");
+}
+
+void unmountFilesystems(void) {
+ int fd, size;
+ char buf[65535]; /* this should be big enough */
+ char * chptr, * start;
+ struct unmountInfo filesystems[500];
+ int numFilesystems = 0;
+ int i;
+ struct loop_info li;
+ char * device;
+ struct stat sb;
+
+ fd = open("/proc/mounts", O_RDONLY, 0);
+ if (fd < 1) {
+ /* FIXME: was perror */
+ printstr("failed to open /proc/mounts");
+ sleep(2);
+ return;
+ }
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ buf[size] = '\0';
+
+ close(fd);
+
+ chptr = buf;
+ while (*chptr) {
+ device = chptr;
+ while (*chptr != ' ') chptr++;
+ *chptr++ = '\0';
+ start = chptr;
+ while (*chptr != ' ') chptr++;
+ *chptr++ = '\0';
+
+ if (strcmp(start, "/") && strcmp(start, "/tmp")) {
+ filesystems[numFilesystems].name = alloca(strlen(start) + 1);
+ strcpy(filesystems[numFilesystems].name, start);
+ filesystems[numFilesystems].what = FS;
+ filesystems[numFilesystems].mounted = 1;
+
+ stat(start, &sb);
+ if ((sb.st_dev >> 8) == 7) {
+ filesystems[numFilesystems].loopDevice = sb.st_dev & 0xf;
+ } else {
+ filesystems[numFilesystems].loopDevice = -1;
+ }
+
+ numFilesystems++;
+ }
+
+ while (*chptr != '\n') chptr++;
+ chptr++;
+ }
+
+ for (i = 0; i < 7; i++) {
+ unlink("/tmp/loop");
+ mknod("/tmp/loop", 0600 | S_IFBLK, (7 << 8) | i);
+ if ((fd = open("/tmp/loop", O_RDONLY, 0)) >= 0) {
+ if (!ioctl(fd, LOOP_GET_STATUS, &li) && li.lo_name[0]) {
+ filesystems[numFilesystems].name = alloca(strlen(li.lo_name)
+ + 1);
+ strcpy(filesystems[numFilesystems].name, li.lo_name);
+ filesystems[numFilesystems].what = LOOP;
+ filesystems[numFilesystems].mounted = 1;
+ filesystems[numFilesystems].loopDevice = i;
+ numFilesystems++;
+ }
+
+ close(fd);
+ }
+ }
+
+ for (i = 0; i < numFilesystems; i++) {
+ if (filesystems[i].what == LOOP) {
+ undoLoop(filesystems, numFilesystems, i);
+ }
+ }
+
+ for (i = 0; i < numFilesystems; i++) {
+ if (filesystems[i].mounted) {
+ undoMount(filesystems, numFilesystems, i);
+ }
+ }
+}
+
+void disableSwap(void) {
+ int fd;
+ char buf[4096];
+ int i;
+ char * start;
+ char * chptr;
+
+ if ((fd = open("/proc/swaps", O_RDONLY, 0)) < 0) return;
+
+ i = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (i < 0) return;
+ buf[i] = '\0';
+
+ start = buf;
+ while (*start) {
+ while (*start != '\n' && *start) start++;
+ if (!*start) return;
+
+ start++;
+ if (*start != '/') return;
+ chptr = start;
+ while (*chptr && *chptr != ' ') chptr++;
+ if (!(*chptr)) return;
+ *chptr = '\0';
+ printf("\t%s", start);
+ if (swapoff(start))
+ printf(" failed (%d)", errno);
+ printf("\n");
+
+ start = chptr + 1;
+ }
+}
+
+void ejectCdrom(void) {
+ int ejectfd;
+ struct stat sb;
+
+ stat("/tmp/cdrom", &sb);
+
+ if ((sb.st_mode & S_IFBLK) == S_IFBLK) {
+ printf("ejecting /tmp/cdrom...");
+ if ((ejectfd = open("/tmp/cdrom", O_RDONLY | O_NONBLOCK, 0)) >= 0) {
+ if (ioctl(ejectfd, CDROMEJECT, 0))
+ printf("eject failed %d ", errno);
+ close(ejectfd);
+ } else {
+ printf("eject failed %d ", errno);
+ }
+ printf("\n");
+ }
+}
+
+int mystrstr(char *str1, char *str2) {
+ char *p;
+ int rc=0;
+
+ for (p=str1; *p; p++) {
+ if (*p == *str2) {
+ char *s, *t;
+
+ rc = 1;
+ for (s=p, t=str2; *s && *t; s++, t++)
+ if (*s != *t) {
+ rc = 0;
+ p++;
+ }
+
+ if (rc)
+ return rc;
+ }
+ }
+ return rc;
+}
+
+
+
+int main(int argc, char **argv) {
+ pid_t installpid, childpid;
+ int waitStatus;
+ int fd;
+ int nfsRoot = 0;
+ int roRoot = 0;
+ int cdRoot = 0;
+ int doReboot = 0;
+ int doShutdown =0;
+ int isSerial = 0;
+ int noKill = 0;
+#ifdef __alpha__
+ char * kernel;
+#endif
+ char * argvc[15];
+ char ** argvp = argvc;
+ char twelve = 12;
+ int i;
+ char buf[500];
+ int len;
+
+
+#if !defined(__s390__) && !defined(__s390x__)
+ testing = (getppid() != 0) && (getppid() != 1);
+#endif
+
+ if (!testing) {
+ /* turn off screen blanking */
+ printstr("\033[9;0]");
+ printstr("\033[8]");
+ } else {
+ printstr("(running in test mode).\n");
+ }
+
+ umask(022);
+
+ printstr("Greetings.\n");
+
+ printf("Red Hat install init version %s starting\n", VERSION);
+
+ printf("mounting /proc filesystem... ");
+ if (!testing) {
+ if (mount("/proc", "/proc", "proc", 0, NULL))
+ fatal_error(1);
+ }
+ printf("done\n");
+
+ printf("mounting /dev/pts (unix98 pty) filesystem... ");
+ if (!testing) {
+ if (mount("/dev/pts", "/dev/pts", "devpts", 0, NULL))
+ fatal_error(1);
+ }
+ printf("done\n");
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+
+ /* these args are only for testing from commandline */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp (argv[i], "serial")) {
+ isSerial = 1;
+ break;
+ }
+ }
+
+ /* look through /proc/cmdline for special options */
+ if ((fd = open("/proc/cmdline", O_RDONLY,0)) > 0) {
+ len = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (len > 0 && mystrstr(buf, "nokill"))
+ noKill = 1;
+ }
+
+#if !defined(__s390__) && !defined(__s390x__)
+ if (ioctl (0, TIOCLINUX, &twelve) < 0) {
+ isSerial = 2;
+ }
+
+ if (isSerial) {
+ char *device = "/dev/ttyS0";
+
+ printf("Red Hat install init version %s using a serial console\n",
+ VERSION);
+
+ printf("remember, cereal is an important part of a nutritionally "
+ "balanced breakfast.\n\n");
+
+ if (isSerial == 2)
+ device = "/dev/console";
+ fd = open(device, O_RDWR, 0);
+ if (fd < 0)
+ device = "/dev/tts/0";
+
+ if (fd < 0) {
+ printf("failed to open %s\n", device);
+ fatal_error(1);
+ }
+
+ setupTerminal(fd);
+ } else {
+ fd = open("/dev/tty1", O_RDWR, 0);
+ if (fd < 0)
+ fd = open("/dev/vc/1", O_RDWR, 0);
+
+ if (fd < 0) {
+ printf("failed to open /dev/tty1 and /dev/vc/1");
+ fatal_error(1);
+ }
+ }
+
+ if (testing)
+ exit(0);
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+#endif
+
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL)) {
+ printf("could not set new controlling tty\n");
+ }
+
+ if (!testing) {
+ sethostname("localhost.localdomain", 21);
+ /* the default domainname (as of 2.0.35) is "(none)", which confuses
+ glibc */
+ setdomainname("", 0);
+ }
+
+ printf("checking for NFS root filesystem...");
+ if (hasNetConfiged()) {
+ printf("yes\n");
+ roRoot = nfsRoot = 1;
+ } else {
+ printf("no\n");
+ }
+
+ if (!nfsRoot) {
+ printf("trying to remount root filesystem read write... ");
+ if (mount("/", "/", "ext2", MS_REMOUNT | MS_MGC_VAL, NULL)) {
+ printf("failed (but that's okay)\n");
+
+ roRoot = 1;
+ } else {
+ printf("done\n");
+
+ /* 2.0.18 (at least) lets us remount a CD r/w!! */
+ printf("checking for writeable /tmp... ");
+ fd = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ printf("no (probably a CD rooted install)\n");
+ roRoot = 1;
+ } else {
+ close(fd);
+ unlink("/tmp/tmp");
+ printf("yes\n");
+ }
+ }
+ }
+
+ /* JKFIXME: bah, I don't like this but it has to stay like this until
+ * ramfs doesn't suck */
+#if !defined(__s390__) && !defined(__s390x__)
+#define RAMDISK_DEVICE "/dev/ram"
+#else
+#define RAMDISK_DEVICE "/dev/ram2"
+#endif
+
+ if (!testing && roRoot) {
+ printf("creating 300k of ramdisk space... ");
+ if (doMke2fs(RAMDISK_DEVICE, "300"))
+ fatal_error(0);
+
+ printf("done\n");
+
+ printf("mounting /tmp from ramdisk... ");
+ if (mount(RAMDISK_DEVICE, "/tmp", "ext2", 0, NULL))
+ fatal_error(1);
+
+ printf("done\n");
+
+ if (!nfsRoot) cdRoot = 1;
+ }
+
+ /* Now we have some /tmp space set up, and /etc and /dev point to
+ it. We should be in pretty good shape. */
+
+ if (!testing)
+ doklog("/dev/tty4");
+
+ /* Go into normal init mode - keep going, and then do a orderly shutdown
+ when:
+
+ 1) /bin/install exits
+ 2) we receive a SIGHUP
+ */
+
+ printf("running install...\n");
+
+ setsid();
+
+ if (!(installpid = fork())) {
+ /* child */
+ *argvp++ = "/sbin/loader";
+ *argvp++ = NULL;
+
+ printf("running %s\n", argvc[0]);
+ execve(argvc[0], argvc, env);
+
+ exit(0);
+ }
+
+ while (!doShutdown) {
+ childpid = wait4(-1, &waitStatus, 0, NULL);
+
+ if (childpid == installpid)
+ doShutdown = 1;
+ }
+
+ if (!WIFEXITED(waitStatus) || WEXITSTATUS(waitStatus)) {
+ printf("install exited abnormally ");
+ if (WIFSIGNALED(waitStatus)) {
+ printf("-- received signal %d", WTERMSIG(waitStatus));
+ }
+ printf("\n");
+ } else {
+ doReboot = 1;
+ }
+
+ if (testing)
+ exit(0);
+
+ sync(); sync();
+
+ if (!testing && !noKill) {
+ printf("sending termination signals...");
+ kill(-1, 15);
+ sleep(2);
+ printf("done\n");
+
+ printf("sending kill signals...");
+ kill(-1, 9);
+ sleep(2);
+ printf("done\n");
+ }
+
+ printf("disabling swap...\n");
+ disableSwap();
+
+ printf("unmounting filesystems...\n");
+ unmountFilesystems();
+
+ ejectCdrom();
+
+ if (doReboot) {
+ printf("rebooting system\n");
+ sleep(2);
+
+#if USE_MINILIBC
+ reboot(0xfee1dead, 672274793, 0x1234567);
+#else
+# ifdef __alpha__
+ reboot(RB_HALT_SYSTEM);
+# else
+ reboot(RB_AUTOBOOT);
+# endif
+#endif
+ } else {
+ printf("you may safely reboot your system\n");
+ while (1);
+ }
+
+ exit(0);
+
+ return 0;
+}
diff --git a/loader2/kbd.c b/loader2/kbd.c
new file mode 100644
index 000000000..e3149a29b
--- /dev/null
+++ b/loader2/kbd.c
@@ -0,0 +1,194 @@
+/*
+ * kbd.c - keyboard handling
+ *
+ * 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 <alloca.h>
+#include <errno.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "log.h"
+#include "lang.h"
+#include "windows.h"
+
+#include "../isys/stubs.h"
+#include "../isys/lang.h"
+
+/* JKFIXME: these should just be included from isys somehow.. */
+/* define ask johnsonm@redhat.com where this came from */
+#define KMAP_MAGIC 0x8B39C07F
+#define KMAP_NAMELEN 40 /* including '\0' */
+
+struct kmapHeader {
+ int magic;
+ int numEntries;
+};
+
+struct kmapInfo {
+ int size;
+ char name[KMAP_NAMELEN];
+};
+
+int chooseKeyboard(char ** keymap, char ** kbdtypep, int flags) {
+ int num = -1;
+ int rc;
+ gzFile f;
+ struct kmapHeader hdr;
+ struct kmapInfo * infoTable;
+ struct langInfo * languages;
+ int numLanguages;
+ char ** kbds;
+ char buf[16384]; /* I hope this is big enough */
+ int i;
+ char * defkbd = keymap ? *keymap : NULL;
+ char *lang;
+
+#if defined(__s390__) || defined(__s390x__)
+ return LOADER_NOOP;
+#endif
+
+ if (FL_SERIAL (flags)) return LOADER_NOOP;
+
+#ifdef __sparc__
+ {
+ int fd;
+
+ fd = open("/dev/kbd", O_RDWR);
+ if (fd < 0)
+ kbdtype = KBDTYPE_PC; /* if PC keyboard, then there is no driver for /dev/kbd */
+ else {
+ close(fd);
+ kbdtype = KBDTYPE_SUN;
+ }
+ }
+#endif /* sparc */
+
+ numLanguages = getLangInfo(&languages, flags);
+
+ lang = getenv("LANG");
+ if (!defkbd && lang) {
+ for (i = 0; i < numLanguages; i++) {
+ if (!strncmp(languages[i].lc_all, lang, 2)) {
+ defkbd = languages[i].keyboard;
+ break;
+ }
+ }
+ }
+
+ if (!defkbd)
+#ifdef __sparc__
+ if (kbdtype == KBDTYPE_SUN)
+ defkbd = "sunkeymap";
+ else
+#endif /* sparc drain bamage */
+ defkbd = "us";
+
+ f = gunzip_open("/etc/keymaps.gz");
+ if (!f) {
+ errorWindow("cannot open /etc/keymaps.gz: %s");
+ return LOADER_ERROR;
+ }
+
+ if (gunzip_read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ errorWindow("failed to read keymaps header: %s");
+ gunzip_close(f);
+ return LOADER_ERROR;
+ }
+
+ logMessage("%d keymaps are available", hdr.numEntries);
+
+ i = hdr.numEntries * sizeof(*infoTable);
+ infoTable = alloca(i);
+ if (gunzip_read(f, infoTable, i) != i) {
+ errorWindow("failed to read keymap information: %s");
+ gunzip_close(f);
+ return LOADER_ERROR;
+ }
+
+ /* JKFIXME: this actually looks how I want most of the kickstart loader
+ * stuff to look. but since I've not stubbed kickstart in yet,
+ * let's not include it yet */
+#if 0
+ if (FL_KICKSTART(flags)) {
+ if (!ksGetCommand(KS_CMD_KEYBOARD, NULL, &argc, &argv)) {
+ if (argc < 2) {
+ logMessage("no argument passed to keyboard "
+ "kickstart command");
+ } else {
+ for (i = 0; i < hdr.numEntries; i++)
+ if (!strcmp(infoTable[i].name, argv[1])) break;
+ if (i < hdr.numEntries)
+ num = i;
+ else
+ newtWinMessage("Kickstart Error", "OK", "Bad keymap "
+ "name %s passed to kickstart command.",
+ argv[1]);
+ }
+ }
+ }
+#endif
+
+ if (num == -1 ) {
+ kbds = alloca(sizeof(*kbds) * (hdr.numEntries + 1));
+ for (i = 0; i < hdr.numEntries; i++) {
+ kbds[i] = infoTable[i].name;
+ }
+
+ kbds[i] = NULL;
+ qsort(kbds, i, sizeof(*kbds), simpleStringCmp);
+
+ for (i = 0; i < hdr.numEntries; i++)
+ if (!strcmp(kbds[i], defkbd))
+ num = i;
+
+ rc = newtWinMenu(_("Keyboard Type"),
+ _("What type of keyboard do you have?"),
+ 40, 5, 5, 8, kbds, &num, _("OK"), _("Back"), NULL);
+ if (rc == 2) return LOADER_BACK;
+
+ /* num needs to index the right keyboard infoTable */
+ for (i = 0; i < hdr.numEntries; i++)
+ if (!strcmp(kbds[num], infoTable[i].name)) break;
+ num = i;
+ }
+
+ rc = 0;
+
+ for (i = 0; i < num; i++) {
+ if (gunzip_read(f, buf, infoTable[i].size) != infoTable[i].size) {
+ logMessage("error reading %d bytes from file: %s",
+ infoTable[i].size, strerror(errno));
+ gunzip_close(f);
+ rc = LOADER_ERROR;
+ }
+ }
+
+ if (!rc) rc = loadKeymap(f);
+
+ gunzip_close(f);
+
+ if (keymap) *keymap = strdup(infoTable[num].name);
+
+#ifdef __sparc__
+ if (kbdtypep) *kbdtypep = (kbdtype == KBDTYPE_SUN) ? "sun" : "pc";
+#endif
+
+ return rc;
+}
diff --git a/loader2/kbd.h b/loader2/kbd.h
new file mode 100644
index 000000000..35867c9bb
--- /dev/null
+++ b/loader2/kbd.h
@@ -0,0 +1,6 @@
+#ifndef H_KBD
+#define H_KBD
+
+int chooseKeyboard(char ** keymap, char ** kbdtypep, int flags);
+
+#endif
diff --git a/loader2/lang.c b/loader2/lang.c
new file mode 100644
index 000000000..47aa15d7e
--- /dev/null
+++ b/loader2/lang.c
@@ -0,0 +1,328 @@
+/*
+ * lang.c - determines language, handles translations
+ *
+ * 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 <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "lang.h"
+#include "log.h"
+#include "loadermisc.h"
+#include "windows.h"
+
+#include "../isys/stubs.h"
+#include "../isys/cpio.h"
+#include "../isys/lang.h"
+
+struct aString {
+ unsigned int hash;
+ short length;
+ char * str;
+} ;
+
+struct aString * strings = NULL;
+int numStrings = 0, allocedStrings = 0;
+
+static char * topLineWelcome = N_("Welcome to %s");
+static char * bottomHelpLine = N_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen ");
+
+static int aStringCmp(const void * a, const void * b) {
+ const struct aString * first = a;
+ const struct aString * second = b;
+
+ if (first->hash < second->hash)
+ return -1;
+ else if (first->hash == second->hash)
+ return 0;
+
+ return 1;
+}
+
+char * translateString(char * str) {
+ unsigned int sum = 0, xor = 0;
+ int len = 0;
+ char * chptr;
+ struct aString * match;
+ struct aString key;
+
+ for (chptr = str; *chptr; chptr++) {
+ sum += *chptr;
+ xor ^= *chptr;
+ len++;
+ }
+
+ key.hash = (sum << 16) | ((xor & 0xFF) << 8) | (len & 0xFF);
+
+ match = bsearch(&key, strings, numStrings, sizeof(*strings), aStringCmp);
+ if (!match)
+ return str;
+
+ return match->str;
+}
+
+static struct langInfo * languages = NULL;
+static int numLanguages = 0;
+
+static void loadLanguageList(int flags) {
+ char * file = FL_TESTING(flags) ? "../lang-table" :
+ "/etc/lang-table";
+ FILE * f;
+ char line[256];
+ char name[256], key[256], font[256], map[256], code[256],
+ keyboard[256], timezone[256];
+ int lineNum = 0;
+
+ f = fopen(file, "r");
+ if (!f) {
+ newtWinMessage(_("Error"), _("OK"), "cannot open %s: %s",
+ file, strerror (errno));
+ return;
+ }
+
+ while (fgets(line, sizeof(line), f)) {
+ lineNum++;
+ languages = realloc(languages, sizeof(*languages) * (numLanguages + 1));
+ if (sscanf(line, "%s %s %s %s %s %s %s\n", name, key, font, map,
+ code, keyboard, timezone) != 7) {
+ logMessage("bad line %d in lang-table", lineNum);
+ } else {
+ languages[numLanguages].lang = strdup(name);
+ languages[numLanguages].key = strdup(key);
+ languages[numLanguages].font = strdup(font);
+ languages[numLanguages].map = strdup(map);
+ languages[numLanguages].lc_all = strdup(code);
+ languages[numLanguages].keyboard = strdup(keyboard);
+ numLanguages++;
+ }
+ }
+}
+
+int getLangInfo(struct langInfo ** langs, int flags) {
+ if (!languages)
+ loadLanguageList(flags);
+
+ *langs = languages;
+ return numLanguages;
+}
+
+void loadLanguage (char * file, int flags) {
+ char filename[200];
+ gzFile stream;
+ int fd, hash, rc;
+ char * key = getenv("LANGKEY");
+
+ if (!key || !strcmp(key, "en_US")) {
+ if (strings) {
+ free(strings), strings = NULL;
+ numStrings = allocedStrings = 0;
+ }
+ return;
+ }
+
+ if (!file) {
+ file = filename;
+ if (FL_TESTING(flags))
+ sprintf(filename, "loader.tr");
+ else
+ sprintf(filename, "/etc/loader.tr");
+ }
+
+ stream = gunzip_open(file);
+
+ if (!stream) {
+ newtWinMessage("Error", "OK", "Translation for %s is not available. "
+ "The Installation will proceed in English.", key);
+ return ;
+ }
+
+ sprintf(filename, "%s.tr", key);
+
+ rc = installCpioFile(stream, filename, "/tmp/translation", 1);
+ gunzip_close(stream);
+
+ if (rc || access("/tmp/translation", R_OK)) {
+ newtWinMessage("Error", "OK", "Cannot get translation file %s.\n",
+ filename);
+ return;
+ }
+
+ fd = open("/tmp/translation", O_RDONLY);
+ if (fd < 0) {
+ newtWinMessage("Error", "OK", "Failed to open /tmp/translation: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ while (read(fd, &hash, 4) == 4) {
+ if (allocedStrings == numStrings) {
+ allocedStrings += 10;
+ strings = realloc(strings, sizeof(*strings) * allocedStrings);
+ }
+
+ strings[numStrings].hash = ntohl(hash);
+ read(fd, &strings[numStrings].length, 2);
+ strings[numStrings].length = ntohs(strings[numStrings].length);
+ strings[numStrings].str = malloc(strings[numStrings].length + 1);
+ read(fd, strings[numStrings].str, strings[numStrings].length);
+ strings[numStrings].str[strings[numStrings].length] = '\0';
+ numStrings++;
+ }
+
+ close(fd);
+ unlink("/tmp/translation");
+
+ qsort(strings, numStrings, sizeof(*strings), aStringCmp);
+}
+
+
+void setLanguage (char * key, int flags) {
+ int i;
+
+ if (!languages) loadLanguageList(flags);
+
+ for (i = 0; i < numLanguages; i++) {
+ if (!strcmp(languages[i].key, key)) {
+ if (!strcmp(languages[i].font, "None"))
+ break;
+ setenv("LANG", languages[i].lc_all, 1);
+ setenv("LANGKEY", languages[i].key, 1);
+ setenv("LC_ALL", languages[i].lc_all, 1);
+ setenv("LINGUAS", languages[i].lc_all, 1);
+ loadLanguage (NULL, flags);
+ if (languages[i].map)
+ isysLoadFont(languages[i].map);
+ break;
+ }
+ }
+}
+
+int chooseLanguage(char ** lang, int flags) {
+ int choice = 0;
+ char ** langs;
+ int i;
+ int english = 0;
+ int current = -1;
+ char * currentLangName = getenv("LANG");
+ int numLangs = 0;
+ char * langPicked;
+ char * buf;
+
+ /* JKFIXME: I ripped out some of the wacky Kon stuff. it might need
+ * to come back for bterm */
+ if (!languages) loadLanguageList(flags);
+
+ langs = alloca(sizeof(*langs) * (numLanguages + 1));
+
+ for (i = 0; i < numLanguages; i++) {
+ if (!strncmp(languages[i].key, "en", 2))
+ english = numLangs;
+ if (currentLangName &&
+ !strcmp(languages[i].lc_all, currentLangName))
+ current = numLangs;
+
+ langs[numLangs++] = languages[i].lang;
+ }
+
+ langs[numLangs] = NULL;
+
+ if (current >= 0)
+ choice = current;
+ else
+ choice = english;
+
+ newtWinMenu(_("Choose a Language"),
+ _("What language would you like to use during the "
+ "installation process?"), 40, 5, 5, 8,
+ langs, &choice, _("OK"), NULL);
+
+ langPicked = langs[choice];
+ for (i = 0; i < numLanguages; i++) {
+ if (!strcmp(langPicked, languages[i].lang)) {
+ *lang = languages[i].lc_all;
+ choice = i;
+ break;
+ }
+ }
+
+ /* this can't happen */
+ if (i == numLanguages) abort();
+
+ if (!strncmp(languages[choice].key, "en", 2)) {
+ char *buf;
+ /* stick with the default (English) */
+ unsetenv("LANG");
+ unsetenv("LANGKEY");
+ unsetenv("LC_ALL");
+ unsetenv("LINGUAS");
+ if (strings) {
+ free(strings), strings = NULL;
+ numStrings = allocedStrings = 0;
+ }
+ buf = sdupprintf(_(topLineWelcome), PRODUCTNAME);
+ newtDrawRootText(0, 0, buf);
+ free(buf);
+ newtPushHelpLine(_(bottomHelpLine));
+
+ return 0;
+ }
+
+ /* only set the environment variables when we actually have a way
+ to display the language */
+ if (strcmp(languages[choice].font, "None")) {
+ setenv("LANG", languages[choice].lc_all, 1);
+ setenv("LANGKEY", languages[choice].key, 1);
+ setenv("LC_ALL", languages[choice].lc_all, 1);
+ setenv("LINGUAS", languages[choice].lc_all, 1);
+ }
+
+ if (strings) {
+ free(strings), strings = NULL;
+ numStrings = allocedStrings = 0;
+ }
+
+ /* load the language only if it is displayable */
+ if (!strcmp(languages[choice].font, "None")) {
+ newtWinMessage("Language Unavailable", "OK",
+ "%s display is unavailable in text mode. The "
+ "installation will continue in English until the "
+ "display of %s is possible.", languages[choice].lang,
+ languages[choice].lang);
+ } else {
+ loadLanguage (NULL, flags);
+ }
+
+ if (languages[choice].map)
+ isysLoadFont(languages[choice].map);
+
+
+ buf = sdupprintf(_(topLineWelcome), PRODUCTNAME);
+ newtDrawRootText(0, 0, buf);
+ free(buf);
+ newtPushHelpLine(_(bottomHelpLine));
+
+ return 0;
+}
+
diff --git a/loader2/lang.h b/loader2/lang.h
new file mode 100644
index 000000000..405f955f8
--- /dev/null
+++ b/loader2/lang.h
@@ -0,0 +1,18 @@
+#ifndef _LANG_H_
+#define _LANG_H_
+
+#define _(x) translateString (x)
+#define N_(foo) (foo)
+
+struct langInfo {
+ char * lang, * key, * font, * map, * lc_all, * keyboard;
+} ;
+
+
+int chooseLanguage(char ** lang, int flags);
+char * translateString(char * str);
+void setLanguage (char * key, int flags);
+int getLangInfo(struct langInfo **langs, int flags);
+
+
+#endif /* _LANG_H_ */
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;
+}
diff --git a/loader2/loader.h b/loader2/loader.h
new file mode 100644
index 000000000..720e70e48
--- /dev/null
+++ b/loader2/loader.h
@@ -0,0 +1,77 @@
+#define LOADER_OK 0
+#define LOADER_BACK 1
+#define LOADER_NOOP 2
+#define LOADER_ERROR -1
+
+
+#define LOADER_FLAGS_TESTING (1 << 0)
+#define LOADER_FLAGS_EXPERT (1 << 1)
+#define LOADER_FLAGS_TEXT (1 << 2)
+#define LOADER_FLAGS_RESCUE (1 << 3)
+#define LOADER_FLAGS_KICKSTART (1 << 4)
+#define LOADER_FLAGS_KSFLOPPY (1 << 5)
+#define LOADER_FLAGS_KSHD (1 << 6)
+#define LOADER_FLAGS_NOPROBE (1 << 7)
+#define LOADER_FLAGS_MODDISK (1 << 8)
+#define LOADER_FLAGS_ISA (1 << 9)
+#define LOADER_FLAGS_SERIAL (1 << 10)
+#define LOADER_FLAGS_UPDATES (1 << 11)
+#define LOADER_FLAGS_KSFILE (1 << 12)
+#define LOADER_FLAGS_KSCDROM (1 << 13)
+#define LOADER_FLAGS_MCHECK (1 << 14)
+#define LOADER_FLAGS_KSNFS (1 << 15)
+#define LOADER_FLAGS_NOUSB (1 << 16)
+#define LOADER_FLAGS_NOSHELL (1 << 17)
+#define LOADER_FLAGS_NOPCMCIA (1 << 18)
+#define LOADER_FLAGS_TELNETD (1 << 19)
+#define LOADER_FLAGS_NOPASS (1 << 20)
+#define LOADER_FLAGS_KSHTTP (1 << 21)
+#define LOADER_FLAGS_MEDIACHECK (1 << 22)
+#define LOADER_FLAGS_NOUSBSTORAGE (1 << 23)
+#define LOADER_FLAGS_ASKMETHOD (1 << 24)
+#define LOADER_FLAGS_NOPARPORT (1 << 25)
+#define LOADER_FLAGS_NOIEEE1394 (1 << 26)
+
+#define FL_TESTING(a) ((a) & LOADER_FLAGS_TESTING)
+#define FL_EXPERT(a) ((a) & LOADER_FLAGS_EXPERT)
+#define FL_TEXT(a) ((a) & LOADER_FLAGS_TEXT)
+#define FL_RESCUE(a) ((a) & LOADER_FLAGS_RESCUE)
+#define FL_KICKSTART(a) ((a) & LOADER_FLAGS_KICKSTART)
+#define FL_KSFLOPPY(a) ((a) & LOADER_FLAGS_KSFLOPPY)
+#define FL_KSHD(a) ((a) & LOADER_FLAGS_KSHD)
+#define FL_NOPROBE(a) ((a) & LOADER_FLAGS_NOPROBE)
+#define FL_MODDISK(a) ((a) & LOADER_FLAGS_MODDISK)
+#define FL_ISA(a) ((a) & LOADER_FLAGS_ISA)
+#define FL_SERIAL(a) ((a) & LOADER_FLAGS_SERIAL)
+#define FL_UPDATES(a) ((a) & LOADER_FLAGS_UPDATES)
+#define FL_KSFILE(a) ((a) & LOADER_FLAGS_KSFILE)
+#define FL_KSCDROM(a) ((a) & LOADER_FLAGS_KSCDROM)
+#define FL_MCHECK(a) ((a) & LOADER_FLAGS_MCHECK)
+#define FL_KSNFS(a) ((a) & LOADER_FLAGS_KSNFS)
+#define FL_NOUSB(a) ((a) & LOADER_FLAGS_NOUSB)
+#define FL_NOSHELL(a) ((a) & LOADER_FLAGS_NOSHELL)
+#define FL_LOWRES(a) ((a) & LOADER_FLAGS_LOWRES)
+#define FL_NOFB(a) ((a) & LOADER_FLAGS_NOFB)
+#define FL_NOPCMCIA(a) ((a) & LOADER_FLAGS_NOPCMCIA)
+#define FL_RESCUE_NOMOUNT(a) ((a) & LOADER_FLAGS_RESCUE_NOMOUNT)
+#define FL_TELNETD(a) ((a) & LOADER_FLAGS_TELNETD)
+#define FL_NOPASS(a) ((a) & LOADER_FLAGS_NOPASS)
+#define FL_KSHTTP(a) ((a) & LOADER_FLAGS_KSHTTP)
+#define FL_MEDIACHECK(a) ((a) & LOADER_FLAGS_MEDIACHECK)
+#define FL_NOUSBSTORAGE(a) ((a) & LOADER_FLAGS_NOUSBSTORAGE)
+#define FL_ASKMETHOD(a) ((a) & LOADER_FLAGS_ASKMETHOD)
+#define FL_NOPARPORT(a) ((a) & LOADER_FLAGS_NOPARPORT)
+#define FL_NOIEEE1394(a) ((a) & LOADER_FLAGS_NOIEEE1394)
+
+
+
+void startNewt(int flags);
+void stopNewt();
+int setupRamdisk(void);
+
+
+#if !defined(__s390__) && !defined(__s390x__)
+#define RAMDISK_DEVICE "/dev/ram"
+#else
+#define RAMDISK_DEVICE "/dev/ram2"
+#endif
diff --git a/loader2/loadermisc.c b/loader2/loadermisc.c
new file mode 100644
index 000000000..2827312d4
--- /dev/null
+++ b/loader2/loadermisc.c
@@ -0,0 +1,116 @@
+/*
+ * loadermisc.c - miscellaneous loader functions that don't seem to fit
+ * anywhere else (yet) (was misc.c)
+ * JKFIXME: need to break out into reasonable files based on function
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 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 <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "log.h"
+
+int copyFileFd(int infd, char * dest) {
+ int outfd;
+ char buf[4096];
+ int i;
+ int rc = 0;
+
+ outfd = open(dest, O_CREAT | O_RDWR, 0666);
+
+ if (outfd < 0) {
+ logMessage("failed to open %s: %s", dest, strerror(errno));
+ return 1;
+ }
+
+ while ((i = read(infd, buf, sizeof(buf))) > 0) {
+ if (write(outfd, buf, i) != i) {
+ rc = 1;
+ break;
+ }
+ }
+
+ close(outfd);
+
+ return rc;
+}
+
+int copyFile(char * source, char * dest) {
+ int infd = -1;
+ int rc;
+
+ infd = open(source, O_RDONLY);
+
+ if (infd < 0) {
+ logMessage("failed to open %s: %s", source, strerror(errno));
+ return 1;
+ }
+
+ rc = copyFileFd(infd, dest);
+
+ close(infd);
+
+ return rc;
+}
+
+char * readLine(FILE * f) {
+ char buf[1024];
+
+ fgets(buf, sizeof(buf), f);
+
+ /* chop */
+ buf[strlen(buf) - 1] = '\0';
+
+ return strdup(buf);
+}
+
+int simpleStringCmp(const void * a, const void * b) {
+ const char * first = *((const char **) a);
+ const char * second = *((const char **) b);
+
+ return strcmp(first, second);
+}
+
+char * sdupprintf(const char *format, ...) {
+ char *buf = NULL;
+ char c;
+ va_list ap1, ap2;
+ size_t size = 0;
+
+ va_start(ap1, format);
+ va_copy(ap2, ap1);
+
+ /* XXX requires C99 vsnprintf behavior */
+ size = vsnprintf(&c, 1, format, ap1) + 1;
+ if (size == -1) {
+ printf("ERROR: vsnprintf behavior is not C99\n");
+ abort();
+ }
+
+ va_end(ap1);
+
+ buf = malloc(size);
+ if (buf == NULL)
+ return NULL;
+ vsnprintf(buf, size, format, ap2);
+ va_end (ap2);
+
+ return buf;
+}
diff --git a/loader2/loadermisc.h b/loader2/loadermisc.h
new file mode 100644
index 000000000..3e673d6e5
--- /dev/null
+++ b/loader2/loadermisc.h
@@ -0,0 +1,12 @@
+#ifndef H_LOADER_MISC_H
+#define H_LOADER_MISC_H
+#include <stdio.h>
+#include <stdarg.h>
+
+int copyFile(char * source, char * dest);
+int copyFileFd(int infd, char * dest);
+char * readLine(FILE * f);
+int simpleStringCmp(const void * a, const void * b);
+char * sdupprintf(const char *format, ...);
+
+#endif
diff --git a/loader2/log.c b/loader2/log.c
new file mode 100644
index 000000000..20030ae06
--- /dev/null
+++ b/loader2/log.c
@@ -0,0 +1,98 @@
+/*
+ * log.c - logging functionality
+ *
+ * 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 <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "log.h"
+
+static FILE * logfile = NULL;
+static int logfd;
+static int loglevel = 10;
+
+static FILE * logfile2 = NULL;
+static int logfd2 = 0;
+
+void logMessage(const char * s, ...) {
+ /* JKFIXME: need to make this debugMessage and handle a level param */
+ /* if (level > loglevel)
+ return;*/
+
+ va_list args;
+
+ if (!logfile) return;
+
+ va_start(args, s);
+
+ fprintf(logfile, "* ");
+ vfprintf(logfile, s, args);
+ fprintf(logfile, "\n");
+ fflush(logfile);
+
+ va_end(args);
+
+ if (!logfile2) return;
+
+ va_start(args, s);
+
+ fprintf(logfile2, "* ");
+ vfprintf(logfile2, s, args);
+ fprintf(logfile2, "\n");
+ fflush(logfile2);
+
+ va_end(args);
+
+ return;
+}
+
+void openLog(int useLocal) {
+ if (!useLocal) {
+ logfile = fopen("/dev/tty3", "w");
+ if (logfile) {
+ logfd = open("/dev/tty3", O_WRONLY);
+ logfile2 = fopen("/tmp/anaconda.log", "w");
+ if (logfile2)
+ logfd2 = open("/tmp/anaconda.log", O_WRONLY | O_APPEND);
+ } else {
+ logfile = fopen("/tmp/anaconda.log", "w");
+ logfd = open("/tmp/anaconda.log", O_WRONLY| O_APPEND);
+ }
+ } else {
+ logfile = fopen("debug.log", "w");
+ logfd = open("debug.log", O_WRONLY);
+ }
+}
+
+void closeLog(void) {
+ if (logfile) {
+ fclose(logfile);
+ close(logfd);
+ }
+ if (logfile2) {
+ fclose(logfile2);
+ close(logfd2);
+ }
+}
+
+/* set the level. higher means you see more verbosity */
+void setLogLevel(int level) {
+ loglevel = level;
+}
diff --git a/loader2/log.h b/loader2/log.h
new file mode 100644
index 000000000..a8bafa38d
--- /dev/null
+++ b/loader2/log.h
@@ -0,0 +1,14 @@
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdio.h>
+
+extern FILE * log;
+extern int logfd;
+
+void logMessage(const char * s, ...);
+void openLog(int useLocal);
+void closeLog(void);
+void setLogLevel(int level);
+
+#endif /* _LOG_H_ */
diff --git a/loader2/method.c b/loader2/method.c
new file mode 100644
index 000000000..b5691e693
--- /dev/null
+++ b/loader2/method.c
@@ -0,0 +1,359 @@
+/*
+ * method.c - generic install method setup functions
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "log.h"
+#include "lang.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+
+
+/* JKFIXME: this is a pile of crap... should at least only be done once */
+/* Need to tell loop.h what the actual dev_t type is. */
+#undef dev_t
+#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
+#define dev_t unsigned int
+#else
+#if defined(__x86_64__)
+#define dev_t unsigned long
+#else
+#define dev_t unsigned short
+#endif
+#endif
+#include <linux/loop.h>
+#undef dev_t
+#define dev_t dev_t
+
+
+
+int umountLoopback(char * mntpoint, char * device) {
+ int loopfd;
+
+ umount(mntpoint);
+
+ logMessage("umounting loopback %s %s", mntpoint, device);
+
+ devMakeInode(device, "/tmp/loop");
+ loopfd = open("/tmp/loop", O_RDONLY);
+
+ if (ioctl(loopfd, LOOP_CLR_FD, 0) < 0)
+ logMessage("LOOP_CLR_FD failed for %s %s (%s)", mntpoint, device,
+ strerror(errno));
+
+ close(loopfd);
+
+ return 0;
+}
+
+
+int mountLoopback(char * fsystem, char * mntpoint, char * device) {
+ struct loop_info loopInfo;
+ int targfd, loopfd;
+ char *filename;
+
+ mkdirChain(mntpoint);
+ filename = alloca(15 + strlen(device));
+ sprintf(filename, "/tmp/%s", device);
+
+ mkdirChain(mntpoint);
+
+ targfd = open(fsystem, O_RDONLY);
+ if (targfd < 0)
+ logMessage("opening target filesystem %s failed", fsystem);
+
+ devMakeInode(device, filename);
+ loopfd = open(filename, O_RDONLY);
+ logMessage("mntloop %s on %s as %s fd is %d",
+ device, mntpoint, fsystem, loopfd);
+
+ if (ioctl(loopfd, LOOP_SET_FD, targfd)) {
+ logMessage("LOOP_SET_FD failed: %s", strerror(errno));
+ close(targfd);
+ close(loopfd);
+ return LOADER_ERROR;
+ }
+
+ close(targfd);
+
+ memset(&loopInfo, 0, sizeof(loopInfo));
+ strcpy(loopInfo.lo_name, fsystem);
+
+ if (ioctl(loopfd, LOOP_SET_STATUS, &loopInfo)) {
+ logMessage("LOOP_SET_STATUS failed: %s", strerror(errno));
+ close(loopfd);
+ return LOADER_ERROR;
+ }
+
+ close(loopfd);
+
+ if (doPwMount(filename, mntpoint, "iso9660", 1,
+ 0, NULL, NULL)) {
+ if (doPwMount(filename, mntpoint, "ext2", 1,
+ 0, NULL, NULL)) {
+ if (doPwMount(filename, mntpoint, "cramfs", 1,
+ 0, NULL, NULL)) {
+
+ logMessage("failed to mount loop: %s",
+ strerror(errno));
+ return LOADER_ERROR;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* returns the *absolute* path (malloced) to the #1 iso image */
+char * validIsoImages(char * dirName) {
+ DIR * dir;
+ struct dirent * ent;
+ char isoImage[1024];
+
+ if (!(dir = opendir(dirName))) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to read directory %s: %s"),
+ dirName, strerror(errno));
+ return 0;
+ }
+
+ /* Walk through the directories looking for a Red Hat CD image. */
+ errno = 0;
+ while ((ent = readdir(dir))) {
+ sprintf(isoImage, "%s/%s", dirName, ent->d_name);
+
+ if (fileIsIso(isoImage)) {
+ errno = 0;
+ continue;
+ }
+
+ if (mountLoopback(isoImage, "/tmp/loopimage", "loop7")) {
+ logMessage("failed to mount %s", isoImage);
+ errno = 0;
+ continue;
+ }
+
+ if (!access("/tmp/loopimage/RedHat/base/hdstg1.img", F_OK)) {
+ umountLoopback("/tmp/loopimage", "loop7");
+ break;
+ }
+
+ umountLoopback("/tmp/loopimage", "loop7");
+
+ errno = 0;
+ }
+
+ closedir(dir);
+
+ if (!ent) return NULL;
+
+ return strdup(isoImage);
+}
+
+/* JKFIXME: needs implementing. should be very similar to the cdrom version */
+void queryIsoMediaCheck(char * isoDir, int flags) {
+ return;
+}
+
+/* Recursive */
+int copyDirectory(char * from, char * to) {
+ DIR * dir;
+ struct dirent * ent;
+ int fd, outfd;
+ char buf[4096];
+ int i;
+ struct stat sb;
+ char filespec[256];
+ char filespec2[256];
+ char link[1024];
+
+ mkdir(to, 0755);
+
+ if (!(dir = opendir(from))) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to read directory %s: %s"),
+ from, strerror(errno));
+ return 1;
+ }
+
+ errno = 0;
+ while ((ent = readdir(dir))) {
+ if (ent->d_name[0] == '.') continue;
+
+ sprintf(filespec, "%s/%s", from, ent->d_name);
+ sprintf(filespec2, "%s/%s", to, ent->d_name);
+
+ lstat(filespec, &sb);
+
+ if (S_ISDIR(sb.st_mode)) {
+ logMessage("recursively copying %s", filespec);
+ if (copyDirectory(filespec, filespec2)) return 1;
+ } else if (S_ISLNK(sb.st_mode)) {
+ i = readlink(filespec, link, sizeof(link) - 1);
+ link[i] = '\0';
+ if (symlink(link, filespec2)) {
+ logMessage("failed to symlink %s to %s: %s",
+ filespec2, link, strerror(errno));
+ }
+ } else {
+ fd = open(filespec, O_RDONLY);
+ if (fd < 0) {
+ logMessage("failed to open %s: %s", filespec,
+ strerror(errno));
+ return 1;
+ }
+ outfd = open(filespec2, O_RDWR | O_TRUNC | O_CREAT, 0644);
+ if (outfd < 0) {
+ logMessage("failed to create %s: %s", filespec2,
+ strerror(errno));
+ } else {
+ fchmod(outfd, sb.st_mode & 07777);
+
+ while ((i = read(fd, buf, sizeof(buf))) > 0)
+ write(outfd, buf, i);
+ close(outfd);
+ }
+
+ close(fd);
+ }
+
+ errno = 0;
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+
+void copyUpdatesImg(char * path) {
+ if (!access(path, R_OK)) {
+ if (!mountLoopback(path, "/tmp/update-disk", "loop7")) {
+ copyDirectory("/tmp/update-disk", "/tmp/updates");
+ umountLoopback("/tmp/update-disk", "loop7");
+ }
+ }
+}
+
+
+/* verify that the stamp files in / of the initrd and the stage2 match */
+int verifyStamp(char * path) {
+ char *stamp1;
+ char *stamp2;
+ FILE *f;
+ int fail = 0;
+ char * p;
+
+ stamp1 = alloca(13);
+ stamp2 = alloca(13);
+
+ /* grab the one from the initrd */
+ f = fopen("/.buildstamp", "r");
+ if (!f) {
+ fail = 1;
+ } else {
+ fgets(stamp1, 13, f);
+ fclose(f);
+
+ /* and the runtime */
+ p = sdupprintf("%s/.buildstamp", path);
+ f = fopen(p, "r");
+ free(p);
+ if (!f) {
+ fail = 1;
+ } else {
+ fgets(stamp2, 13, f);
+ fclose(f);
+
+ if (strncmp(stamp1, stamp2, 12) != 0) {
+ fail = 1;
+ }
+ }
+ }
+
+ if (fail == 1) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+
+
+/* mount a second stage, verify the stamp file, copy updates
+ * Returns 0 on success, 1 on failure to mount, -1 on bad stamp */
+int mountStage2(char * path) {
+ if (access(path, R_OK)) {
+ return 1;
+ }
+
+ if (mountLoopback(path, "/mnt/runtime", "loop0")) {
+ return 1;
+ }
+
+ if (!verifyStamp("/mnt/runtime")) {
+ umountLoopback("/mnt/runtime", "loop0");
+ return -1;
+ }
+
+ /* JKFIXME: this is kind of silly.. /mnt/source is hardcoded :/ */
+ copyUpdatesImg("/mnt/source/RedHat/base/updates.img");
+ return 0;
+}
+
+
+/* copies a second stage from fd to dest and mounts on mntpoint */
+int copyFileAndLoopbackMount(int fd, char * dest, int flags,
+ char * device, char * mntpoint) {
+ int rc;
+ struct stat sb;
+
+ rc = copyFileFd(fd, dest);
+ stat(dest, &sb);
+ logMessage("copied %d bytes to %s%s", sb.st_size, dest,
+ (rc) ? " (incomplete)" : "");
+
+ if (rc) {
+ /* just to make sure */
+ unlink(dest);
+ return 1;
+ }
+
+ if (mountLoopback(dest, mntpoint, device)) {
+ /* JKFIXME: this used to be fatal, but that seems unfriendly */
+ logMessage("Error mounting /dev/%s on %s (%s)", device, mntpoint,
+ strerror(errno));
+ unlink(dest);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/loader2/method.h b/loader2/method.h
new file mode 100644
index 000000000..6b8585066
--- /dev/null
+++ b/loader2/method.h
@@ -0,0 +1,32 @@
+#ifndef H_METHOD
+#define H_METHOD
+
+#include "../isys/probe.h"
+#include "modules.h"
+#include "moduledeps.h"
+
+struct installMethod {
+ char * name;
+ int network;
+ enum deviceClass deviceType; /* for pcmcia */
+ char * (*mountImage)(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags);
+};
+
+
+int umountLoopback(char * mntpoint, char * device);
+int mountLoopback(char * fsystem, char * mntpoint, char * device);
+
+char * validIsoImages(char * dirName);
+void queryIsoMediaCheck(char * isoDir, int flags);
+
+int mountStage2(char * path);
+int copyFileAndLoopbackMount(int fd, char * dest, int flags,
+ char * device, char * mntpoint);
+
+void copyUpdatesImg(char * path);
+int copyDirectory(char * from, char * to);
+
+#endif
diff --git a/loader2/mkctype.c b/loader2/mkctype.c
new file mode 100644
index 000000000..ed00411a9
--- /dev/null
+++ b/loader2/mkctype.c
@@ -0,0 +1,57 @@
+#include <ctype.h>
+#include <stdio.h>
+
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
+# define __ctype_b (*__ctype_b_loc())
+# define __ctype_tolower (*__ctype_tolower_loc())
+# define __ctype_toupper (*__ctype_toupper_loc())
+#endif
+
+int main(int argc, char ** argv) {
+ int i;
+
+ printf("#include <sys/types.h>\n\n");
+
+ printf("static const unsigned short int __ctype_b_internal[] = {");
+
+ for (i = -128; i < 256; i++) {
+ if (!(i % 8)) {
+ printf("\n");
+ }
+
+ printf("\t0x%x,", __ctype_b[i]);
+ }
+
+ printf("\n};\n\n");
+ printf("const unsigned short int * __ctype_b = __ctype_b_internal + 128;\n\n");
+
+ printf("const int __ctype_toupper_internal[] = {");
+ for (i = -128; i < 256; i++) {
+ if (!(i % 8)) {
+ printf("\n");
+ }
+
+ printf("\t0x%x,", __ctype_toupper[i]);
+ }
+
+ printf("\n};\n\n");
+ printf("const int * __ctype_toupper = __ctype_toupper_internal + 128;\n\n");
+
+ printf("const int __ctype_tolower_internal[] = {");
+ for (i = -128; i < 256; i++) {
+ if (!(i % 8)) {
+ printf("\n");
+ }
+
+ printf("\t0x%x,", __ctype_tolower[i]);
+ }
+
+ printf("\n};\n\n");
+ printf("const int * __ctype_tolower = __ctype_tolower_internal + 128;\n\n");
+
+ printf ("const unsigned short int **__ctype_b_loc (void) { return &__ctype_b; }\n");
+ printf ("const int **__ctype_toupper_loc (void) { return &__ctype_toupper; }\n");
+ printf ("const int **__ctype_tolower_loc (void) { return &__ctype_tolower; }\n\n");
+
+ return 0;
+};
diff --git a/loader2/modstubs.c b/loader2/modstubs.c
new file mode 100644
index 000000000..79de5f323
--- /dev/null
+++ b/loader2/modstubs.c
@@ -0,0 +1,160 @@
+/*
+ * modstubs.c - stubs around modutils commands
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#include "../isys/cpio.h"
+#include "../isys/stubs.h"
+
+/* hack */
+int combined_insmod_main(int argc, char ** argv);
+
+int ourInsmodCommand(int argc, char ** argv) {
+ char * file;
+ char finalName[100];
+ char * chptr;
+ gzFile fd;
+ int rc, rmObj = 0;
+ char * ballPath = NULL;
+ char fullName[100];
+ struct utsname u;
+
+ uname(&u);
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: insmod [-p <path>] <module>.o [params]\n");
+ return 1;
+ }
+
+ if (!strcmp(argv[1], "-p")) {
+ ballPath = malloc(strlen(argv[2]) + 30);
+ sprintf(ballPath, "%s/modules.cgz", argv[2]);
+ argv += 2;
+ argc -= 2;
+ } else {
+ ballPath = strdup("/modules/modules.cgz");
+ }
+
+ file = argv[1];
+
+ if (access(file, R_OK)) {
+ /* it might be having a ball */
+ fd = gunzip_open(ballPath);
+ if (!fd) {
+ free(ballPath);
+ return 1;
+ }
+
+ chptr = strrchr(file, '/');
+ if (chptr) file = chptr + 1;
+ sprintf(finalName, "/tmp/%s", file);
+
+ sprintf(fullName, "%s/%s", u.release, file);
+
+ if (installCpioFile(fd, fullName, finalName, 0)) {
+ free(ballPath);
+ return 1;
+ }
+
+ rmObj = 1;
+ file = finalName;
+ }
+
+ free(ballPath);
+
+ argv[0] = "insmod";
+ argv[1] = file;
+
+ rc = combined_insmod_main(argc, argv);
+
+ if (rmObj) unlink(file);
+
+ return rc;
+}
+
+int rmmod(char * modName) {
+ pid_t child;
+ int status;
+ char * argv[] = { "/bin/rmmod", modName, NULL };
+ int argc = 2;
+ int rc = 0;
+
+ if ((child = fork()) == 0) {
+ exit(combined_insmod_main(argc, argv));
+ }
+
+ waitpid(child, &status, 0);
+
+ if (WIFEXITED(status))
+ rc = WEXITSTATUS(status);
+ else
+ rc = -1;
+
+ return rc;
+}
+
+int insmod(char * modName, char * path, char ** args) {
+ int argc;
+ char ** argv;
+ int rc = 0;
+ pid_t child;
+ int status;
+ int count;
+
+ argc = 0;
+ for (argv = args; argv && *argv; argv++, argc++);
+
+ argv = alloca(sizeof(*argv) * (argc + 5));
+ argv[0] = "/bin/insmod";
+ count = 1;
+ if (path) {
+ argv[1] = "-p";
+ argv[2] = path;
+ count += 2;
+ }
+
+ argv[count] = modName;
+ count++;
+
+ if (args)
+ memcpy(argv + count, args, sizeof(*args) * argc);
+
+ argv[argc + count] = NULL;
+
+ argc += count;
+
+ if ((child = fork()) == 0) {
+ execv("/bin/loader", argv);
+ exit(1);
+ }
+
+ waitpid(child, &status, 0);
+
+ if (WIFEXITED(status))
+ rc = WEXITSTATUS(status);
+ else
+ rc = -1;
+
+ return rc;
+}
diff --git a/loader2/modstubs.h b/loader2/modstubs.h
new file mode 100644
index 000000000..a03c17aea
--- /dev/null
+++ b/loader2/modstubs.h
@@ -0,0 +1,8 @@
+#ifndef H_MODSTUBS
+#define H_MODSTUBS
+
+int ourInsmodCommand(int argc, char ** argv);
+int rmmod(char * modName);
+int insmod(char * modName, char * path, char ** args);
+
+#endif
diff --git a/loader2/moduledeps.c b/loader2/moduledeps.c
new file mode 100644
index 000000000..287f31b84
--- /dev/null
+++ b/loader2/moduledeps.c
@@ -0,0 +1,133 @@
+/*
+ * moduledeps.c - module dependency determination
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 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 <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "moduledeps.h"
+
+moduleDeps mlNewDeps(void) {
+ moduleDeps md;
+
+ md = malloc(sizeof(*md));
+ md->name = NULL;
+ md->deps = NULL;
+
+ return md;
+}
+
+/* JKFIXME: if we have a new module with different deps, this doesn't
+ * handle it correctly */
+int mlLoadDeps(moduleDeps * moduleDepListPtr, const char * path) {
+ int fd;
+ char * buf;
+ struct stat sb;
+ char * start, * end, * chptr;
+ int i, numItems;
+ moduleDeps nextDep;
+ moduleDeps moduleDepList = *moduleDepListPtr;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ return -1;
+ }
+
+ fstat(fd, &sb);
+ buf = alloca(sb.st_size + 1);
+ read(fd, buf, sb.st_size);
+ buf[sb.st_size] = '\0';
+ close(fd);
+
+ start = buf;
+ numItems = 0;
+ while (start) {
+ numItems++;
+ start = strchr(start + 1, '\n');
+ }
+
+ for (nextDep = moduleDepList; nextDep->name; nextDep++) numItems++;
+
+ moduleDepList = realloc(moduleDepList, sizeof(*moduleDepList) * numItems);
+ for (nextDep = moduleDepList; nextDep->name; nextDep++) ;
+
+ start = buf;
+ while (start < (buf + sb.st_size) && *start) {
+ end = strchr(start, '\n');
+ *end = '\0';
+
+ chptr = strchr(start, ':');
+ if (!chptr) {
+ start = end + 1;
+ continue;
+ }
+
+ *chptr++ = '\0';
+ while (*chptr && isspace(*chptr)) chptr++;
+ if (!*chptr) {
+ start = end + 1;
+ continue;
+ }
+
+ /* found something */
+ nextDep->name = strdup(start);
+ nextDep->deps = malloc(sizeof(char *) * (strlen(chptr) + 1));
+ start = chptr, i = 0;
+ while (start && *start) {
+ chptr = strchr(start, ' ');
+ if (chptr) *chptr = '\0';
+ nextDep->deps[i++] = strdup(start);
+ if (chptr)
+ start = chptr + 1;
+ else
+ start = NULL;
+ while (start && *start && isspace(*start)) start++;
+ }
+ nextDep->deps[i] = NULL;
+ nextDep->deps = realloc(nextDep->deps, sizeof(char *) * (i + 1));
+ nextDep++;
+
+ start = end + 1;
+ }
+
+ nextDep->name = NULL;
+ nextDep->deps = NULL;
+ moduleDepList = realloc(moduleDepList, sizeof(*moduleDepList) *
+ (nextDep - moduleDepList + 1));
+
+ *moduleDepListPtr = moduleDepList;
+
+ return 0;
+}
+
+char ** mlGetDeps(moduleDeps modDeps, const char * modName) {
+ moduleDeps dep;
+
+ for (dep = modDeps; dep && dep->name && strcmp(dep->name, modName); dep++);
+
+ if (dep) return dep->deps;
+
+ return NULL;
+}
diff --git a/loader2/moduledeps.h b/loader2/moduledeps.h
new file mode 100644
index 000000000..de040c269
--- /dev/null
+++ b/loader2/moduledeps.h
@@ -0,0 +1,15 @@
+#ifndef MODULEDEPS_H
+#define MODULEDEPS_H
+
+typedef struct moduleDependency_s * moduleDeps;
+
+struct moduleDependency_s {
+ char * name;
+ char ** deps;
+};
+
+moduleDeps mlNewDeps(void);
+int mlLoadDeps(moduleDeps * moduleDepListPtr, const char * path);
+char ** mlGetDeps(moduleDeps modDeps, const char * modName);
+
+#endif
diff --git a/loader2/moduleinfo.c b/loader2/moduleinfo.c
new file mode 100644
index 000000000..6ef940b86
--- /dev/null
+++ b/loader2/moduleinfo.c
@@ -0,0 +1,254 @@
+/*
+ * moduleinfo.c - module info functionality
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@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 <alloca.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+#include "moduleinfo.h"
+
+struct moduleInfo * getModuleList(moduleInfoSet mis,
+ enum driverMajor major) {
+ struct moduleInfo * miList, * next;
+ int i;
+
+ next = miList = malloc(sizeof(*miList) * mis->numModules + 1);
+ for (i = 0; i < mis->numModules; i++) {
+ if (mis->moduleList[i].major == major || major == DRIVER_NONE) {
+ *next = mis->moduleList[i];
+ next++;
+ }
+ }
+
+ if (next == miList) {
+ free(next);
+ return NULL;
+ }
+
+ next->moduleName = NULL;
+ next++;
+
+ miList = realloc(miList, sizeof(*miList) * (next - miList));
+ return miList;
+}
+
+struct moduleInfo * findModuleInfo(moduleInfoSet mis,
+ const char * moduleName) {
+ int i;
+ struct moduleInfo * found = NULL;
+
+ for (i = 0; i < mis->numModules; i++) {
+ if (!strcmp(moduleName, mis->moduleList[i].moduleName)) {
+ if (!found)
+ found = mis->moduleList + i;
+ else if (found->locationID && !mis->moduleList[i].locationID)
+ ;
+ else
+ found = mis->moduleList + i;
+ }
+ }
+
+ return found;
+}
+
+moduleInfoSet newModuleInfoSet(void) {
+ return calloc(sizeof(struct moduleInfoSet_s), 1);
+}
+
+/* filename: file to read module-info from
+ * mis: moduleInfoSet
+ * location: moduleBallLocation struct describing the location of
+ * these modules. (may be NULL)
+ * override: 1 if modules from this module ball should override old ones
+ * of the same name.
+ */
+int readModuleInfo(const char * filename, moduleInfoSet mis,
+ void * location, int override) {
+ int fd, isIndented;
+ char * buf, * start, * next, * chptr;
+ struct stat sb;
+ char oldch;
+ struct moduleInfo * nextModule;
+ int modulesAlloced;
+ int i;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) return -1;
+
+ fstat(fd, &sb);
+ buf = alloca(sb.st_size + 1);
+ i = read(fd, buf, sb.st_size);
+ buf[sb.st_size] = '\0';
+ close(fd);
+
+ if (i != sb.st_size)
+ return -1;
+
+ nextModule = NULL;
+ modulesAlloced = mis->numModules;
+
+ if (strncmp(buf, "Version 0\n", 10)) return -1;
+
+ start = buf + 10;
+ while (start && *start) {
+ chptr = strchr(start, '\n');
+ if (chptr) {
+ /* slice and dice */
+ next = chptr + 1;
+ } else {
+ chptr + strlen(start) - 1;
+ }
+
+ chptr--;
+ while (isspace(*chptr)) chptr--;
+ chptr++;
+ *chptr = '\0';
+
+ isIndented = 0;
+ if (isspace(*start)) {
+ while (isspace(*start) && *start != '\n') start++;
+ isIndented = 1;
+ }
+
+ if (*start != '\n' && *start && *start != '#') {
+ if (!isIndented) {
+ if (nextModule && nextModule->moduleName &&
+ nextModule == (mis->moduleList + mis->numModules)) {
+ mis->numModules++;
+ }
+
+ if (mis->numModules == modulesAlloced) {
+ modulesAlloced += 5;
+ mis->moduleList = realloc(mis->moduleList,
+ modulesAlloced * sizeof(*mis->moduleList));
+ }
+
+ nextModule = NULL;
+ if (override) {
+ for (i = 0; i < mis->numModules; i++) {
+ if (!strcmp(mis->moduleList[i].moduleName, start)) {
+ nextModule = mis->moduleList + i;
+ break;
+ }
+ }
+ }
+
+ if (!nextModule) {
+ nextModule = mis->moduleList + mis->numModules;
+
+ nextModule->moduleName = strdup(start);
+ }
+
+ nextModule->major = DRIVER_NONE;
+ nextModule->minor = DRIVER_MINOR_NONE;
+ nextModule->description = NULL;
+ nextModule->flags = 0;
+ nextModule->args = NULL;
+ nextModule->numArgs = 0;
+ nextModule->locationID = location;
+ } else if (!nextModule) {
+ /* ACK! syntax error */
+ return 1;
+ } else if (nextModule->major == DRIVER_NONE) {
+ chptr = start + strlen(start) - 1;
+ while (!isspace(*chptr) && chptr > start) chptr--;
+ if (chptr != start) chptr++;
+
+ if (!strcmp(chptr, "eth")) {
+ nextModule->major = DRIVER_NET;
+ nextModule->minor = DRIVER_MINOR_ETHERNET;
+ } else if (!strcmp(chptr, "tr")) {
+ nextModule->major = DRIVER_NET;
+ nextModule->minor = DRIVER_MINOR_TR;
+ } else if (!strcmp(chptr, "plip")) {
+ nextModule->major = DRIVER_NET;
+ nextModule->minor = DRIVER_MINOR_PLIP;
+ } else if (!strcmp(chptr, "scsi_hostadapter") ||
+ !strcmp(chptr, "scsi")) {
+ nextModule->major = DRIVER_SCSI;
+ } else if (!strcmp(chptr, "cdrom")) {
+ nextModule->major = DRIVER_CDROM;
+ }
+ } else if (!nextModule->description) {
+ chptr = start + strlen(start) - 1;
+ if (*start == '"' && *chptr == '"') {
+ start++;
+ *chptr = '\0';
+ nextModule->description = strdup(start);
+ }
+ } else {
+ nextModule->args = realloc(nextModule->args,
+ sizeof(*nextModule->args) * (nextModule->numArgs + 1));
+ chptr = start;
+ while (!isspace(*chptr) && *chptr) chptr++;
+ if (*chptr) {
+ oldch = *chptr;
+ *chptr = '\0';
+ nextModule->args[nextModule->numArgs].arg = strdup(start);
+
+ start = chptr + 1;
+ while (*start && isspace(*start)) start++;
+
+ if (*start == '"') {
+ start++;
+ chptr = strchr(start, '"');
+ if (chptr) {
+ *chptr = '\0';
+ nextModule->args[nextModule->numArgs].description =
+ strdup(start);
+ nextModule->numArgs++;
+ }
+ }
+ }
+ }
+ }
+
+ start = next;
+ }
+
+ /* do we need to add in this last module? */
+ if (nextModule && ((nextModule - mis->moduleList) == mis->numModules))
+ mis->numModules++;
+
+ return 0;
+}
+
+void freeModuleInfoSet(moduleInfoSet mis) {
+ int i, j;
+
+ for (i = 0; i < mis->numModules; i++) {
+ if (mis->moduleList[i].moduleName)
+ free(mis->moduleList[i].moduleName);
+
+ if (mis->moduleList[i].description)
+ free(mis->moduleList[i].description);
+
+ for (j = 0; i < mis->moduleList[i].numArgs; j++) {
+ if (mis->moduleList[i].args[j].arg)
+ free(mis->moduleList[i].args[j].arg) ;
+ if (mis->moduleList[i].args[j].description)
+ free(mis->moduleList[i].args[j].description) ;
+ }
+ }
+
+ free(mis);
+}
diff --git a/loader2/moduleinfo.h b/loader2/moduleinfo.h
new file mode 100644
index 000000000..50179352e
--- /dev/null
+++ b/loader2/moduleinfo.h
@@ -0,0 +1,51 @@
+#ifndef MODULEINFO_H
+#define MODULEINFO_H
+
+enum driverMajor { DRIVER_NONE = 0, DRIVER_SCSI, DRIVER_NET, DRIVER_CDROM,
+ DRIVER_PCMCIA, DRIVER_FS, DRIVER_OTHER = 1000};
+enum driverMinor { DRIVER_MINOR_NONE = 0, DRIVER_MINOR_ETHERNET,
+ DRIVER_MINOR_PLIP, DRIVER_MINOR_TR };
+
+struct moduleArg {
+ char * arg;
+ char * description;
+};
+
+#define MI_FLAG_NOMISCARGS (1 << 0)
+
+struct moduleInfo {
+ char * moduleName;
+ char * description;
+ enum driverMajor major;
+ enum driverMinor minor;
+ int numArgs;
+ struct moduleArg * args;
+ int flags;
+ void * locationID;
+};
+
+struct moduleInfoSet_s {
+ struct moduleInfo * moduleList;
+ int numModules;
+};
+
+struct moduleBallLocation {
+ char * path; /* path to module ball that this driver is from. if NULL,
+ * implies /modules/modules.cgz */
+ char * title; /* title used for driver disk -- may be NULL */
+};
+
+typedef struct moduleInfoSet_s * moduleInfoSet;
+
+moduleInfoSet newModuleInfoSet(void);
+void freeModuleInfoSet(moduleInfoSet mis);
+int readModuleInfo(const char * filename, moduleInfoSet mis, void * path, int override);
+struct moduleInfo * findModuleInfo(moduleInfoSet mis,
+ const char * moduleName);
+
+/* NULL moduleName indicates the end of the list; the list must be freed() */
+struct moduleInfo * getModuleList(moduleInfoSet mis,
+ enum driverMajor major);
+
+
+#endif
diff --git a/loader2/modules.c b/loader2/modules.c
new file mode 100644
index 000000000..acd723a24
--- /dev/null
+++ b/loader2/modules.c
@@ -0,0 +1,595 @@
+/*
+ * modules.c - module loading functionality
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 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 <kudzu/kudzu.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "log.h"
+#include "modules.h"
+#include "modstubs.h"
+#include "windows.h"
+
+#include "../isys/cpio.h"
+
+static int mlModuleInList(const char * modName, moduleList list);
+static int mlWriteConfModules(moduleList list, int fd);
+static struct extractedModule * extractModules (char * const * modNames,
+ struct extractedModule * oldPaths,
+ struct moduleBallLocation * location);
+
+static int ethCount(void) {
+ int fd;
+ char buf[16384];
+ int i;
+ char * chptr;
+ int count = 0;
+
+ fd = open("/proc/net/dev", O_RDONLY);
+ i = read(fd, buf, sizeof(buf) - 1);
+ buf[i] = '\0';
+
+ /* skip first two header lines */
+ chptr = strchr(buf, '\n') + 1;
+ chptr = strchr(chptr, '\n') + 1;
+
+ while (chptr) {
+ while (*chptr && isspace(*chptr)) chptr++;
+ if (!strncmp(chptr, "eth", 3))
+ count++;
+ chptr = strchr(chptr, '\n');
+ if (chptr) chptr++;
+ }
+
+ return count;
+}
+
+static int scsiDiskCount(void) {
+ struct device ** devices, ** device;
+ int i = 0;
+
+ devices = probeDevices(CLASS_HD, BUS_SCSI, PROBE_ALL);
+
+ for (device = devices; *device; device++) i++;
+
+ return i;
+}
+
+int mlReadLoadedList(moduleList * mlp) {
+ int fd;
+ char * start;
+ char * end;
+ char buf[4096];
+ struct stat sb;
+ int i;
+ moduleList ml;
+
+ if ((fd = open("/proc/modules", O_RDONLY)) < 0)
+ return -1;
+
+ fstat(fd, &sb);
+ i = read(fd, buf, sizeof(buf));
+ buf[i] = '\0';
+ close(fd);
+
+ ml = malloc(sizeof(*ml));
+ ml->numModules = 0;
+
+ start = buf;
+ while (start && *start) {
+ end = start;
+ while (!isspace(*end) && *end != '\n') end++;
+ *end = '\0';
+ ml->mods[ml->numModules].name = strdup(start);
+ ml->mods[ml->numModules].args = NULL;
+ ml->mods[ml->numModules].path = NULL;
+ ml->mods[ml->numModules].weLoaded = 0;
+ *end = ' ';
+ ml->numModules++;
+ start = strchr(end, '\n');
+ if (start) start++;
+ }
+
+ *mlp = ml;
+
+ return 0;
+}
+
+/* this leaks memory if their is a loop in the modules. oh well. */
+char ** tsortModules(moduleList modLoaded, moduleDeps ml, char ** args,
+ int depth, char *** listPtr, int * listSizePtr) {
+ int listSize;
+ char ** list;
+ char ** next;
+ char ** deps;
+
+ if (!depth) {
+ int count;
+
+ listSize = 5;
+ list = malloc((listSize + 1) * sizeof(*list));
+ *list = NULL;
+
+ listPtr = &list;
+ listSizePtr = &listSize;
+
+ for (deps = args, count = 0; *deps; deps++, count++);
+ } else {
+ list = *listPtr;
+ listSize = *listSizePtr;
+ }
+
+ if (depth++ > 100) {
+ return NULL;
+ }
+
+ while (*args) {
+ /* don't load it twice */
+ next = list;
+ while (*next && strcmp(*next, *args)) next++;
+
+ if (*next || mlModuleInList(*args, modLoaded)) {
+ args++;
+ continue;
+ }
+
+ /* load everything this depends on */
+ deps = mlGetDeps(ml, *args);
+ if (deps) {
+ if (!tsortModules(modLoaded, ml, deps, depth,
+ listPtr, listSizePtr))
+ return NULL;
+
+ list = *listPtr;
+ listSize = *listSizePtr;
+ }
+
+ /* add this to the list */
+ next = list;
+ while (*next) next++;
+
+ if ((next - list) >= listSize) {
+ int count = next - list;
+
+ listSize += 10;
+ /* leave room for a NULL */
+ list = realloc(list, sizeof(*list) * (listSize + 1));
+
+ *listSizePtr = listSize;
+ *listPtr = list;
+
+ next = list + count;
+ }
+
+ next[0] = *args;
+ next[1] = NULL;
+
+ args++;
+ }
+
+ return list;
+}
+
+static int mlModuleInList(const char * modName, moduleList list) {
+ int i;
+
+ if (!list) return 0;
+
+ for(i = 0; i < list->numModules; i++)
+ if (!strcmp(list->mods[i].name, modName)) return 1;
+
+ return 0;
+}
+
+/* load a single module. this is the real workhorse of loading modules */
+static int loadModule(const char * modName, struct extractedModule * path,
+ moduleList modLoaded, char ** args,
+ moduleInfoSet modInfo, int flags) {
+ char fileName[300];
+ char ** argPtr, ** newArgs, ** arg;
+ struct moduleInfo * mi = NULL;
+ int deviceCount = -1;
+ int popWindow = 0;
+ int rc, child, i, status;
+
+ /* don't need to load a module that's already loaded */
+ if (mlModuleInList(modName, modLoaded))
+ return 0;
+
+ if (modInfo && (mi = findModuleInfo(modInfo, modName))) {
+ if (mi->major == DRIVER_NET && mi->minor == DRIVER_MINOR_ETHERNET) {
+ deviceCount = ethCount();
+ }
+
+ if (mi->major == DRIVER_SCSI) {
+ startNewt(flags);
+ scsiWindow(modName);
+ popWindow = 1;
+ }
+ }
+
+ sprintf(fileName, "%s.o", modName);
+ for (argPtr = args; argPtr && *argPtr; argPtr++) {
+ strcat(fileName, " ");
+ strcat(fileName, *argPtr);
+ }
+
+ if (FL_TESTING(flags)) {
+ logMessage("would have insmod %s (%s)", path, fileName);
+ rc = 0;
+ } else {
+ if (!(child = fork())) {
+ int fd = open("/dev/tty3", O_RDWR);
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+
+ rc = insmod(path->path, NULL, args);
+ _exit(rc);
+ }
+
+ waitpid(child, &status, 0);
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ rc = 1;
+ } else {
+ rc = 0;
+ }
+ }
+
+ if (!rc) {
+ int num = modLoaded->numModules;
+
+ modLoaded->mods[num].name = strdup(modName);
+ modLoaded->mods[num].weLoaded = 1;
+ modLoaded->mods[num].path =
+ path->location ? strdup(path->location) : NULL;
+ modLoaded->mods[num].firstDevNum = -1;
+ modLoaded->mods[num].lastDevNum = -1;
+ modLoaded->mods[num].written = 0;
+
+ if (mi) {
+ modLoaded->mods[num].major = mi->major;
+ modLoaded->mods[num].minor = mi->minor;
+
+ if (deviceCount >= 0) {
+ if (mi->major == DRIVER_NET) {
+ modLoaded->mods[num].firstDevNum = deviceCount;
+ modLoaded->mods[num].firstDevNum = ethCount() - 1;
+ } else if (mi->major == DRIVER_SCSI) {
+ modLoaded->mods[num].firstDevNum = deviceCount;
+ modLoaded->mods[num].firstDevNum = scsiDiskCount() - 1;
+ }
+ }
+ } else {
+ modLoaded->mods[num].major = DRIVER_NONE;
+ modLoaded->mods[num].minor = DRIVER_MINOR_NONE;
+ }
+
+ if (args) {
+ for (i=0, arg = args; *arg; arg++, i++);
+ newArgs = malloc(sizeof(*newArgs) * (i + 1));
+ for (i = 0, arg = args; *arg; arg++, i++)
+ newArgs[i] = strdup(*arg);
+ newArgs[i] = NULL;
+ } else {
+ newArgs = NULL;
+ }
+
+ modLoaded->mods[modLoaded->numModules++].args = newArgs;
+ }
+
+ if (popWindow) {
+ sleep(1);
+ newtPopWindow();
+ }
+
+ return rc;
+}
+
+/* handle loading a set of modules including their dependencies. also has
+ * a nasty evil hack for handling usb-storage removal/reloading for scsi
+ * device ordering. */
+/* JKFIXME: the location argument is a hack to handle modules
+ * without module-info that I know need to be loaded from other than
+ * /modules/modules.cgz. should module-info be extended to cover
+ * *ALL* modules? this would probably want for auto module-info generation */
+static int doLoadModules(const char * origModNames, moduleList modLoaded,
+ moduleDeps modDeps, moduleInfoSet modInfo,
+ int flags, const char * argModule, char ** args,
+ struct moduleBallLocation * modLocation) {
+ char * modNames;
+ char * start, * next, * end;
+ char ** initialList;
+ char ** list, ** l;
+ char items[1024] = ""; /* 1024 characters should be enough... */
+ struct extractedModule * paths, * p;
+ struct moduleBallLocation *location = NULL;
+ int i;
+ int reloadUsbStorage;
+
+ struct moduleInfo * mi;
+
+ start = modNames = alloca(strlen(origModNames) + 1);
+ strcpy(modNames, origModNames);
+
+ next = start;
+ i = 1;
+ while (*next) {
+ if (*next == ':') i++;
+ next++;
+ }
+
+ initialList = alloca(sizeof(*initialList) * (i + 1));
+
+ i = 0;
+ while (start) {
+ next = end = strchr(start, ':');
+ if (next) {
+ *end = '\0';
+ next++;
+ }
+
+ if (mlModuleInList(start, modLoaded)) {
+ /* already loaded, we don't need to load it again */
+ start = next;
+ continue;
+ }
+
+ initialList[i++] = start;
+ start = next;
+ }
+
+ initialList[i] = NULL;
+
+ list = tsortModules(modLoaded, modDeps, initialList, 0, NULL, NULL);
+ if (!list) {
+ logMessage("ERROR: loop in module dependencies; not inserting");
+ return 1;
+ }
+
+ for (i = 0; list[i]; i++) {
+ strcat(items, " ");
+ strcat(items, list[i]);
+ }
+
+ logMessage("modules to insert%s", items);
+
+ paths = NULL;
+ reloadUsbStorage = 0;
+ if (modInfo) {
+ for (i = 0; list[i]; i++) {
+ mi = findModuleInfo(modInfo, list[i]);
+
+ if (mi && mi->locationID) {
+ location = mi->locationID;
+ }
+
+ if (mi && mi->major == DRIVER_SCSI) {
+ reloadUsbStorage = 1;
+ }
+ }
+ }
+
+ /* JKFIXME: this is a hack to handle an explicit location for modules */
+ if (!location && modLocation)
+ location = modLocation;
+
+ /* JKFIXME: do something to extract the modules */
+ paths = extractModules(list, paths, location);
+
+ i = 0;
+ if (!paths) {
+ logMessage("no modules found -- aborting insertion");
+ return i;
+ }
+
+ *items = '\0';
+ for (l = list, p = paths; *l && p; l++, p++) {
+ if (!p->path) {
+ if (*items) strcat(items, " ");
+ strcat(items, *l);
+ i++;
+ }
+ }
+
+ if (*items) logMessage("module(s) %s not found", items);
+
+ if (reloadUsbStorage) {
+ /* JKFIXME: here are the big hacks... for now, just described.
+ * 1) figure out which scsi devs are claimed by usb-storage.
+ * if lastScsiDev == usb-storage->lastDev,
+ * lastScsiDev = usb->firstDev. else, log that we're screwed.
+ * 2) if stage2 is cdrom and mounted, umount stage2, umount cdrom
+ * 3) rmmod usb-storage
+ */
+ }
+
+ /* insert the modules now */
+
+ for(l = list, p = paths; paths && *l; l++, p++) {
+ if (!p->path)
+ /* no path for this module */
+ continue;
+ if (loadModule(*l, p, modLoaded,
+ (argModule && !strcmp(argModule, *l)) ? args : NULL,
+ modInfo, flags)) {
+ logMessage("failed to insert %s", *p);
+ } else {
+ logMessage("inserted %s", p->path);
+ }
+ }
+
+ if (reloadUsbStorage) {
+ /* JKFIXME: here's the rest of the hacks. basically do the reverse
+ * of what we did before.
+ */
+ }
+
+ if (!FL_TESTING(flags)) {
+ int fd;
+
+ fd = open("/tmp/modules.conf", O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd == -1) {
+ logMessage("error appending to /tmp/modules.conf: %s\n",
+ strerror(errno));
+ } else {
+ mlWriteConfModules(modLoaded, fd);
+ close(fd);
+ }
+ }
+
+ for (p = paths; p->path; p++) {
+ unlink(p->path);
+ free(p->path);
+ if (p->location) free(p->location);
+ }
+
+ free(paths);
+ free(list);
+
+ logMessage("load module set done");
+
+ return i;
+}
+
+/* loads a : separated list of modules. the arg only applies to the
+ first module in the list */
+int mlLoadModuleSet(const char * modNames,
+ moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ return doLoadModules(modNames, modLoaded, modDeps, modInfo,
+ flags, NULL, NULL, NULL);
+}
+
+/* like mlLoadModuleSet but from an explicit location */
+/* JKFIXME: this is a hack */
+int mlLoadModuleSetLocation(const char * modNames,
+ moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags,
+ struct moduleBallLocation * location) {
+ return doLoadModules(modNames, modLoaded, modDeps, modInfo,
+ flags, NULL, NULL, location);
+}
+
+static int mlWriteConfModules(moduleList list, int fd) {
+ /* JKFIXME: add code to do stuff here... */
+ return 0;
+}
+
+/* JKFIXME: needs a way to know about module locations. also, we should
+ * extract them to a ramfs instead of /tmp */
+static struct extractedModule * extractModules (char * const * modNames,
+ struct extractedModule * oldPaths,
+ struct moduleBallLocation * location) {
+
+ gzFile fd;
+ char * ballPath;
+ struct cpioFileMapping * map;
+ int i, numMaps, rc;
+ char * const * m;
+ char fn[255];
+ const char * failedFile;
+ struct stat sb;
+ struct utsname u;
+
+ uname(&u);
+
+ /* JKFIXME: handle driver disk path somehow */
+ if (!location)
+ ballPath = strdup("/modules/modules.cgz");
+ else
+ ballPath = strdup(location->path);
+
+ fd = gunzip_open(ballPath);
+ if (!fd) {
+ logMessage("failed to open %s", ballPath);
+ free(ballPath);
+ return NULL;
+ }
+
+ for(m = modNames, i = 0; *m; i++, m++);
+
+ map = alloca(sizeof(*map) * i);
+ memset(map, 0, sizeof(*map) * i);
+
+ if (!oldPaths)
+ /* +1 NULL to terminate the list */
+ oldPaths = calloc(i + 1, sizeof(*oldPaths));
+
+ for (m = modNames, i = 0, numMaps = 0; *m; m++, i++) {
+ /* if we don't know the path of this module yet, "figure" it out */
+ if (!oldPaths[i].path) {
+ map[numMaps].archivePath = alloca(strlen(u.release) +
+ strlen(*m) + 25);
+ sprintf(map[numMaps].archivePath, "%s/%s.o", u.release, *m);
+ map[numMaps].fsPath = alloca(10 + strlen(*m));
+ sprintf(map[numMaps].fsPath, "/tmp/%s.o", *m);
+ unlink(map[numMaps].fsPath);
+ map[numMaps].mapFlags = CPIO_MAP_PATH;
+ numMaps++;
+ }
+ }
+
+ if (!numMaps) {
+ gunzip_close(fd);
+ free(ballPath);
+ return oldPaths;
+ }
+
+ qsort(map, numMaps, sizeof(*map), myCpioFileMapCmp);
+ rc = myCpioInstallArchive(fd, map, numMaps, NULL, NULL, &failedFile);
+
+ gunzip_close(fd);
+
+ for (m = modNames, i = 0, numMaps = 0; *m; m++, i++) {
+ if (!oldPaths[i].path) {
+ sprintf(fn, "/tmp/%s.o", modNames[i]);
+ if (!stat(fn, &sb)) {
+ oldPaths[i].path = strdup(fn);
+ /* JKFIXME: this is copied from the old stuff -- do we really need it? */
+ if (location && location->path) {
+ oldPaths[i].location = strdup(location->path);
+ if (location->title)
+ logMessage("module %s found on driver disk %s",
+ modNames[i], location->title);
+ logMessage("loaded %s from %s", modNames[i],
+ location->path);
+ } else
+ logMessage("loaded %s from /modules/modules.cgz", modNames[i]);
+ }
+ numMaps++;
+ }
+ }
+
+ free(ballPath);
+ return oldPaths;
+}
diff --git a/loader2/modules.h b/loader2/modules.h
new file mode 100644
index 000000000..9e055ee84
--- /dev/null
+++ b/loader2/modules.h
@@ -0,0 +1,43 @@
+#ifndef H_MODULES
+#define H_MODULES
+
+#include "moduleinfo.h"
+#include "moduledeps.h"
+
+typedef struct moduleList_s * moduleList;
+
+struct loadedModuleInfo {
+ char * name;
+ char ** args;
+ int weLoaded;
+ int written;
+ char * path;
+ int firstDevNum, lastDevNum; /* only used for ethernet currently */
+ enum driverMajor major;
+ enum driverMinor minor;
+};
+
+struct extractedModule {
+ char * path;
+ char * location;
+};
+
+struct moduleList_s {
+ struct loadedModuleInfo mods[50];
+ int numModules;
+};
+
+int mlReadLoadedList(moduleList * mlp);
+int mlLoadModuleSet(const char * modNames,
+ moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags);
+/* like mlLoadModuleSet but from an explicit location */
+/* JKFIXME: this is a hack */
+int mlLoadModuleSetLocation(const char * modNames,
+ moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags,
+ struct moduleBallLocation * location);
+
+
+
+#endif
diff --git a/loader2/net.c b/loader2/net.c
new file mode 100644
index 000000000..ebbbbe116
--- /dev/null
+++ b/loader2/net.c
@@ -0,0 +1,704 @@
+/*
+ * Copyright 1999-2001 Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Red Hat shall not be
+ * used in advertising or otherwise to promote the sale, use or other dealings
+ * in this Software without prior written authorization from Red Hat.
+ *
+ */
+
+/* JKFIXME: clean this file up to get rid of crappy __standalone__ defines */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <popt.h>
+#include <resolv.h>
+#include <net/if.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+
+# include "../isys/dns.h"
+
+#include "lang.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "log.h"
+#include "net.h"
+#include "windows.h"
+
+char *netServerPrompt = \
+ N_("Please enter the following information:\n"
+ "\n"
+ " o the name or IP number of your %s server\n"
+ " o the directory on that server containing\n"
+ " %s for your architecture\n");
+
+struct intfconfig_s {
+ newtComponent ipEntry, nmEntry, gwEntry, nsEntry;
+ char * ip, * nm, * gw, * ns;
+};
+
+typedef int int32;
+
+static void ipCallback(newtComponent co, void * dptr) {
+ struct intfconfig_s * data = dptr;
+ struct in_addr ipaddr, nmaddr, addr;
+ char * ascii;
+ int broadcast, network;
+
+ if (co == data->ipEntry) {
+ if (strlen(data->ip) && !strlen(data->nm)) {
+ if (inet_aton(data->ip, &ipaddr)) {
+ ipaddr.s_addr = ntohl(ipaddr.s_addr);
+ ascii = "255.255.255.0";
+ newtEntrySet(data->nmEntry, ascii, 1);
+ }
+ }
+ } else if (co == data->nmEntry) {
+ if (!strlen(data->ip) || !strlen(data->nm)) return;
+ if (!inet_aton(data->ip, &ipaddr)) return;
+ if (!inet_aton(data->nm, &nmaddr)) return;
+
+ network = ipaddr.s_addr & nmaddr.s_addr;
+ broadcast = (ipaddr.s_addr & nmaddr.s_addr) | (~nmaddr.s_addr);
+
+ if (!strlen(data->gw)) {
+ addr.s_addr = htonl(ntohl(broadcast) - 1);
+ newtEntrySet(data->gwEntry, inet_ntoa(addr), 1);
+ }
+
+ if (!strlen(data->ns)) {
+ addr.s_addr = htonl(ntohl(network) + 1);
+ newtEntrySet(data->nsEntry, inet_ntoa(addr), 1);
+ }
+ }
+}
+
+static void fillInIpInfo(struct networkDeviceConfig * cfg) {
+ int32 * i;
+ char * nm;
+
+ if (!(cfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)) {
+ i = (int32 *) &cfg->dev.ip;
+
+ nm = "255.255.255.0";
+
+ inet_aton(nm, &cfg->dev.netmask);
+ cfg->dev.set |= PUMP_INTFINFO_HAS_NETMASK;
+ }
+
+ if (!(cfg->dev.set & PUMP_INTFINFO_HAS_BROADCAST)) {
+ *((int32 *) &cfg->dev.broadcast) = (*((int32 *) &cfg->dev.ip) &
+ *((int32 *) &cfg->dev.netmask)) |
+ ~(*((int32 *) &cfg->dev.netmask));
+ cfg->dev.set |= PUMP_INTFINFO_HAS_BROADCAST;
+ }
+
+ if (!(cfg->dev.set & PUMP_INTFINFO_HAS_NETWORK)) {
+ *((int32 *) &cfg->dev.network) =
+ *((int32 *) &cfg->dev.ip) &
+ *((int32 *) &cfg->dev.netmask);
+ cfg->dev.set |= PUMP_INTFINFO_HAS_NETWORK;
+ }
+}
+
+void initLoopback(void) {
+ struct pumpNetIntf dev;
+
+ strcpy(dev.device, "lo");
+ inet_aton("127.0.0.1", &dev.ip);
+ inet_aton("255.0.0.0", &dev.netmask);
+ inet_aton("127.0.0.0", &dev.network);
+ dev.set = PUMP_INTFINFO_HAS_NETMASK | PUMP_INTFINFO_HAS_IP
+ | PUMP_INTFINFO_HAS_NETWORK;
+
+ pumpSetupInterface(&dev);
+}
+
+static void dhcpBoxCallback(newtComponent co, void * ptr) {
+ struct intfconfig_s * c = ptr;
+
+ newtEntrySetFlags(c->ipEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
+ newtEntrySetFlags(c->gwEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
+ newtEntrySetFlags(c->nmEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
+ newtEntrySetFlags(c->nsEntry, NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE);
+}
+
+static int getDnsServers(struct networkDeviceConfig * cfg) {
+ int rc;
+ char * ns = "";
+ struct newtWinEntry entry[] = { { N_("Nameserver IP"), &ns, 0 },
+ { NULL, NULL, 0 } };
+
+ do {
+ rc = newtWinEntries(_("Nameserver"),
+ _("Your dynamic IP request returned IP configuration "
+ "information, but it did not include a DNS nameserver. "
+ "If you know what your nameserver is, please enter it "
+ "now. If you don't have this information, you can leave "
+ "this field blank and the install will continue."),
+ 40, 5, 10, 25, entry, _("OK"), _("Back"), NULL);
+
+ if (rc == 2) return LOADER_BACK;
+
+ if (ns && *ns && !inet_aton(ns, &cfg->dev.dnsServers[0])) {
+ newtWinMessage(_("Invalid IP Information"), _("Retry"),
+ _("You entered an invalid IP address."));
+ rc = 2;
+ }
+
+ } while (rc == 2);
+
+ cfg->dev.set |= PUMP_NETINFO_HAS_DNS;
+ cfg->dev.numDns = 1;
+
+ return LOADER_OK;
+}
+
+int readNetConfig(char * device, struct networkDeviceConfig * cfg, int flags) {
+ newtComponent text, f, okay, back, answer, dhcpCheckbox;
+ newtGrid grid, subgrid, buttons;
+ struct networkDeviceConfig newCfg;
+ struct intfconfig_s c;
+ int i;
+ struct in_addr addr;
+ char dhcpChoice;
+ char * chptr;
+
+ /* JKFIXME: I do NOT like this crap */
+#if !defined(__s390__) && !defined(__s390x__)
+ text = newtTextboxReflowed(-1, -1,
+ _("Please enter the IP configuration for this machine. Each "
+ "item should be entered as an IP address in dotted-decimal "
+ "notation (for example, 1.2.3.4)."), 50, 5, 10, 0);
+
+ subgrid = newtCreateGrid(2, 4);
+ newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("IP address:")),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("Netmask:")),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 0, 2, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("Default gateway (IP):")),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 0, 3, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("Primary nameserver:")),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+ c.ipEntry = newtEntry(-1, -1, NULL, 16, &c.ip, 0);
+ c.nmEntry = newtEntry(-1, -1, NULL, 16, &c.nm, 0);
+ c.gwEntry = newtEntry(-1, -1, NULL, 16, &c.gw, 0);
+ c.nsEntry = newtEntry(-1, -1, NULL, 16, &c.ns, 0);
+
+ if (!cfg->isDynamic) {
+ if (cfg->dev.set & PUMP_INTFINFO_HAS_IP)
+ newtEntrySet(c.ipEntry, inet_ntoa(cfg->dev.ip), 1);
+
+ if (cfg->dev.set & PUMP_INTFINFO_HAS_NETMASK)
+ newtEntrySet(c.nmEntry, inet_ntoa(cfg->dev.netmask), 1);
+
+ if (cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)
+ newtEntrySet(c.gwEntry, inet_ntoa(cfg->dev.gateway), 1);
+
+ if (cfg->dev.numDns)
+ newtEntrySet(c.nsEntry, inet_ntoa(cfg->dev.dnsServers[0]), 1);
+
+ dhcpChoice = ' ';
+ } else {
+ dhcpChoice = '*';
+ }
+
+ dhcpCheckbox = newtCheckbox(-1, -1,
+ _("Use dynamic IP configuration (BOOTP/DHCP)"),
+ dhcpChoice, NULL, &dhcpChoice);
+ newtComponentAddCallback(dhcpCheckbox, dhcpBoxCallback, &c);
+ if (dhcpChoice == '*') dhcpBoxCallback(dhcpCheckbox, &c);
+
+ newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, c.ipEntry,
+ 1, 0, 0, 0, 0, 0);
+ newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, c.nmEntry,
+ 1, 0, 0, 0, 0, 0);
+ newtGridSetField(subgrid, 1, 2, NEWT_GRID_COMPONENT, c.gwEntry,
+ 1, 0, 0, 0, 0, 0);
+ newtGridSetField(subgrid, 1, 3, NEWT_GRID_COMPONENT, c.nsEntry,
+ 1, 0, 0, 0, 0, 0);
+
+ buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
+
+ grid = newtCreateGrid(1, 4);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 1, 0, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, dhcpCheckbox,
+ 0, 0, 0, 1, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, subgrid,
+ 0, 0, 0, 1, 0, 0);
+ newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
+ 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ f = newtForm(NULL, NULL, 0);
+ newtGridAddComponentsToForm(grid, f, 1);
+ newtGridWrappedWindow(grid, _("Configure TCP/IP"));
+ newtGridFree(grid, 1);
+
+ newtComponentAddCallback(c.ipEntry, ipCallback, &c);
+ newtComponentAddCallback(c.nmEntry, ipCallback, &c);
+
+ do {
+ answer = newtRunForm(f);
+
+ if (answer == back) {
+ newtFormDestroy(f);
+ newtPopWindow();
+ return LOADER_BACK;
+ }
+
+ if (dhcpChoice == ' ') {
+ i = 0;
+ memset(&newCfg, 0, sizeof(newCfg));
+ if (*c.ip && inet_aton(c.ip, &addr)) {
+ i++;
+ newCfg.dev.ip = addr;
+ newCfg.dev.set |= PUMP_INTFINFO_HAS_IP;
+ }
+
+ if (*c.nm && inet_aton(c.nm, &addr)) {
+ i++;
+ newCfg.dev.netmask = addr;
+ newCfg.dev.set |= PUMP_INTFINFO_HAS_NETMASK;
+ }
+
+ if (i != 2) {
+ newtWinMessage(_("Missing Information"), _("Retry"),
+ _("You must enter both a valid IP address and a "
+ "netmask."));
+ }
+
+ strcpy(newCfg.dev.device, device);
+ newCfg.isDynamic = 0;
+ } else {
+ if (!FL_TESTING(flags)) {
+ winStatus(50, 3, _("Dynamic IP"),
+ _("Sending request for IP information..."),
+ 0);
+ chptr = pumpDhcpRun(device, 0, 0, NULL, &newCfg.dev, NULL);
+ newtPopWindow();
+ } else {
+ chptr = NULL;
+ }
+
+ if (!chptr) {
+ newCfg.isDynamic = 1;
+ if (!(newCfg.dev.set & PUMP_NETINFO_HAS_DNS)) {
+ logMessage("pump worked, but didn't return a DNS server");
+ i = getDnsServers(&newCfg);
+ i = i ? 0 : 2;
+ } else {
+ i = 2;
+ }
+ } else {
+ logMessage("pump told us: %s", chptr);
+ i = 0;
+ }
+ }
+ } while (i != 2);
+
+#else /* s390 now */
+ char * env;
+ /* quick and dirty hack by opaukstadt@millenux.com for s390 */
+ /* ctc stores remoteip in broadcast-field until pump.h is changed */
+ memset(&newCfg, 0, sizeof(newCfg));
+ strcpy(newCfg.dev.device, device);
+ newCfg.isDynamic = 0;
+ env = getenv("IPADDR");
+ if (env && *env) {
+ if(inet_aton(env, &newCfg.dev.ip))
+ newCfg.dev.set |= PUMP_INTFINFO_HAS_IP;
+ }
+ env = getenv("NETMASK");
+ if (env && *env) {
+ if(inet_aton(env, &newCfg.dev.netmask))
+ newCfg.dev.set |= PUMP_INTFINFO_HAS_NETMASK;
+ }
+ env = getenv("GATEWAY");
+ if (env && *env) {
+ if(inet_aton(env, &newCfg.dev.gateway))
+ newCfg.dev.set |= PUMP_NETINFO_HAS_GATEWAY;
+ }
+ env = getenv("NETWORK");
+ if (env && *env) {
+ if(inet_aton(env, &newCfg.dev.network))
+ newCfg.dev.set |= PUMP_INTFINFO_HAS_NETWORK;
+ }
+ env = getenv("DNS");
+ if (env && *env) {
+ char *s = strdup (env);
+ char *t = strtok (s, ":");
+ if(inet_aton((t? t : s), &newCfg.dev.dnsServers[0]))
+ newCfg.dev.set |= PUMP_NETINFO_HAS_DNS;
+ }
+ if (!strncmp(newCfg.dev.device, "ctc", 3)) {
+ env = getenv("REMIP");
+ if (env && *env) {
+ if(inet_aton(env, &newCfg.dev.gateway))
+ newCfg.dev.set |= PUMP_NETINFO_HAS_GATEWAY;
+ }
+ }
+ env = getenv("BROADCAST");
+ if (env && *env) {
+ if(inet_aton(env, &newCfg.dev.broadcast))
+ newCfg.dev.set |= PUMP_INTFINFO_HAS_BROADCAST;
+ }
+#endif /* s390 */
+
+ cfg->isDynamic = newCfg.isDynamic;
+ memcpy(&cfg->dev,&newCfg.dev,sizeof(newCfg.dev));
+
+ fillInIpInfo(cfg);
+
+#if !defined(__s390__) && !defined(__s390x__)
+ if (!(cfg->dev.set & PUMP_NETINFO_HAS_GATEWAY)) {
+ if (*c.gw && inet_aton(c.gw, &addr)) {
+ cfg->dev.gateway = addr;
+ cfg->dev.set |= PUMP_NETINFO_HAS_GATEWAY;
+ }
+ }
+
+ if (!(cfg->dev.numDns)) {
+ if (*c.ns && inet_aton(c.ns, &addr)) {
+ cfg->dev.dnsServers[0] = addr;
+ cfg->dev.numDns = 1;
+ }
+ }
+
+ newtPopWindow();
+#endif
+ if (!FL_TESTING(flags)) {
+ configureNetwork(cfg);
+ findHostAndDomain(cfg, flags);
+ writeResolvConf(cfg);
+ }
+
+ return 0;
+}
+
+int configureNetwork(struct networkDeviceConfig * dev) {
+#if !defined(__s390__) && !defined(__s390x__)
+ pumpSetupInterface(&dev->dev);
+
+ if (dev->dev.set & PUMP_NETINFO_HAS_GATEWAY)
+ pumpSetupDefaultGateway(&dev->dev.gateway);
+
+#endif
+ return 0;
+}
+
+int writeNetInfo(const char * fn, struct networkDeviceConfig * dev,
+ struct knownDevices * kd) {
+ FILE * f;
+ int i;
+
+ for (i = 0; i < kd->numKnown; i++)
+ if (!strcmp(kd->known[i].name, dev->dev.device)) break;
+
+ if (!(f = fopen(fn, "w"))) return -1;
+
+ fprintf(f, "DEVICE=%s\n", dev->dev.device);
+
+ /* JKFIXME: this used kd->known[i].code == CODE_PCMCIA to toggle onboot */
+ fprintf(f, "ONBOOT=yes\n");
+
+ if (dev->isDynamic) {
+ fprintf(f, "BOOTPROTO=dhcp\n");
+ } else {
+ fprintf(f, "BOOTPROTO=static\n");
+ fprintf(f, "IPADDR=%s\n", inet_ntoa(dev->dev.ip));
+ fprintf(f, "NETMASK=%s\n", inet_ntoa(dev->dev.netmask));
+ if (dev->dev.set & PUMP_NETINFO_HAS_GATEWAY) {
+ fprintf(f, "GATEWAY=%s\n", inet_ntoa(dev->dev.gateway));
+ if (!strncmp(dev->dev.device, "ctc", 3) || \
+ !strncmp(dev->dev.device, "iucv", 4))
+ fprintf(f, "REMIP=%s\n", inet_ntoa(dev->dev.gateway));
+ }
+ if (dev->dev.set & PUMP_INTFINFO_HAS_BROADCAST)
+ fprintf(f, "BROADCAST=%s\n", inet_ntoa(dev->dev.broadcast));
+ }
+
+ if (dev->dev.set & PUMP_NETINFO_HAS_HOSTNAME)
+ fprintf(f, "HOSTNAME=%s\n", dev->dev.hostname);
+ if (dev->dev.set & PUMP_NETINFO_HAS_DOMAIN)
+ fprintf(f, "DOMAIN=%s\n", dev->dev.domain);
+
+ fclose(f);
+
+ return 0;
+}
+
+int writeResolvConf(struct networkDeviceConfig * net) {
+ char * filename = "/etc/resolv.conf";
+ FILE * f;
+ int i;
+#if defined(__s390__) || defined(__s390x__)
+ return 0;
+#endif
+
+ if (!(net->dev.set & PUMP_NETINFO_HAS_DOMAIN) && !net->dev.numDns)
+ return LOADER_ERROR;
+
+ f = fopen(filename, "w");
+ if (!f) {
+ logMessage("Cannot create %s: %s\n", filename, strerror(errno));
+ return LOADER_ERROR;
+ }
+
+ if (net->dev.set & PUMP_NETINFO_HAS_DOMAIN)
+ fprintf(f, "search %s\n", net->dev.domain);
+
+ for (i = 0; i < net->dev.numDns; i++)
+ fprintf(f, "nameserver %s\n", inet_ntoa(net->dev.dnsServers[i]));
+
+ fclose(f);
+
+ res_init(); /* reinit the resolver so DNS changes take affect */
+
+ return 0;
+}
+
+int findHostAndDomain(struct networkDeviceConfig * dev, int flags) {
+ char * name, * chptr;
+
+ if (!FL_TESTING(flags)) {
+ writeResolvConf(dev);
+ }
+
+ if (!(dev->dev.set & PUMP_NETINFO_HAS_HOSTNAME)) {
+ winStatus(40, 3, _("Hostname"),
+ _("Determining host name and domain..."));
+ name = mygethostbyaddr(inet_ntoa(dev->dev.ip));
+ newtPopWindow();
+
+ if (!name) {
+ logMessage("reverse name lookup failed");
+ return 1;
+ }
+
+ logMessage("reverse name lookup worked");
+
+ dev->dev.hostname = strdup(name);
+ dev->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
+ } else {
+ name = dev->dev.hostname;
+ }
+
+ if (!(dev->dev.set & PUMP_NETINFO_HAS_DOMAIN)) {
+ for (chptr = name; *chptr && (*chptr != '.'); chptr++) ;
+ if (*chptr == '.') {
+ if (dev->dev.domain) free(dev->dev.domain);
+ dev->dev.domain = strdup(chptr + 1);
+ dev->dev.set |= PUMP_NETINFO_HAS_DOMAIN;
+ }
+ }
+
+ return 0;
+}
+
+/* JKFIXME: kickstart not implemented yet */
+#if 0
+int kickstartNetwork(char ** devicePtr, struct networkDeviceConfig * netDev,
+ char * bootProto, int flags) {
+ char ** ksArgv;
+ int ksArgc;
+ int netSet, rc;
+ char * arg, * chptr;
+ char * kshostname=NULL;
+ poptContext optCon;
+ struct in_addr * parseAddress;
+ int noDns = 0;
+ char * device;
+ struct poptOption ksOptions[] = {
+ { "bootproto", '\0', POPT_ARG_STRING, &bootProto, 0 },
+ { "device", '\0', POPT_ARG_STRING, devicePtr, 0 },
+ { "gateway", '\0', POPT_ARG_STRING, NULL, 'g' },
+ { "ip", '\0', POPT_ARG_STRING, NULL, 'i' },
+ { "nameserver", '\0', POPT_ARG_STRING, NULL, 'n' },
+ { "netmask", '\0', POPT_ARG_STRING, NULL, 'm' },
+ { "nodns", '\0', POPT_ARG_NONE, &noDns, 0 },
+ { "hostname", '\0', POPT_ARG_STRING, NULL, 'h'},
+ { 0, 0, 0, 0, 0 }
+ };
+
+ if (!bootProto) {
+ if (ksGetCommand(KS_CMD_NETWORK, NULL, &ksArgc, &ksArgv)) {
+ /* This is for compatibility with RH 5.0 */
+ ksArgv = alloca(sizeof(*ksArgv) * 1);
+ ksArgv[0] = "network";
+ ksArgc = 1;
+ }
+
+ optCon = poptGetContext(NULL, ksArgc, (const char **) ksArgv, ksOptions, 0);
+ while ((rc = poptGetNextOpt(optCon)) >= 0) {
+ parseAddress = NULL;
+ netSet = 0;
+
+ arg = (char *) poptGetOptArg(optCon);
+
+ switch (rc) {
+ case 'g':
+ parseAddress = &netDev->dev.gateway;
+ netSet = PUMP_NETINFO_HAS_GATEWAY;
+ break;
+
+ case 'i':
+ parseAddress = &netDev->dev.ip;
+ netSet = PUMP_INTFINFO_HAS_IP;
+ break;
+
+ case 'n':
+ parseAddress = &netDev->dev.dnsServers[netDev->dev.numDns++];
+ netSet = PUMP_NETINFO_HAS_DNS;
+ break;
+
+ case 'm':
+ parseAddress = &netDev->dev.netmask;
+ netSet = PUMP_INTFINFO_HAS_NETMASK;
+ break;
+
+ case 'h':
+ if (kshostname)
+ free(kshostname);
+ kshostname = strdup(arg);
+ logMessage("netDev->dev.hostname = %s", kshostname);
+ break;
+ }
+
+ if (parseAddress && !inet_aton(arg, parseAddress)) {
+ logMessage("bad ip number in network command: %s", arg);
+ return -1;
+ }
+
+ netDev->dev.set |= netSet;
+ }
+
+ if (rc < -1) {
+ newtWinMessage(_("kickstart"), _("OK"),
+ _("bad argument to kickstart network command %s: %s"),
+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+ poptStrerror(rc));
+ } else {
+ poptFreeContext(optCon);
+ }
+ }
+
+ device = *devicePtr;
+
+ if (!bootProto)
+ bootProto = "dhcp";
+
+ if (!strcmp(bootProto, "dhcp") || !strcmp(bootProto, "bootp")) {
+ logMessage("sending dhcp request through device %s", device);
+ winStatus(50, 3, _("Dynamic IP"),
+ _("Sending request for IP information..."),
+ 0);
+
+ chptr = pumpDhcpRun(device, 0, 0, NULL, &netDev->dev, NULL);
+ newtPopWindow();
+ if (chptr) {
+ logMessage("pump told us: %s", chptr);
+ return -1;
+ }
+ netDev->isDynamic = 1;
+ } else if (!strcmp(bootProto, "static")) {
+ strcpy(netDev->dev.device, device);
+ } else if (!strcmp(bootProto, "query")) {
+ strcpy(netDev->dev.device, device);
+ readNetConfig("eth0", netDev, flags);
+ } else {
+ newtWinMessage(_("kickstart"), _("OK"),
+ _("Bad bootproto %s specified in network command"),
+ bootProto);
+ return -1;
+ }
+
+ fillInIpInfo(netDev);
+ configureNetwork(netDev);
+
+ logMessage("nodns is %d", noDns);
+
+ if (kshostname) {
+ logMessage("setting ks specified hostname of %s", kshostname);
+ netDev->dev.hostname=strdup(kshostname);
+ netDev->dev.set |= PUMP_NETINFO_HAS_HOSTNAME;
+ }
+
+ if (!noDns)
+ findHostAndDomain(netDev, flags);
+
+ writeResolvConf(netDev);
+
+ return 0;
+}
+
+#endif /* 0 for no kickstart right now */
+
+
+
+int chooseNetworkInterface(struct knownDevices * kd, char ** devNamePtr,
+ int flags) {
+ int i, rc;
+ int deviceNums = 0;
+ int deviceNum;
+ char ** devices;
+
+ /* JKFIXME: this is a lot bigger than it has to be.. */
+ devices = alloca((kd->numKnown + 1) * sizeof(*devices));
+ for (i = 0; i < kd->numKnown; i++) {
+ if (kd->known[i].class != CLASS_NETWORK)
+ continue;
+
+ devices[deviceNums++] = kd->known[i].name;
+ }
+
+ devices[deviceNums] = NULL;
+
+ /* ASSERT: we should *ALWAYS* have a network device when we get here */
+ if (!deviceNums) {
+ logMessage("ASSERT: no network device in chooseNetworkInterface");
+ return LOADER_ERROR;
+ }
+
+ /* JKFIXME: if we only have one interface and it doesn't have link,
+ * do we go ahead? */
+ if (deviceNums == 1) {
+ *devNamePtr = devices[0];
+ return LOADER_NOOP;
+ }
+
+ startNewt(flags);
+
+ /* JKFIXME: should display link status */
+ deviceNum = 0;
+ rc = newtWinMenu(_("Networking Device"),
+ _("You have multiple network devices on this system. "
+ "Which would you like to install through?"), 40, 10, 10,
+ deviceNums < 6 ? deviceNums : 6, devices,
+ &deviceNum, _("OK"), _("Back"), NULL);
+ if (rc == 2)
+ return LOADER_BACK;
+
+ *devNamePtr = devices[deviceNum];
+
+ return LOADER_OK;
+}
diff --git a/loader2/net.h b/loader2/net.h
new file mode 100644
index 000000000..a7040f137
--- /dev/null
+++ b/loader2/net.h
@@ -0,0 +1,27 @@
+#ifndef H_LOADER_NET
+#define H_LOADER_NET
+
+#include "pump.h"
+#include "../isys/probe.h"
+
+struct networkDeviceConfig {
+ struct pumpNetIntf dev;
+ int isDynamic;
+};
+
+int readNetConfig(char * device, struct networkDeviceConfig * dev,
+ int flags);
+int configureNetwork(struct networkDeviceConfig * dev);
+int writeNetInfo(const char * fn, struct networkDeviceConfig * dev,
+ struct knownDevices * kd);
+int findHostAndDomain(struct networkDeviceConfig * dev, int flags);
+int writeResolvConf(struct networkDeviceConfig * net);
+extern char *netServerPrompt;
+int nfsGetSetup(char ** hostptr, char ** dirptr);
+int kickstartNetwork(char ** devicePtr, struct networkDeviceConfig * netDev,
+ char * bootProto, int flags);
+void initLoopback(void);
+int chooseNetworkInterface(struct knownDevices * kd, char ** devNamePtr,
+ int flags);
+
+#endif
diff --git a/loader2/nfsinstall.c b/loader2/nfsinstall.c
new file mode 100644
index 000000000..73073b834
--- /dev/null
+++ b/loader2/nfsinstall.c
@@ -0,0 +1,209 @@
+/*
+ * nfsinstall.c - code to set up nfs installs
+ *
+ * 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 <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "lang.h"
+#include "loadermisc.h"
+#include "log.h"
+#include "method.h"
+#include "net.h"
+
+#include "../isys/imount.h"
+
+int nfsGetSetup(char ** hostptr, char ** dirptr) {
+ struct newtWinEntry entries[3];
+ char * buf;
+ char * newServer = *hostptr ? strdup(*hostptr) : NULL;
+ char * newDir = *dirptr ? strdup(*dirptr) : NULL;
+ int rc;
+
+ entries[0].text = _("NFS server name:");
+ entries[0].value = &newServer;
+ entries[0].flags = NEWT_FLAG_SCROLL;
+ entries[1].text = _("Red Hat directory:");
+ entries[1].value = &newDir;
+ entries[1].flags = NEWT_FLAG_SCROLL;
+ entries[2].text = NULL;
+ entries[2].value = NULL;
+ buf = sdupprintf(_(netServerPrompt), "NFS", PRODUCTNAME);
+ rc = newtWinEntries(_("NFS Setup"), buf, 60, 5, 15,
+ 24, entries, _("OK"), _("Back"), NULL);
+ free(buf);
+
+ if (rc == 2) {
+ if (newServer) free(newServer);
+ if (newDir) free(newDir);
+ return LOADER_BACK;
+ }
+
+ if (*hostptr) free(*hostptr);
+ if (*dirptr) free(*dirptr);
+ *hostptr = newServer;
+ *dirptr = newDir;
+
+ return 0;
+}
+
+
+
+char * mountNfsImage(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDepsPtr, int flags) {
+ static struct networkDeviceConfig netDev;
+ char * devName = NULL;
+ char * host = NULL;
+ char * directory = NULL;
+ char * fullPath = NULL;
+ char * path;
+ char * url = NULL;
+
+ enum { NFS_STAGE_IFACE, NFS_STAGE_IP, NFS_STAGE_NFS,
+ NFS_STAGE_MOUNT, NFS_STAGE_DONE } stage = NFS_STAGE_IFACE;
+
+ int rc;
+ int dir = 1;
+
+ initLoopback();
+
+ memset(&netDev, 0, sizeof(netDev));
+ netDev.isDynamic = 1;
+
+ /* JKFIXME: ASSERT -- we have a network device when we get here */
+ while (stage != NFS_STAGE_DONE) {
+ switch (stage) {
+ case NFS_STAGE_IFACE:
+ logMessage("going to pick interface");
+ rc = chooseNetworkInterface(kd, &devName, flags);
+ if ((rc == LOADER_BACK) || (rc == LOADER_ERROR) ||
+ ((dir == -1) && (rc == LOADER_NOOP))) return NULL;
+
+ stage = NFS_STAGE_IP;
+ dir = 1;
+ break;
+
+ case NFS_STAGE_IP:
+ logMessage("going to do getNetConfig");
+ rc = readNetConfig(devName, &netDev, flags);
+ if (rc) {
+ stage = NFS_STAGE_IFACE;
+ dir = -1;
+ break;
+ }
+ stage = NFS_STAGE_NFS;
+ break;
+
+ case NFS_STAGE_NFS:
+ logMessage("going to do nfsGetSetup");
+ if (nfsGetSetup(&host, &directory) == LOADER_BACK) {
+ stage = NFS_STAGE_IP;
+ dir = -1;
+ break;
+ } else {
+ stage = NFS_STAGE_MOUNT;
+ dir = 1;
+ break;
+ }
+
+ case NFS_STAGE_MOUNT: {
+ int foundinvalid = 0;
+ char * buf;
+
+ if (FL_TESTING(flags)) {
+ stage = NFS_STAGE_DONE;
+ dir = 1;
+ break;
+ }
+
+ fullPath = alloca(strlen(host) + strlen(directory) + 2);
+ sprintf(fullPath, "%s:%s", host, directory);
+
+ logMessage("mounting nfs path %s", fullPath);
+
+ stage = NFS_STAGE_NFS;
+
+ if (!doPwMount(fullPath, "/mnt/source", "nfs", 1, 0, NULL, NULL)) {
+ logMessage("mounted %s on /mnt/source", fullPath);
+ if (!access("/mnt/source/RedHat/base/stage2.img", R_OK)) {
+ logMessage("can access stage2.img");
+ rc = mountStage2("/mnt/source/RedHat/base/stage2.img");
+ logMessage("after mountStage2, rc is %d", rc);
+ if (rc) {
+ umount("/mnt/source");
+ if (rc == -1) { foundinvalid = 1; logMessage("not the right one"); }
+ } else {
+ stage = NFS_STAGE_DONE;
+ url = "nfs://mnt/source/.";
+ break;
+ }
+ }
+ if ((path = validIsoImages("/mnt/source"))) {
+ copyUpdatesImg("/mnt/source/updates.img");
+
+ if (mountLoopback(path, "/mnt/source2", "loop1"))
+ logMessage("failed to mount iso %s loopback", path);
+ else {
+ rc = mountStage2("/mnt/source2/RedHat/base/stage2.img");
+ if (rc) {
+ umountLoopback("/mnt/source2", "loop1");
+ if (rc == -1) foundinvalid = 1;
+ } else {
+ queryIsoMediaCheck(path, flags);
+
+ stage = NFS_STAGE_DONE;
+ url = "nfsiso:/mnt/source";
+ break;
+ }
+ }
+ }
+
+ if (foundinvalid)
+ buf = sdupprintf(_("The %s installation tree in that "
+ "directory does not seem to match "
+ "your boot media."), PRODUCTNAME);
+ else
+ buf = sdupprintf(_("That directory does not seem to "
+ "contain a %s installation tree."),
+ PRODUCTNAME);
+ newtWinMessage(_("Error"), _("OK"), buf);
+ break;
+ } else {
+ newtWinMessage(_("Error"), _("OK"),
+ _("That directory could not be mounted from "
+ "the server."));
+ break;
+ }
+ }
+
+ case NFS_STAGE_DONE:
+ break;
+ }
+ }
+
+ writeNetInfo("/tmp/netinfo", &netDev, kd);
+ free(host);
+ free(directory);
+
+ return url;
+}
diff --git a/loader2/otherinsmod.c b/loader2/otherinsmod.c
new file mode 100644
index 000000000..881946533
--- /dev/null
+++ b/loader2/otherinsmod.c
@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#include "cpio.h"
+#include "isys.h"
+#include "stubs.h"
+
+/* hack */
+int combined_insmod_main(int argc, char ** argv);
+
+int ourInsmodCommand(int argc, char ** argv) {
+ char * file;
+ char finalName[100];
+ char * chptr;
+ gzFile fd;
+ int rc, rmObj = 0;
+ int sparc64 = 0, i;
+ char * ballPath = NULL;
+ char fullName[100];
+ struct utsname u;
+
+ uname(&u);
+
+#ifdef __sparc__
+ if (!strcmp(u.machine, "sparc64"))
+ sparc64 = 1;
+#endif
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: insmod [-p <path>] <module>.o [params]\n");
+ return 1;
+ }
+
+ if (!strcmp(argv[1], "-p")) {
+ ballPath = malloc(strlen(argv[2]) + 30);
+ sprintf(ballPath, "%s/%s", argv[2], sparc64 ?
+ "modules64.cgz" : "modules.cgz");
+ argv += 2;
+ argc -= 2;
+ } else {
+ ballPath = strdup(sparc64 ?
+ "/modules/modules64.cgz" :
+ "/modules/modules.cgz");
+
+ }
+
+ file = argv[1];
+
+ if (access(file, R_OK)) {
+ /* Try two balls on sparc64, one elsewhere */
+ for (i = 0; ; i++) {
+ /* it might be having a ball */
+ fd = gunzip_open(ballPath);
+ if (!fd) {
+ free(ballPath);
+ return 1;
+ }
+
+ chptr = strrchr(file, '/');
+ if (chptr) file = chptr + 1;
+ sprintf(finalName, "/tmp/%s", file);
+
+ sprintf(fullName, "%s/%s", u.release, file);
+
+ if (installCpioFile(fd, fullName, finalName, 0)) {
+ if (i < sparc64) {
+ ballPath[strlen(ballPath)-5] = '5';
+ continue;
+ }
+ free(ballPath);
+ return 1;
+ }
+
+ rmObj = 1;
+ file = finalName;
+ break;
+ }
+ }
+
+ free(ballPath);
+
+ argv[0] = "insmod";
+ argv[1] = file;
+
+ rc = combined_insmod_main(argc, argv);
+
+ if (rmObj) unlink(file);
+
+ return rc;
+}
+
+int rmmod(char * modName) {
+ pid_t child;
+ int status;
+ char * argv[] = { "/bin/rmmod", modName, NULL };
+ int argc = 2;
+ int rc = 0;
+
+ if ((child = fork()) == 0) {
+ exit(combined_insmod_main(argc, argv));
+ }
+
+ waitpid(child, &status, 0);
+
+ if (WIFEXITED(status))
+ rc = WEXITSTATUS(status);
+ else
+ rc = -1;
+
+ return rc;
+}
+
+int insmod(char * modName, char * path, char ** args) {
+ int argc;
+ char ** argv;
+ int rc = 0;
+ pid_t child;
+ int status;
+ int count;
+
+ argc = 0;
+ for (argv = args; argv && *argv; argv++, argc++);
+
+ argv = alloca(sizeof(*argv) * (argc + 5));
+ argv[0] = "/bin/insmod";
+ count = 1;
+ if (path) {
+ argv[1] = "-p";
+ argv[2] = path;
+ count += 2;
+ }
+
+ argv[count] = modName;
+ count++;
+
+ if (args)
+ memcpy(argv + count, args, sizeof(*args) * argc);
+
+ argv[argc + count] = NULL;
+
+ argc += count;
+
+ if ((child = fork()) == 0) {
+ execv("/bin/loader", argv);
+ exit(1);
+ }
+
+ waitpid(child, &status, 0);
+
+ if (WIFEXITED(status))
+ rc = WEXITSTATUS(status);
+ else
+ rc = -1;
+
+ return rc;
+}
diff --git a/loader2/pcmcia.c b/loader2/pcmcia.c
new file mode 100644
index 000000000..a44d852d6
--- /dev/null
+++ b/loader2/pcmcia.c
@@ -0,0 +1,29 @@
+/*
+ * pcmcia.c - pcmcia functionality
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 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 "loader.h"
+#include "modules.h"
+
+int pcmciaInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ if (FL_NOPCMCIA(flags))
+ return 0;
+
+ /* JKFIXME: obviously we need real code here... */
+ return 0;
+}
diff --git a/loader2/pcmcia.h b/loader2/pcmcia.h
new file mode 100644
index 000000000..fffa362e5
--- /dev/null
+++ b/loader2/pcmcia.h
@@ -0,0 +1,7 @@
+#ifndef H_PCMCIA
+#define H_PCMCIA
+
+int pcmciaInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags);
+
+#endif
diff --git a/loader2/urlinstall.c b/loader2/urlinstall.c
new file mode 100644
index 000000000..403fa8cc2
--- /dev/null
+++ b/loader2/urlinstall.c
@@ -0,0 +1,255 @@
+/*
+ * urlinstall.c - code to set up url (ftp/http) installs
+ *
+ * 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 <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "loader.h"
+#include "lang.h"
+#include "log.h"
+#include "net.h"
+#include "method.h"
+#include "urls.h"
+
+static int loadSingleUrlImage(struct iurlinfo * ui, char * file, int flags,
+ char * dest, char * mntpoint, char * device,
+ int silentErrors) {
+ int fd;
+ int rc;
+ char * newFile = NULL;
+
+ fd = urlinstStartTransfer(ui, file, 1);
+
+ if (fd == -2) return 1;
+
+ if (fd < 0) {
+ /* file not found */
+
+ newFile = alloca(strlen(device) + 20);
+ sprintf(newFile, "disc1/%s", file);
+
+ fd = urlinstStartTransfer(ui, newFile, 1);
+
+ if (fd == -2) return 1;
+ if (fd < 0) {
+ if (!silentErrors)
+ newtWinMessage(_("Error"), _("OK"),
+ _("File %s/%s not found on server."),
+ ui->prefix, file);
+ return 1;
+ }
+ }
+
+ rc = copyFileAndLoopbackMount(fd, dest, flags, device, mntpoint);
+
+ urlinstFinishTransfer(ui, fd);
+
+ if (newFile) {
+ newFile = malloc(strlen(ui->prefix ) + 20);
+ sprintf(newFile, "%s/disc1", ui->prefix);
+ free(ui->prefix);
+ ui->prefix = newFile;
+ }
+
+ return rc;
+}
+
+
+static int loadUrlImages(struct iurlinfo * ui, int flags) {
+ setupRamdisk();
+
+ /* grab the updates.img before netstg1.img so that we minimize our
+ * ramdisk usage */
+ if (!loadSingleUrlImage(ui, "RedHat/base/updates.img", flags,
+ "/tmp/ramfs/updates-disk.img", "/tmp/update-disk",
+ "loop7", 1)) {
+ copyDirectory("/tmp/update-disk", "/tmp/updates");
+ umountLoopback("/tmp/update-disk", "loop7");
+ unlink("/tmp/ramfs/updates-disk.img");
+ }
+
+ if (loadSingleUrlImage(ui, "RedHat/base/netstg1.img", flags,
+ "/tmp/ramfs/netstg1.img",
+ "/mnt/runtime", "loop0", 0)) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("Unable to retrieve the install image."));
+ return 1;
+ }
+
+ /* now verify the stamp... */
+ if (!verifyStamp("/mnt/runtime")) {
+ char * buf;
+
+ buf = sdupprintf(_("The %s installation tree in that directory does "
+ "not seem to match your boot media."), PRODUCTNAME);
+
+ newtWinMessage(_("Error"), _("OK"), buf);
+
+ umountLoopback("/mnt/runtime", "loop0");
+ return 1;
+ }
+
+ return 0;
+
+}
+
+static char * getLoginName(char * login, struct iurlinfo ui) {
+ int i;
+
+ i = 0;
+ /* password w/o login isn't useful */
+ if (ui.login && strlen(ui.login)) {
+ i += strlen(ui.login) + 5;
+ if (strlen(ui.password))
+ i += 3*strlen(ui.password) + 5;
+
+ if (ui.login || ui.password) {
+ login = malloc(i);
+ strcpy(login, ui.login);
+ if (ui.password) {
+ char * chptr;
+ char code[4];
+
+ strcat(login, ":");
+ for (chptr = ui.password; *chptr; chptr++) {
+ sprintf(code, "%%%2x", *chptr);
+ strcat(login, code);
+ }
+ strcat(login, "@");
+ }
+ }
+ }
+
+ return login;
+}
+
+char * mountUrlImage(struct installMethod * method,
+ char * location, struct knownDevices * kd,
+ moduleInfoSet modInfo, moduleList modLoaded,
+ moduleDeps * modDeps, int flags) {
+ int rc;
+ char * url;
+ char * devName;
+ static struct networkDeviceConfig netDev;
+ struct iurlinfo ui;
+ char needsSecondary = ' ';
+ int dir = 1;
+ char * login;
+ char * finalPrefix;
+
+ enum { URL_STAGE_IFACE, URL_STAGE_IP, URL_STAGE_MAIN, URL_STAGE_SECOND,
+ URL_STAGE_FETCH, URL_STAGE_DONE } stage = URL_STAGE_IFACE;
+
+ enum urlprotocol_t proto =
+ !strcmp(method->name, "FTP") ? URL_METHOD_FTP : URL_METHOD_HTTP;
+
+ /* JKFIXME: we used to do another ram check here... keep it? */
+
+ initLoopback();
+
+ memset(&ui, 0, sizeof(ui));
+ memset(&netDev, 0, sizeof(netDev));
+ netDev.isDynamic = 1;
+
+ while (stage != URL_STAGE_DONE) {
+ switch(stage) {
+ case URL_STAGE_IFACE:
+ logMessage("going to pick interface");
+ rc = chooseNetworkInterface(kd, &devName, flags);
+ if ((rc == LOADER_BACK) || (rc == LOADER_ERROR) ||
+ ((dir == -1) && (rc == LOADER_NOOP))) return NULL;
+
+ stage = URL_STAGE_IP;
+ dir = 1;
+ break;
+
+ case URL_STAGE_IP:
+ logMessage("going to do getNetConfig");
+ rc = readNetConfig(devName, &netDev, flags);
+ if (rc) {
+ stage = URL_STAGE_IFACE;
+ dir = -1;
+ break;
+ }
+ stage = URL_STAGE_MAIN;
+ dir = 1;
+
+ case URL_STAGE_MAIN:
+ rc = urlMainSetupPanel(&ui, proto, &needsSecondary);
+ if (rc) {
+ stage = URL_STAGE_IP;
+ dir = -1;
+ } else {
+ stage = (needsSecondary != ' ') ? URL_STAGE_SECOND :
+ URL_STAGE_FETCH;
+ dir = 1;
+ }
+ break;
+
+ case URL_STAGE_SECOND:
+ rc = urlSecondarySetupPanel(&ui, proto);
+ if (rc) {
+ stage = URL_STAGE_MAIN;
+ dir = -1;
+ } else {
+ stage = URL_STAGE_FETCH;
+ dir = 1;
+ }
+ break;
+
+ case URL_STAGE_FETCH:
+ if (FL_TESTING(flags)) {
+ stage = URL_STAGE_DONE;
+ dir = 1;
+ break;
+ }
+
+ if (loadUrlImages(&ui, flags)) {
+ stage = URL_STAGE_MAIN;
+ dir = -1;
+ } else {
+ stage = URL_STAGE_DONE;
+ dir = 1;
+ }
+ break;
+
+ case URL_STAGE_DONE:
+ break;
+ }
+ }
+
+ login = "";
+ login = getLoginName(login, ui);
+
+ if (!strcmp(ui.prefix, "/"))
+ finalPrefix = "/.";
+ else
+ finalPrefix = ui.prefix;
+
+ url = malloc(strlen(finalPrefix) + 25 + strlen(ui.address) +
+ strlen(login));
+
+ sprintf(url, "%s://%s%s/%s",
+ ui.protocol == URL_METHOD_FTP ? "ftp" : "http",
+ login, ui.address, finalPrefix);
+ writeNetInfo("/tmp/netinfo", &netDev, kd);
+
+ return url;
+}
diff --git a/loader2/urls.c b/loader2/urls.c
new file mode 100644
index 000000000..4f6e6a0fc
--- /dev/null
+++ b/loader2/urls.c
@@ -0,0 +1,417 @@
+/*
+ * urls.c - url handling code
+ *
+ * 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 <arpa/inet.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../isys/dns.h"
+
+#include "ftp.h"
+#include "lang.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "urls.h"
+#include "log.h"
+#include "windows.h"
+#include "net.h"
+
+
+int urlinstStartTransfer(struct iurlinfo * ui, char * filename,
+ int silentErrors) {
+ char * buf;
+ int fd;
+ char * finalPrefix;
+
+ if (!strcmp(ui->prefix, "/"))
+ finalPrefix = "/.";
+ else
+ finalPrefix = ui->prefix;
+
+ logMessage("transferring %s://%s/%s/%s to a fd",
+ ui->protocol == URL_METHOD_FTP ? "ftp" : "http",
+ ui->address, finalPrefix, filename);
+
+ buf = alloca(strlen(finalPrefix) + strlen(filename) + 20);
+ sprintf(buf, "%s/%s", finalPrefix, filename);
+
+ if (ui->protocol == URL_METHOD_FTP) {
+ ui->ftpPort = ftpOpen(ui->address,
+ ui->login ? ui->login : "anonymous",
+ ui->password ? ui->password : "rhinstall@",
+ NULL, -1);
+ if (ui->ftpPort < 0) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to log into %s: %s"), ui->address,
+ ftpStrerror(ui->ftpPort));
+ return -2;
+ }
+
+ fd = ftpGetFileDesc(ui->ftpPort, buf);
+ if (fd < 0) {
+ close(ui->ftpPort);
+ if (!silentErrors)
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to retrieve %s: %s"), buf, ftpStrerror(fd));
+ return -1;
+ }
+ } else {
+ fd = httpGetFileDesc(ui->address, -1, buf);
+ if (fd < 0) {
+ if (!silentErrors)
+ newtWinMessage(_("Error"), _("OK"),
+ _("Failed to retrieve %s: %s"), buf, ftpStrerror(fd));
+ return -1;
+ }
+ }
+
+ winStatus(70, 3, _("Retrieving"), "%s %s...", _("Retrieving"), filename);
+
+ return fd;
+}
+
+int urlinstFinishTransfer(struct iurlinfo * ui, int fd) {
+ if (ui->protocol == URL_METHOD_FTP)
+ close(ui->ftpPort);
+ close(fd);
+
+ newtPopWindow();
+
+ return 0;
+}
+
+/* JKFIXME: this must go away / be generalized to be like all other platform */
+#if defined (__s390__) || defined (__s390x__)
+int setupRemote(struct iurlinfo * ui) {
+ char *env, *d;
+
+ if (!(env = getenv("RPMSERVER"))) {
+ ui->address = "";
+ ui->prefix = "";
+ return 0;
+ }
+
+ if (!strncmp(env, "ftp://",6))
+ env += 6;
+ else if (!strncmp(env, "http://",7))
+ env += 7;
+
+ if (!(d = index (env, '/'))) {
+ d = "";
+ ui->prefix = strdup(d);
+ }
+ else /* make sure the path either starts with a / or a ~ */
+ if(*d != '/') {
+ ui->prefix = (char *)malloc(strlen(d)+2);
+ *ui->prefix = '/';
+ strcat(ui->prefix, d);
+ }
+ else ui->prefix = strdup(d);
+
+ ui->address = strdup(env);
+ if (ui->address && (d = index (ui->address, '/')))
+ *d = '\0';
+ if (ui->address && (d = index (ui->address, ':')))
+ *d = '\0';
+
+ return 0;
+}
+#endif /* #if defined (__s390__) || defined (__s390x__) */
+
+char * addrToIp(char * hostname) {
+ struct in_addr ad;
+ char * chptr;
+
+ for (chptr = hostname; *chptr; chptr++)
+ if (!(isdigit(*chptr) || *chptr == '.')) break;
+
+ if (!*chptr)
+ return hostname;
+
+ if (mygethostbyname(hostname, &ad))
+ return NULL;
+
+ return inet_ntoa(ad);
+}
+
+int urlMainSetupPanel(struct iurlinfo * ui, urlprotocol protocol,
+ char * doSecondarySetup) {
+ newtComponent form, okay, cancel, siteEntry, dirEntry;
+ newtComponent answer, text;
+ newtComponent cb = NULL;
+ char * site, * dir;
+ char * reflowedText = NULL;
+ int width, height;
+ newtGrid entryGrid, buttons, grid;
+ char * chptr;
+ char * buf;
+
+ if (ui->address) {
+ site = ui->address;
+ dir = ui->prefix;
+ } else {
+ site = "";
+ dir = "";
+ }
+
+ if (ui->login || ui->password || ui->proxy || ui->proxyPort)
+ *doSecondarySetup = '*';
+ else
+ *doSecondarySetup = ' ';
+
+ buttons = newtButtonBar(_("OK"), &okay, _("Back"), &cancel, NULL);
+
+ switch (protocol) {
+ case URL_METHOD_FTP:
+ buf = sdupprintf(_(netServerPrompt), "FTP", PRODUCTNAME);
+ reflowedText = newtReflowText(buf, 47, 5, 5, &width, &height);
+ free(buf);
+ break;
+ case URL_METHOD_HTTP:
+ buf = sdupprintf(_(netServerPrompt), "Web", PRODUCTNAME);
+ reflowedText = newtReflowText(buf, 47, 5, 5, &width, &height);
+ free(buf);
+ break;
+ }
+ text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
+ newtTextboxSetText(text, reflowedText);
+ free(reflowedText);
+
+ siteEntry = newtEntry(22, 8, site, 24, &site, NEWT_ENTRY_SCROLL);
+ dirEntry = newtEntry(22, 9, dir, 24, &dir, NEWT_ENTRY_SCROLL);
+
+ entryGrid = newtCreateGrid(2, 2);
+ newtGridSetField(entryGrid, 0, 0, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, (protocol == URL_METHOD_FTP) ?
+ _("FTP site name:") :
+ _("Web site name:")),
+ 0, 0, 1, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(entryGrid, 0, 1, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("Red Hat directory:")),
+ 0, 0, 1, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(entryGrid, 1, 0, NEWT_GRID_COMPONENT, siteEntry,
+ 0, 0, 0, 0, 0, 0);
+ newtGridSetField(entryGrid, 1, 1, NEWT_GRID_COMPONENT, dirEntry,
+ 0, 0, 0, 0, 0, 0);
+
+ grid = newtCreateGrid(1, 4);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 1, 0, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, entryGrid,
+ 0, 0, 0, 1, 0, 0);
+
+ if (protocol == URL_METHOD_FTP) {
+ cb = newtCheckbox(3, 11, _("Use non-anonymous ftp"),
+ *doSecondarySetup, NULL, doSecondarySetup);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, cb,
+ 0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0);
+ }
+
+ newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
+ 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ newtGridWrappedWindow(grid, (protocol == URL_METHOD_FTP) ? _("FTP Setup") :
+ _("HTTP Setup"));
+
+ form = newtForm(NULL, NULL, 0);
+ newtGridAddComponentsToForm(grid, form, 1);
+
+ do {
+ answer = newtRunForm(form);
+ if (answer != cancel) {
+ if (!strlen(site)) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("You must enter a server name."));
+ continue;
+ }
+ if (!strlen(dir)) {
+ newtWinMessage(_("Error"), _("OK"),
+ _("You must enter a directory."));
+ continue;
+ }
+
+ if (!addrToIp(site)) {
+ newtWinMessage(_("Unknown Host"), _("OK"),
+ _("%s is not a valid hostname."), site);
+ continue;
+ }
+ }
+
+ break;
+ } while (1);
+
+ if (answer == cancel) {
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return LOADER_BACK;
+ }
+
+ if (ui->address) free(ui->address);
+ ui->address = strdup(site);
+
+ if (ui->prefix) free(ui->prefix);
+
+ /* add a slash at the start of the dir if it is missing */
+ if (*dir != '/') {
+ char *buf = malloc(strlen(dir) + 2);
+ buf[0] = '/';
+ buf[1] = '\0';
+ strcat (buf, dir);
+ ui->prefix = buf;
+ } else
+ ui->prefix = strdup(dir);
+
+ /* Get rid of trailing /'s */
+ chptr = ui->prefix + strlen(ui->prefix) - 1;
+ while (chptr > ui->prefix && *chptr == '/') chptr--;
+ chptr++;
+ *chptr = '\0';
+
+ if (*doSecondarySetup != '*') {
+ if (ui->login)
+ free(ui->login);
+ if (ui->password)
+ free(ui->password);
+ if (ui->proxy)
+ free(ui->proxy);
+ if (ui->proxyPort)
+ free(ui->proxyPort);
+ ui->login = ui->password = ui->proxy = ui->proxyPort = NULL;
+ /*
+ delMacro(NULL, "_httpproxy");
+ delMacro(NULL, "_ftpproxy");
+ delMacro(NULL, "_httpproxyport");
+ delMacro(NULL, "_ftpproxyport");
+ */
+ }
+
+ ui->protocol = protocol;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return 0;
+
+}
+int urlSecondarySetupPanel(struct iurlinfo * ui, urlprotocol protocol) {
+ newtComponent form, okay, cancel, answer, text, accountEntry = NULL;
+ newtComponent passwordEntry = NULL, proxyEntry = NULL;
+ newtComponent proxyPortEntry = NULL;
+ char * account, * password, * proxy, * proxyPort;
+ newtGrid buttons, entryGrid, grid;
+ char * reflowedText = NULL;
+ int width, height;
+
+ if (protocol == URL_METHOD_FTP) {
+ reflowedText = newtReflowText(
+ _("If you are using non anonymous ftp, enter the account name and "
+ "password you wish to use below."),
+ 47, 5, 5, &width, &height);
+ } else {
+ reflowedText = newtReflowText(
+ _("If you are using a HTTP proxy server "
+ "enter the name of the HTTP proxy server to use."),
+ 47, 5, 5, &width, &height);
+ }
+ text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
+ newtTextboxSetText(text, reflowedText);
+ free(reflowedText);
+
+ if (protocol == URL_METHOD_FTP) {
+ accountEntry = newtEntry(-1, -1, NULL, 24, &account,
+ NEWT_FLAG_SCROLL);
+ passwordEntry = newtEntry(-1, -1, NULL, 24, &password,
+ NEWT_FLAG_SCROLL | NEWT_FLAG_PASSWORD);
+ }
+ proxyEntry = newtEntry(-1, -1, ui->proxy, 24, &proxy, NEWT_ENTRY_SCROLL);
+ proxyPortEntry = newtEntry(-1, -1, ui->proxyPort, 6, &proxyPort,
+ NEWT_FLAG_SCROLL);
+
+ entryGrid = newtCreateGrid(2, 4);
+ if (protocol == URL_METHOD_FTP) {
+ newtGridSetField(entryGrid, 0, 0, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("Account name:")),
+ 0, 0, 2, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(entryGrid, 0, 1, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, _("Password:")),
+ 0, 0, 2, 0, NEWT_ANCHOR_LEFT, 0);
+ }
+ if (protocol == URL_METHOD_FTP) {
+ newtGridSetField(entryGrid, 1, 0, NEWT_GRID_COMPONENT, accountEntry,
+ 0, 0, 0, 0, 0, 0);
+ newtGridSetField(entryGrid, 1, 1, NEWT_GRID_COMPONENT, passwordEntry,
+ 0, 0, 0, 0, 0, 0);
+ }
+
+ buttons = newtButtonBar(_("OK"), &okay, _("Back"), &cancel, NULL);
+
+ 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, entryGrid,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+
+
+ if (protocol == URL_METHOD_FTP) {
+ newtGridWrappedWindow(grid, "Further FTP Setup");
+ } else {
+ if (protocol == URL_METHOD_HTTP)
+ newtGridWrappedWindow(grid, "Further HTTP Setup");
+ }
+
+ form = newtForm(NULL, NULL, 0);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridFree(grid, 1);
+
+ answer = newtRunForm(form);
+ if (answer == cancel) {
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return LOADER_BACK;
+ }
+
+ if (protocol == URL_METHOD_FTP) {
+ if (ui->login) free(ui->login);
+ if (strlen(account))
+ ui->login = strdup(account);
+ else
+ ui->login = NULL;
+
+ if (ui->password) free(ui->password);
+ if (strlen(password))
+ ui->password = strdup(password);
+ else
+ ui->password = NULL;
+ }
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return 0;
+}
diff --git a/loader2/urls.h b/loader2/urls.h
new file mode 100644
index 000000000..29cd46798
--- /dev/null
+++ b/loader2/urls.h
@@ -0,0 +1,26 @@
+#ifndef H_LOADER_URLS
+#define H_LOADER_URLS
+
+enum urlprotocol_t { URL_METHOD_FTP, URL_METHOD_HTTP };
+typedef enum urlprotocol_t urlprotocol;
+
+struct iurlinfo {
+ urlprotocol protocol;
+ char * address;
+ char * login;
+ char * password;
+ char * prefix;
+ char * proxy;
+ char * proxyPort;
+ int ftpPort;
+};
+
+int setupRemote(struct iurlinfo * ui);
+int urlMainSetupPanel(struct iurlinfo * ui, urlprotocol protocol,
+ char * doSecondarySetup);
+int urlSecondarySetupPanel(struct iurlinfo * ui, urlprotocol protocol);
+int urlinstStartTransfer(struct iurlinfo * ui, char * filename,
+ int silentErrors);
+int urlinstFinishTransfer(struct iurlinfo * ui, int fd);
+
+#endif
diff --git a/loader2/usb.c b/loader2/usb.c
new file mode 100644
index 000000000..09aa509fd
--- /dev/null
+++ b/loader2/usb.c
@@ -0,0 +1,129 @@
+/*
+ * usb.c - usb probing/module loading functionality
+ *
+ * Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * Copyright 1999 - 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 <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kudzu/kudzu.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "loader.h"
+#include "log.h"
+#include "modules.h"
+#include "moduledeps.h"
+
+#include "../isys/imount.h"
+
+
+/* This forces a pause between initializing usb and trusting the /proc
+ stuff */
+static void sleepUntilUsbIsStable(void) {
+ struct stat sb;
+ time_t last = 0;
+ int i, count = 0;
+
+ /* sleep for a maximum of 20 seconds, minimum of 2 seconds */
+ logMessage("waiting for usb to become stable...");
+ for (i = 0; i < 20; i++) {
+ stat("/proc/bus/usb/devices", &sb);
+ if (last == sb.st_mtime) {
+ count++;
+ /* if we get the same mtime twice in a row, should be
+ good enough to use now */
+ if (count > 1)
+ break;
+ } else {
+ /* if we didn't match mtimes, reset the stability counter */
+ count = 0;
+ }
+ last = sb.st_mtime;
+ sleep(1);
+ }
+ logMessage("%d seconds.", i);
+}
+
+int usbInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ struct device ** devices;
+ char * buf;
+ int i;
+
+ if (FL_NOUSB(flags)) return 0;
+
+ logMessage("looking for usb controllers");
+
+ devices = probeDevices(CLASS_USB, BUS_PCI, PROBE_ALL);
+
+ if (!devices) {
+ logMessage("no usb controller found");
+ return 0;
+ }
+
+ /* JKFIXME: if we looked for all of them, we could batch this up and it
+ * would be faster */
+ for (i=0; devices[i]; i++) {
+ logMessage("found USB controller %s", devices[i]->driver);
+
+ if (mlLoadModuleSet(devices[i]->driver, modLoaded, modDeps,
+ modInfo, flags)) {
+ /* dont return, just keep going. */
+ /* may have USB built into kernel */
+ /* return 1; */
+ }
+ }
+
+ if (FL_TESTING(flags)) return 0;
+
+ if (doPwMount("/proc/bus/usb", "/proc/bus/usb", "usbdevfs", 0, 0,
+ NULL, NULL))
+ logMessage("failed to mount device usbdevfs: %s", strerror(errno));
+
+ /* sleep so we make sure usb devices get properly enumerated.
+ that way we should block when initializing each usb driver until
+ the device is ready for use */
+ sleepUntilUsbIsStable();
+
+ buf = alloca(40);
+ sprintf(buf, "hid:keybdev%s",
+ (FL_NOUSBSTORAGE(flags) ? "" : ":usb-storage"));
+ mlLoadModuleSet(buf, modLoaded, modDeps, modInfo, flags);
+ sleep(1);
+
+ return 0;
+}
+
+void usbInitializeMouse(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags) {
+ extern struct moduleBallLocation * secondStageModuleLocation;
+
+ if (FL_NOUSB(flags)) return;
+
+ if (access("/proc/bus/usb/devices", R_OK)) return;
+
+ logMessage("looking for USB mouse...");
+ if (probeDevices(CLASS_MOUSE, BUS_USB, PROBE_ALL)) {
+ logMessage("USB mouse found, loading mousedev module");
+ if (mlLoadModuleSetLocation("mousedev", modLoaded, modDeps, modInfo, flags, secondStageModuleLocation)) {
+ logMessage ("failed to loading mousedev module");
+ return;
+ }
+ }
+}
+
diff --git a/loader2/usb.h b/loader2/usb.h
new file mode 100644
index 000000000..d35754bc3
--- /dev/null
+++ b/loader2/usb.h
@@ -0,0 +1,9 @@
+#ifndef H_USB
+#define H_USB
+
+int usbInitialize(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags);
+void usbInitializeMouse(moduleList modLoaded, moduleDeps modDeps,
+ moduleInfoSet modInfo, int flags);
+
+#endif
diff --git a/loader2/windows.c b/loader2/windows.c
new file mode 100644
index 000000000..e97956ca5
--- /dev/null
+++ b/loader2/windows.c
@@ -0,0 +1,66 @@
+/*
+ * windows.c - simple popup windows used by the loader
+ *
+ * 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 <errno.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "windows.h"
+
+void winStatus(int width, int height, char * title,
+ char * text, ...) {
+ newtComponent t, f;
+ char * buf = NULL;
+ int size = 0;
+ int i = 0;
+ va_list args;
+
+ va_start(args, text);
+
+ do {
+ size += 1000;
+ if (buf) free(buf);
+ buf = malloc(size);
+ i = vsnprintf(buf, size, text, args);
+ } while (i == size);
+
+ va_end(args);
+
+ newtCenteredWindow(width, height, title);
+
+ t = newtTextbox(1, 1, width - 2, height - 2, NEWT_TEXTBOX_WRAP);
+ newtTextboxSetText(t, buf);
+ f = newtForm(NULL, NULL, 0);
+
+ free(buf);
+
+ newtFormAddComponent(f, t);
+
+ newtDrawForm(f);
+ newtRefresh();
+ newtFormDestroy(f);
+}
+
+
+void scsiWindow(const char * driver) {
+ winStatus(40, 3, _("Loading SCSI driver"),
+ _("Loading %s driver..."), driver);
+}
diff --git a/loader2/windows.h b/loader2/windows.h
new file mode 100644
index 000000000..c42da6dd4
--- /dev/null
+++ b/loader2/windows.h
@@ -0,0 +1,12 @@
+#ifndef _WINDOWS_H_
+#define _WINDOWS_H_
+
+#include "lang.h"
+
+void winStatus(int width, int height, char * title, char * text, ...);
+void scsiWindow(const char * driver);
+
+#define errorWindow(String) \
+ newtWinMessage(_("Error"), _("OK"), String, strerror (errno));
+
+#endif /* _WINDOWS_H_ */