diff options
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_ */ |