#include <alloca.h>
#include <ctype.h>
#include <linux/fs.h>
#include <newt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>

#include "devices.h"
#include "fs.h"
#include "install.h"
#include "log.h"
#include "mkswap.h"
#include "perror.h"
#include "run.h"
#include "windows.h"

int readMountTable(struct partitionTable table, struct fstab * finalFstab) {
    newtComponent okay, cancel, form, text, listbox, answer;
    int i, rootPartNum;
    struct partition * rootPart = NULL;
    FILE * f;
    char buf[200];
    char * start, * end;
    char device[50], mntpoint[50], type[50];
    struct fstab fstab;
    struct fstabEntry entry;

    umountFilesystems(finalFstab);
 
    for (i = 0; i < table.count; i++) 
	if (table.parts[i].type == PART_EXT2) break;
    if (i == table.count) {
	errorWindow("You don't have any Linux partitions. You "
			"can't upgrade this system!");
	return INST_CANCEL;		/* INST_ERROR would hang everything */
    }

    newtOpenWindow(10, 2, 55, 19, "Root Partition");
    text = newtTextbox(1, 1, 53, 2, NEWT_TEXTBOX_WRAP);
    newtTextboxSetText(text, "What partition holds the root partition "
		       "of your installation?");

    okay = newtButton(11, 15, "Ok");
    cancel = newtButton(33, 15, "Cancel");

    form = newtForm(NULL, NULL, 0);
    listbox = addPartitionListbox(table, form, 3, 4, 7, PART_EXT2);

    newtFormAddComponents(form, text, okay, cancel, NULL);

    do {
	answer = newtRunForm(form);
	if (answer == cancel) continue;

	rootPart = newtListboxGetCurrent(listbox);
	rootPartNum = (rootPart - table.parts);

	if (doMount(table.parts[rootPartNum].device, "/mnt", "ext2", 0)) {
	    errorWindow("Could not mount device.");
	    answer = NULL;
	    continue;
	}

	if (testing) {
	    continue;
	}

	if (access("/mnt/etc", R_OK) || access("/mnt/etc/fstab", R_OK) ||
	    access("/mnt/proc", R_OK) || access("/mnt/bin", R_OK)) {
	    errorWindow("That doesn't appear to be a root partition.");
	    umount("/mnt");
	    answer = NULL;
	}
    } while (!answer);
			
    newtFormDestroy(form);
    newtPopWindow();

    if (answer == cancel) return INST_CANCEL;

    if (testing) 
	f = fopen("/etc/fstab", "r");
    else
	f = fopen("/mnt/etc/fstab", "r");

    if (!f) {
	errorWindow("Cannot read /mnt/etc/fstab: %s");
	return INST_ERROR;
    }

    memset(&fstab, 0, sizeof(fstab));

    while (fgets(buf, sizeof(buf) - 1, f)) {
	start = buf;
	while (*start && isspace(*start)) start++;
	if (!*start || *start == '#') continue;

	if (strncmp(start, "/dev/", 5)) {
	    continue;
	}

	if (strstr(start, "noauto")) continue;

	end = start + strlen(start) - 1;
	while (isspace(*end)) end--;
	end++;
	*end = '\0';

	if (sscanf(start, "%s %s %s", device, mntpoint, type) != 3) {
	    errorWindow("Bad line in /mnt/etc/fstab -- aborting");
	    fclose(f);
	    freeFstab(fstab);
	    umount("/mnt");
	    return INST_ERROR;
	}

	if (strncmp(device, "/dev/hd", 7) && strncmp(device, "/dev/sd", 7))
	    continue;

	entry.device = strdup(device + 5);
	entry.size = 0;
	entry.isMounted = 0;
	entry.doFormat = 0;
	entry.mntpoint = strdup(mntpoint);

	if (!strcmp(type, "ext2")) {
	    entry.type = PART_EXT2;
	    entry.tagName = "Linux native";
	} else if (!strcmp(type, "swap")) {
	    entry.type = PART_SWAP;
	    entry.tagName = "Linux swap";
	    if (canEnableSwap) {
		enableswap(entry.device, 0, 0);
		canEnableSwap = 0;
	    }
	} else if (!strcmp(type, "msdos")) {
	    entry.type = PART_DOS;
	    entry.tagName = "DOS 16-bit >=32";
	} else if (!strcmp(type, "hpfs")) {
	    entry.type = PART_HPFS;
	    entry.tagName = "OS/2 HPFS";
	} else {
	    entry.type = PART_OTHER;
	    entry.tagName = "Unknown";
	}

	addFstabEntry(&fstab, entry);
    }

    fclose(f);

    umount("/mnt");

    freeFstab(*finalFstab);
    *finalFstab = fstab;

    return 0;
}
