/*
 * install.c
 * 
 * This is the first half of the install. It does just enough to get the
 * second half going. It, and everything it needs, has to fit on one floppy
 * along with a kernel and modules. Needless to say, it's a bit tight.
 *
 * Erik Troan (ewt@redhat.com)
 *
 * Copyright 1996 Red Hat Software 
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <alloca.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <zlib.h>

#include "devices.h"
#include "fs.h"
#include "install.h"
#include "log.h"
#include "methods.h"
#include "mono.h"
#include "net.h"
#include "newt.h"
#include "perror.h"
#include "run.h"
#include "windows.h"

int testing = 0;
int hackdisk = 0;
int debug = 1;

char * welcomeText =
    "Welcome to Red Hat Linux!\n"
    "\n"
    "This installation process is outlined in detail in the Official Red "
    "Hat Linux User's Guide available from Red Hat Software. If you have "
    "access to this manual, you should read the installation section before "
    "continuing.\n\n"
    "If you have purchased Official Red Hat Linux, be sure to register your "
    "purchase through our web site, http://www.redhat.com."
    ;

char * hackdiskText = "Would you like to use a hack disk now?";

void welcome(void) {
    if (!testing)
	winMessage(7, 4, 65, 16, "Red Hat Linux", welcomeText);
}

void mountFloppy() {
    if (!testing) {
	logMessage("mounting ext2 fs on floppy");
	doMount("fd0", "/tmp/bootdisk", "ext2", 1);
	logMessage("floppy filesystem mounted on /tmp/bootdisk");
    }
}

void showmtab(void) {
    char buf[5000];
    int fd, i;

    fd = open("/proc/mounts", O_RDONLY);
    if (fd < 0) {
	messageWindow("error", perrorstr("open /proc/mounts"));
	return;
    }

    i = read(fd, buf, sizeof(buf) - 1);
    if (i < 1) {
	close(fd);
	messageWindow("error", perrorstr("read /proc/mounts"));
	return;
    }
    close(fd);

    buf[i] = '\0';

    messageWindow("/proc/mounts", buf);
}

void mountHackdisk() {
    if (hackdisk) {
	messageWindow("Hackdisk", "Insert hack disk");

	if (!testing) {
	    doMount("fd0", "/tmp/hackdisk", "ext2", 1);

	    symlink("/tmp/hackdisk/lib", "/lib");
	    symlink("/tmp/hackdisk/etc", "/etc");
	    /*showdir("/lib");
	    showdir("/tmp/hackdisk/bin");*/

	    logMessage("hackdisk filesystem mounted on /tmp/bootdisk");
	    if (!fork()) {
		execl("/tmp/hackdisk/bin/open", "open", "/tmp/hackdisk/bin/sh", NULL);
		logMessage(perrorstr("exec of sh failed"));
	    }
	}
    }
}

static int pcmciaChoicePanel(int * havePCMCIA) {
    newtComponent label, f, answer;
    newtComponent yes, no;

    #if defined(__sparc__) || defined(__alpha__)
	*havePCMCIA = 0;
	return 0;
    #endif

    newtOpenWindow(21, 7, 35, 9, "PCMCIA Support");

    label = newtLabel(2, 2, "Do you need PCMCIA support?");
 
    yes = newtButton(5, 5, "Yes");
    no = newtButton(22, 5, "No");

    f = newtForm(NULL, NULL, 0);
    newtFormAddComponents(f, label, yes, no, NULL);
    newtFormSetCurrent(f, no);
    
    answer = newtRunForm(f);
    if (answer == f)
	answer = newtFormGetCurrent(f);

    newtFormDestroy(f);
    newtPopWindow();

    if (answer == no) 
	*havePCMCIA = 0;
    else
	*havePCMCIA = 1;
 
    return 0;
}

int setupPCMCIA(char ** arg) {
    int rc, doit;
    struct driversLoaded * dl = NULL;
    int status;
    char * args[] = { "/sbin/probe", NULL };
    char * probeOutput;
    static char pcic[20];
 
    pcmciaChoicePanel(&doit);
    if (!doit) return 0;

    if ((rc = floppyRoot(NULL))) return rc;

    if (testing) {
	sleep(2);
	return 0;
    }

    winStatus(35, 3, "PCMCIA", "Loading PCMCIA support...");

    chdir("/modules");
    unlink("53c7,8xx.o");
    unlink("3c59x.o");
    unlink("cdrom.o");
    unlink("aztcd.o");
    unlink("cdu31a.o");
    unlink("cm206.o");
    unlink("de4x5.o");
    unlink("sbpcd.o");
    unlink("sjcd.o");
    unlink("sonycd535.o");
    unlink("optcd.o");
    unlink("gscd.o");
    unlink("aic7xxx.o");
    unlink("eata_dma.o");
    unlink("eata_pio.o");
    unlink("pas_16.o");
    unlink("ultrastor.o");
    unlink("u14-34f.o");

    chdir("/");
 
    system("gunzip < /tmp/image/pcmcia.cgz | cpio -iumd --quiet");

    newtPopWindow();

    winStatus(35, 3, "PCMCIA", "Probing PCMCIA controller...");
    rc = runProgramIO(RUN_NOLOG, "/sbin/probe", args, NULL, &probeOutput);
    newtPopWindow();

    if (rc || !probeOutput) {
	errorWindow("PCMCIA probe failed");
	return INST_ERROR;
    }

    logMessage("pcmcia probe returned: %s", probeOutput);

    if (!strstr(probeOutput, "Intel")) {
	strcpy(pcic, "tcic");
    } else
	strcpy(pcic, "i82365");
    logMessage("pcmcia pcic type: %s", pcic);

    winStatus(40, 3, "PCMCIA", "Starting PCMCIA services...");

    loadModule("pcmcia_core", DRIVER_PCMCIA, &dl);
    loadModule(pcic, DRIVER_PCMCIA, &dl);
    loadModule("ds", DRIVER_PCMCIA, &dl);

    *arg = pcic;

    if (!fork()) {
	if (!fork()) {
	    execl("/sbin/cardmgr", "/sbin/cardmgr", NULL);
	    exit(-1);
	}
	exit(-1);
    }

    wait(&status);

    /* if cardmgr a chance to get going */
    sleep(5);

    newtPopWindow();

    return 0;
}

void main(void) {
    struct installMethod * method;
    int rc;
    char * pcmciaArg = NULL;

    if (!testing && (getpid() > 50)) {
	fprintf(stderr, "you're running me on a live system! that's ");
	fprintf(stderr, "incredibly stupid.\n");
	exit(1);
    }

    openLog();

    logMessage("welcome to the Red Hat install (first stage, version %s)",
		VERSION);

    setenv("NEWT_MONO", "1", 1);

    newtInit();
    newtCls();
    newtDrawRootText(0, 0, "Welcome to Red Hat Linux");

    setColorState();

    newtFinished();

    newtInit();
    newtCls();
    newtDrawRootText(0, 0, "Welcome to Red Hat Linux");

    welcome();

    newtPushHelpLine(NULL);

    do {
	rc = setupPCMCIA(&pcmciaArg);
    } while (rc);

    chooseInstallMethod(&method);

    mountHackdisk();

    if (!testing) {
	/* set up some symlinks */
	symlink("/tmp/image/RedHat/instimage/lib", "/tmp/lib");
	if (symlink("/tmp/image/RedHat/instimage/usr/bin", "/tmp/bin")) {
	    messageWindow("Error", perrorstr("symlink 2"));
	}
    }

    newtFinished();

    closeLog();

    if (testing) exit(0);

    if (pcmciaArg) 
	execl("/usr/bin/runinstall2", "runinstall2", "--method", 
		method->abbrev, "--pcmcia", pcmciaArg, NULL);
    else
	execl("/usr/bin/runinstall2", "runinstall2", "--method", 
		method->abbrev, NULL);

    rc = errno;
    openLog();
    logMessage("error in exec of second stage loader :-(");
    logMessage("\terror:%s", strerror(rc));
 
    while (1) ;

    exit(0);
}
