#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <stdio.h>
#include <time.h>
#include <strings.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <utime.h>
#include <ncurses.h>
#include <malloc.h>
#include <signal.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <atasmart.h>
#include <libfdisk/libfdisk.h>
#include <net/if.h>
#include <net/route.h>
#include <netdb.h>
#include <errno.h>
#include <ifaddrs.h>
#include <uuid/uuid.h>
#include <lzma.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_packet.h>
#include <linux/if_arp.h>
#include <net/ethernet.h>
#include <sys/sysmacros.h>
#include "gix.h"


void do_efi();

void _debug_logger(char *__file__,int __line__,const char *fmt, ...);
#define debug_logger(fmt, ...) _debug_logger(__FILE__,__LINE__,fmt, ##__VA_ARGS__)

u_int16_t ip_checksum(u_int8_t *data, int len){
        u_int32_t sum;
        u_int32_t hhigh;
        u_int16_t low;
        u_int16_t high;
        u_int16_t val;
        int i;

        sum = 0x0000;

        for ( i = 0; i < len; i += 2 ){
                low = (u_int16_t)data[i];
                high = (u_int16_t)data[i+1];
                sum += low + (high << 8);
        }
        hhigh = sum >> 16;
        sum &= 0xffff;
        sum += hhigh;


        sum ^= 0xffff;

        return((u_int16_t)sum);
}


u_int16_t udp_checksum(u_int8_t *data, int len, struct ip *ip){
       int i;
        u_int16_t sum1;
        u_int32_t sum2;
        u_int16_t helper;
        u_int16_t helper2;
        u_int16_t x_udp_checksum;
        u_int16_t udp_len;
        u_int8_t  pseudoheader[12];
        sum1 = 0x0000;
        sum2 = 0x00000000;
        bzero(pseudoheader,12);
        memcpy(pseudoheader,&(ip->ip_src.s_addr),4);
        memcpy(&pseudoheader[4],&(ip->ip_dst.s_addr),4);
        pseudoheader[9] = ip->ip_p;
        udp_len = htons((short)len);
        memcpy(&pseudoheader[10],&udp_len,2);

        for ( i = 0; i < 12; i+=2 ){
                helper = (pseudoheader[i] << 8) + pseudoheader[i+1];
                sum1 += helper;
                sum2 += helper;
        }
        for ( i = 0; i < len; i+=2 ){
                helper = (data[i] << 8) + data[i+1];
                sum1 += helper;
                sum2 += helper;
        }
        while ( (( sum2 & 0xFFFF0000 ) >> 16) ){
                u_int16_t highpart;
                highpart = (( sum2 & 0xFFFF0000 ) >> 16);
                sum2 = highpart + sum1;
                sum1 += highpart;
        }
        x_udp_checksum = ~sum1;
        return(htons(x_udp_checksum));
}





unsigned char ipbcast[4]; 	
unsigned char dhcpmagic[4]; 	
/*
    A_NORMAL        Normal display (no highlight)
    A_STANDOUT      Best highlighting mode of the terminal.
    A_UNDERLINE     Underlining
    A_REVERSE       Reverse video
    A_BLINK         Blinking
    A_DIM           Half bright
    A_BOLD          Extra bright or bold
    A_PROTECT       Protected mode
    A_INVIS         Invisible or blank mode
    A_ALTCHARSET    Alternate character set
    A_CHARTEXT      Bit-mask to extract a character
    COLOR_PAIR(n)   Color-pair number n
*/

void end_runner();
#define end_scroller() end_runner()
int create_scroller(char *caption);
int run_program(char *exe, char **arg,char *caption, char *final_prompt);

typedef struct _win_border_struct {
	chtype 	ls, rs, ts, bs, 
	 	tl, tr, bl, br;
}WIN_BORDER;

typedef struct _WIN_struct {

	int start_x, start_y;
	int height, width;
	WIN_BORDER border;
	WINDOW *win;
}WIN;



void draw_frame();

int rows, cols;
int o_rows, o_cols;
char caption[1024];
int current_option = 0;

struct _option {
	char *caption;
	void (*handler)();
};

int options;

struct _select {
	char *name;
	int internal_id;
	int useable;
	void (*handler)(); // Not used yet 
};

struct _select2 {
	char *name;
	int internal_id;
	char selected;
	int useable;
	void (*handler)(); // Not used yet 
};

struct _disk {
	char devname[64];
	u_int64_t size;
	u_int64_t sectors;
	char israid;
	int partitions;
	char serial[256];
	char model[256];
	char badsectors[256];
	char uptime[256];
	fdisk_sector_t cylinders;
	fdisk_sector_t heads;
	fdisk_sector_t first_lba;
	fdisk_sector_t last_lba;
	fdisk_sector_t geom_secs;
	size_t labels;
	unsigned long sector_size;
	int nents;
	struct fdisk_context *ctx;
	struct fdisk_table *tb;
	struct fdisk_label *label;
};

struct _disk *disk = NULL;
int disks = 0;
int current_disk = 0;

void disk_setup();
void exit_setup();
void reboot_system();
void display_options();

void raid_setup();
void raid_stop();
void network_setup();
void efi_setup();
void files_setup();
void zero_all_disks();
void linux_setup();

struct _option option[] = {
	{ "Configure disks",disk_setup },
	{ "Configure RAID",raid_setup },
	{ "Configure network (for installing)",network_setup },
	{ "Install EFI files & GIX-Linux files",files_setup },
	{ "Configure GIX-Linux",linux_setup },
	{ "Configure UEFI-BIOS Boot-Order",efi_setup },
	{ "Reboot system",reboot_system },
	{ "Exec a shell",exit_setup },
	{ "Stop RAID-Systems",raid_stop },
	{ "Zero all disks",zero_all_disks },
	{ NULL,NULL }
};

WIN _sub1;
WIN _sub2;
WIN _walarm;
WIN _runner;
WIN _screen;
WIN *sub1;
WIN *sub2;
WIN *walarm;
WIN *runner;

WIN *screen;
WINDOW *root;

int last_status;
void reaper(int signal){
	while ( wait(&last_status) < 0 );
}





int disk_sorter(const void *_a, const void *_b){
	struct _disk *a;
	struct _disk *b;
	a = (struct _disk *)_a;
	b = (struct _disk *)_b;
	return(strcmp(a->devname,b->devname));

}

int current_select = 0;
int show_selector(char *caption, WIN *win, int y_offset, struct _select *sel, int sels){
	int i;
	int possible_rows;
	int possible_cols;
	char fmt_string[129];
	int start_idx,last_idx;

	possible_rows = (win->height-3) - y_offset;
	possible_cols = win->width-2;

	sprintf(fmt_string,"%%.%ds",possible_cols);

	start_idx = 0;
	last_idx  = possible_rows;

	if ( current_select > last_idx ){
		last_idx = current_select;
		start_idx = last_idx - possible_rows;
		if ( start_idx < 0 ) start_idx = 0;
	}
	for ( i = start_idx; i  <= last_idx && i < sels; i++ ){
		// move((i-start_idx) + win->start_y + 1 + y_offset, win->start_x + 1);
		wmove(win->win, (i-start_idx) +  1 + y_offset,  1);
		if ( current_select == i ){
			wattron(win->win,A_REVERSE);
			wprintw(win->win,fmt_string,sel[i].name);
			// printw("DISK %d",i);
			wattroff(win->win,A_REVERSE);

		} else {
			wattroff(win->win,A_REVERSE);
			wprintw(win->win,fmt_string,sel[i].name);
		}
	}
	wrefresh(win->win);


}
int show_selector2(char *caption, WIN *win, int y_offset, struct _select2 *sel, int sels){
	int i;
	int possible_rows;
	int possible_cols;
	char fmt_string[129];
	int start_idx,last_idx;

	possible_rows = (win->height-3) - y_offset;
	possible_cols = win->width-2;

	sprintf(fmt_string,"%%.%ds",possible_cols);

	start_idx = 0;
	last_idx  = possible_rows;

	if ( current_select > last_idx ){
		last_idx = current_select;
		start_idx = last_idx - possible_rows;
		if ( start_idx < 0 ) start_idx = 0;
	}
	for ( i = start_idx; i  <= last_idx && i < sels; i++ ){
		if ( current_select == i ){
			wattron(win->win, A_REVERSE);
			wmove(win->win,(i-start_idx) +  1 + y_offset,  1);
			if ( sel[i].selected ){
				wprintw(win->win,"[X]  ");
			} else {
				wprintw(win->win,"[ ]  ");
			}
			wmove(win->win,(i-start_idx) +  1 + y_offset,  5);
			wprintw(win->win,fmt_string,sel[i].name);
			// printw("DISK %d",i);
			wattroff(win->win, A_REVERSE);

		} else {
			wattroff(win->win, A_REVERSE);
			wmove(win->win,(i-start_idx) + 1 + y_offset,  1);
			if ( sel[i].selected ){
				wprintw(win->win,"[X]  ");
			} else {
				wprintw(win->win,"[ ]  ");
			}
			wmove(win->win,(i-start_idx)  + 1 + y_offset,  5);
			wprintw(win->win,fmt_string,sel[i].name);
		}
	}
	wrefresh(win->win);


}
int run_selector2(char *caption, WIN *win, int y_offset, struct _select2 *sel, int sels, int(*handler)(int ch) ){
	// current_select = 0;
	show_selector2(caption, win,y_offset, sel, sels);
	refresh();
	while ( 1 ){
		int ch;
		ch = getch();
		if (handler){ 
			int retval;
			retval = handler(ch);
			if ( retval == HANDLER_RETURN_ESCAPE ) return(-2);
			if ( retval == HANDLER_RETURN_CURRENT_SELECT ) return(current_select);
		}
		switch(ch){
			case KEY_UP: 
				current_select--; 
				if ( current_select < 0 ){
					current_select = 0;
				} else {
					show_selector2(caption, win,y_offset, sel, sels);
					refresh();
				}
				break;
			case KEY_DOWN: 
				current_select++; 
				if ( current_select >= sels ){
					current_select = sels-1;
				} else {
					show_selector2(caption, win, y_offset,sel, sels);
					refresh();
				}
				break;
			case 0x0020:
				if ( sel[current_select].selected ) 
					sel[current_select].selected = 0;
				else
					sel[current_select].selected = 1;
				show_selector2(caption, win, y_offset,sel, sels);
				break;
			case KEY_ENTER: 
			case 0x000A:
				return(current_select);
				break;
			case 0x001B:
				return(-1);
				break;
		}	
	}
}

int run_selector(char *caption, WIN *win, int y_offset, struct _select *sel, int sels, int(*handler)(int ch) ){
	// current_select = 0;
	show_selector(caption, win,y_offset, sel, sels);
	refresh();
	while ( 1 ){
		int ch;
		ch = getch();
		if (handler){ 
			int retval;
			retval = handler(ch);
			if ( retval == HANDLER_RETURN_ESCAPE ) return(-2);
			if ( retval == HANDLER_RETURN_CURRENT_SELECT ) return(current_select);
		}
		switch(ch){
			case KEY_UP: 
				current_select--; 
				if ( current_select < 0 ){
					current_select = 0;
				} else {
					show_selector(caption, win,y_offset, sel, sels);
					refresh();
				}
				break;
			case KEY_DOWN: 
				current_select++; 
				if ( current_select >= sels ){
					current_select = sels-1;
				} else {
					show_selector(caption, win, y_offset,sel, sels);
					refresh();
				}
				break;
			case KEY_ENTER: 
			case 0x000A:
				return(current_select);
				break;
			case 0x001B:
				return(-1);
				break;
		}	
	}
}


#define alarm_window(a,b,c,d) _alarm_window(__FILE__,__LINE__,(a),(b),(c),(d))

int _alarm_window(char *__file__, int __line__,char *caption,  int level, char *input, int input_len){ // input_len ANSWER_OK, ANSWER_CANCEL, if input == NULL!!!
	char **content;
	int x,y,w,h,i,j;
	int longest;
	int lines;
	char *ptr1;
	char *ptr2;
	int cursel;

#define ERROR_ALARM  "<EXIT>"
#define INFO_ALARM   "<CONTINUE>"
#define OK_ALARM     "<OK>"
#define CANCEL_ALARM "<CANCEL>"

	debug_logger("ALARM_WINDOW(%s:%d) REQUESTED: [%.32s], LEVEL: %d\n",__file__,__line__,caption,level);

	if ( level == ALARM_INPUT && input ){
		int ch;
		int curpos;
		int input_offset;
		int real_len;
		lines = 3;
		input_offset = strlen(caption) + 1;
		longest = 4 + strlen(caption) + input_len;
		walarm->height = lines;
		walarm->width  = longest;
		walarm->start_x = screen->start_x + ((screen->width  - longest)/2);
		walarm->start_y = screen->start_y + ((screen->height - lines) / 2);
		walarm->win = newwin(walarm->height,walarm->width, walarm->start_y, walarm->start_x);
		wattron(walarm->win,COLOR_PAIR(ALARM_COLOR_INPUT));
		x = 0;
		y = 0;
		w = walarm->width;
		h = walarm->height;
		for(j = y; j <= y + h; ++j)
			for(i = x; i <= x + w; ++i)
				mvwaddch(walarm->win,j, i, ' ');
		box(walarm->win,0,0);
		mvwprintw(walarm->win,1,1,"%s",caption);
		curs_set(2);
		wattron(walarm->win,A_UNDERLINE);
		for ( i = 0; i < input_len; i++ ){
			mvwaddch(walarm->win,1,input_offset+i, ' ');			
		}	
		real_len = strlen(input);
		mvwprintw(walarm->win,1,input_offset,"%s",input);
		for ( i = real_len; i < input_len; i++ ) input[i] = ' ';
		input[i] = 0x00;
		curpos = real_len;
		mvwaddch(walarm->win,1,input_offset+curpos,' '); 
		wmove(walarm->win,1,input_offset+curpos);
		wrefresh(walarm->win);
		while ( (ch = getch()) != KEY_ENTER && ch != 0x000A && ch != 0x001B){

			if ( (curpos < input_len) && 
			     ((ch >= 'A' && ch <= 'Z')||
			     (ch >= 'a' && ch <= 'z')||
			     (ch >= '0' && ch <= '9')||
			     (ch == '-')|| 
			     (ch == '+')|| 
			     (ch == '_')|| 
			     (ch == ':')|| 
			     (ch == ',')|| 
			     (ch == '<')|| 
			     (ch == '>')|| 
			     (ch == '(')|| 
			     (ch == ')')|| 
			     (ch == '[')|| 
			     (ch == ']')|| 
			     (ch == '{')|| 
			     (ch == '}')|| 
			     (ch == ';')|| 
			     (ch == ' ')|| 
			     (ch == '/')|| 
			     (ch == '.'))
			   )
			 {

				input[curpos] = (char)ch; 
				mvwaddch(walarm->win,1,input_offset+curpos,ch); 
				curpos++;
				wmove(walarm->win,1,input_offset+curpos);
				wrefresh(walarm->win); 
				continue;
			}
			if ( ch == KEY_BACKSPACE || ch == 0x0008 ){
				curpos--;
				if ( curpos < 0 ){ curpos = 0; continue; }
				input[curpos] = ' ';
				mvwaddch(walarm->win,1,input_offset+curpos,' '); 
				wmove(walarm->win,1,input_offset+curpos);
				wrefresh(walarm->win);
				continue;
			}
			if ( ch == KEY_LEFT ){
				curpos--;
				if ( curpos < 0 ){ curpos = 0; continue; }
				// mvwaddch(walarm->win,1,input_offset+curpos,input[curpos]);
				wmove(walarm->win,1,input_offset+curpos);
				wrefresh(walarm->win);
				continue;
			}
			if ( ch == KEY_RIGHT ){
				curpos++;
				if ( curpos >= input_len ){ curpos = input_len - 1; continue; }
				// mvwaddch(walarm->win,1,input_offset+curpos,input[curpos]);
				wmove(walarm->win,1,input_offset+curpos);
				wrefresh(walarm->win);
				continue;
			}
		}
		curs_set(0);
		wattroff(walarm->win,A_UNDERLINE);
		werase(walarm->win);
		delwin(walarm->win);
		walarm->win = NULL;
		touchwin(root);
		refresh();
		if ( sub1->win ) touchwin(sub1->win);
		if ( sub1->win ) wrefresh(sub1->win);
		if ( sub2->win ) touchwin(sub2->win);
		if ( sub2->win ) wrefresh(sub2->win);
		if ( runner->win ) touchwin(runner->win);
		if ( runner->win ) wrefresh(runner->win);
		if ( ch == 0x001B ) 
			return(-1);
		else
			return(0);
	}


	cursel = input_len;

	lines = 0;
	longest = 0;
	ptr1 = caption;
	ptr2 = ptr1;
	content = NULL;
	while ( 1 ){
		if ( *ptr2 == '\n' || *ptr2 == '\0' ){
			if ( longest < (ptr2 - ptr1) ) longest = ptr2 - ptr1;
			content = (char **)realloc(content,sizeof(char *) * (lines+1));
			content[lines] = (char *)malloc((ptr2-ptr1) + 2);
			bzero(content[lines],(ptr2-ptr1)+2);
			memcpy(content[lines],ptr1,(ptr2-ptr1));
			lines++;
			ptr1 = ptr2;
			ptr1++;
		}
		if ( *ptr2 == '\0' ) break;
		ptr2++;
	}	
	if ( longest == 0 ) longest = strlen(caption);

	walarm->height  = lines + 5;
	walarm->width   = longest + 4;
	walarm->start_x = screen->start_x + ((screen->width - longest)/2);
	walarm->start_y = screen->start_y + ((screen->height - lines)/2);



	x = 0;
	y = 0;
	w = walarm->width;
	h = walarm->height;


	walarm->win = newwin(walarm->height,walarm->width, walarm->start_y, walarm->start_x);
	if ( level == ALARM_FATAL ){
		wattron(walarm->win,COLOR_PAIR(ALARM_COLOR_FATAL));
	} else if ( level == ALARM_ERROR) {
		wattron(walarm->win,COLOR_PAIR(ALARM_COLOR_ERROR));
	} else if ( level == ALARM_WARNING) {
		wattron(walarm->win,COLOR_PAIR(ALARM_COLOR_WARNING));
	} else if ( level == ALARM_OKCANCEL) {
		wattron(walarm->win,COLOR_PAIR(ALARM_COLOR_OKCANCEL));
	} else {
		wattron(walarm->win,COLOR_PAIR(ALARM_COLOR_INFO));
	}
	for(j = y; j <= y + h; ++j)
		for(i = x; i <= x + w; ++i)
			mvwaddch(walarm->win,j, i, ' ');
	box(walarm->win,0,0);
	for ( i = 0; i < lines; i++ ){
		mvwprintw(walarm->win,2+i,  2,  "%s",content[i]);
		free(content[i]);
	}
	free(content);
	if ( level == ALARM_OKCANCEL ){
		int ch; 
		int ok_offset;
		int cancel_offset;
		char ok_alarm[1024];
		char cancel_alarm[1024];


		strcpy(ok_alarm,OK_ALARM);
		strcpy(cancel_alarm,CANCEL_ALARM);

		if ( input ){
			char *ptr;
			strcpy(ok_alarm,input);
			ptr = ok_alarm;
			while ( *ptr && *ptr != '|' ) ptr++;
			if ( *ptr == '|' ){
				*ptr = 0x00;
				ptr++;
				strcpy(cancel_alarm,ptr);
			}


		}


		ok_offset = walarm->width/2 - (strlen(ok_alarm)+1);
		cancel_offset = walarm->width/2 + 1;
		ch = 0;
		while(ch != KEY_ENTER && ch != 0x000A ){	
			if ( ch == 0x001B ){
				werase(walarm->win);
				delwin(walarm->win);
				walarm->win = NULL;
				touchwin(root);
				refresh();
				if ( sub1->win ) touchwin(sub1->win);
				if ( sub1->win ) wrefresh(sub1->win);
				if ( sub2->win ) touchwin(sub2->win);
				if ( sub2->win ) wrefresh(sub2->win);
				if ( runner->win ) touchwin(runner->win);
				if ( runner->win ) wrefresh(runner->win);
				return(-1);
			}
			if ( cursel == ANSWER_OK ){
				wattron(walarm->win,A_REVERSE);
				mvwprintw(walarm->win,walarm->height  - 2, ok_offset,  "%s",ok_alarm);
				wattroff(walarm->win,A_REVERSE);
				mvwprintw(walarm->win,walarm->height  - 2, cancel_offset,  "%s",cancel_alarm);
			} else {
				wattroff(walarm->win,A_REVERSE);
				mvwprintw(walarm->win,walarm->height  - 2, ok_offset,  "%s",ok_alarm);
				wattron(walarm->win,A_REVERSE);
				mvwprintw(walarm->win,walarm->height  - 2, cancel_offset,  "%s",cancel_alarm);
			}
			wrefresh(walarm->win);
			ch = getch();
			if ( ch == KEY_BTAB || ch == KEY_LEFT || ch == KEY_RIGHT || ch == 0x0009 ){
				if ( cursel == ANSWER_OK ) 
					cursel = ANSWER_CANCEL;
				else
					cursel = ANSWER_OK;
			}
		}
		werase(walarm->win);
		delwin(walarm->win);
		walarm->win = NULL;
		touchwin(root);
		refresh();
		if ( sub1->win ) touchwin(sub1->win);
		if ( sub1->win ) wrefresh(sub1->win);
		if ( sub2->win ) touchwin(sub2->win);
		if ( sub2->win ) wrefresh(sub2->win);
		if ( runner->win ) touchwin(runner->win);
		if ( runner->win ) wrefresh(runner->win);
		return(cursel);
	} else { 
		wattron(walarm->win,A_REVERSE);
		if ( level == ALARM_FATAL ){
			mvwprintw(walarm->win,walarm->height  - 2, walarm->width/2 - strlen(ERROR_ALARM)/2,  "%s",ERROR_ALARM);
		} else {
			mvwprintw(walarm->win,walarm->height  - 2, walarm->width/2 - strlen(INFO_ALARM)/2,  "%s",INFO_ALARM);
		}
		wrefresh(walarm->win);
	}



	{ 
		int ch;
		while ( (ch = getch()) != KEY_ENTER && ch != 0x000A );
	}
	werase(walarm->win);
	delwin(walarm->win);
	if ( level == ALARM_FATAL ){
		erase();
		refresh();
		endwin();
		exit(2);
	}
	walarm->win = NULL;
	touchwin(root);
	refresh();
	if ( sub1->win) touchwin(sub1->win);
	if ( sub1->win) wrefresh(sub1->win);
	if ( sub2->win) touchwin(sub2->win);
	if ( sub2->win) wrefresh(sub2->win);
	if ( runner->win ) touchwin(runner->win);
	if ( runner->win ) wrefresh(runner->win);
	return(0);
}

int current_runner_last_line;
int current_runner_last_col;
int current_runner_current_x;
int current_runner_current_y;

void create_runner(int x,int y,int width,int height,char *caption){
	int w,h,i,j;

	runner->height  = height;
	runner->width   = width;
	runner->start_x = x;
	runner->start_y = y;



	x = 0;
	y = 0;
	w = runner->width;
	h = runner->height;


	if ( runner->win == NULL ){ runner->win = newwin(runner->height,runner->width,runner->start_y,runner->start_x); }
	wattron(runner->win,COLOR_PAIR(RUNNER_COLOR));


	for(j = y; j <= y + h; ++j)
		for(i = x; i <= x + w; ++i)
			mvwaddch(runner->win,j, i, ' ');

	box(runner->win,0,0);
	wattron(runner->win,A_BOLD);
	mvwprintw(runner->win,y, x + ((runner->width  - strlen(caption)) / 2),"%s",caption);
	wrefresh(runner->win);
	refresh();
}

void end_runner(){
		if ( runner->win ){
			werase(runner->win);
			delwin(runner->win);
		}
		runner->win = NULL;
		touchwin(root);
		refresh();
		if ( sub1->win ) touchwin(sub1->win);
		if ( sub1->win ) wrefresh(sub1->win);
		if ( sub2->win ) touchwin(sub2->win);
		if ( sub2->win ) wrefresh(sub2->win);
}

void add_scroller(char *text){
	char c;
	int last_line;
	int last_col;
	int current_x; 
	int current_y;
	last_line = current_runner_last_line;
	last_col = current_runner_last_col;
	current_x = current_runner_current_x;
	current_y = current_runner_current_y;
	while ( c = *(text++) ){
		if ( c == '\r' ){ current_x = 1; continue; }
		if ( c == '\n' ){ 
			current_y++; 
			if ( current_y > last_line ){ 
				int j;
				current_y--;
				for ( ;  current_x <= last_col; current_x++ ){
					mvwaddch(runner->win,current_y, current_x,' ');
				}
				wrefresh(runner->win);
				scroll(runner->win);
				box(runner->win,0,0);
				wrefresh(runner->win);
			}
			current_x = 1;
			continue;
		}
		if ( c == '\t' ) c = ' ';
		if ( isprint(c)){ 
			current_x++;
			if ( current_x > last_col ){
				current_y++; 
				if ( current_y > last_line ){ 
					scroll(runner->win);
					box(runner->win,0,0);
					wrefresh(runner->win);
					current_y--;
				}
				current_x = 1;
			}
			mvwaddch(runner->win,current_y, current_x,c);
			wrefresh(runner->win);
		}
	}
	current_runner_current_x = current_x;
	current_runner_current_y = current_y;

}


#define scroll_logger(fmt, ...) _scroll_logger(__FILE__,__LINE__,fmt, ##__VA_ARGS__)

void _scroll_logger(char *__file__, int __line__, const char *fmt, ...){
        char p[102400];
        va_list ap;
        struct timeval tv;
        struct tm _tm;
        struct tm *tm;
        char datestamp[512];
        gettimeofday(&tv,NULL);
        tm = localtime_r(&tv.tv_sec,&_tm);
        sprintf(datestamp,"[%04d-%02d-%02d %02d:%02d:%02d.%06d] ",
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec);

        va_start(ap,fmt);
        vsnprintf(p,102400,fmt,ap);
        va_end(ap);

	add_scroller(datestamp);
	add_scroller(p);

	debug_logger("SCROLL_LOGGER REQUESTED (%s:%d): [%.100s]\n",__file__,__line__,p);

}

void c_logger(const char *fmt, ...){
        char p[102400];
        va_list ap;

        va_start(ap,fmt);
        vsnprintf(p,102400,fmt,ap);
        va_end(ap);

	add_scroller(p);

	touchwin(runner->win);
	wrefresh(runner->win);

}



int create_scroller(char *caption){
	if ( sub2->win ){
		create_runner(sub2->start_x + 1,sub2->start_y + 1, sub2->width - 2, sub2->height - 2, caption);
        } else if ( sub1->win ) {
		create_runner(sub1->start_x + 1,sub1->start_y + 1, sub1->width - 2, sub1->height - 2, caption);
        } else {
		create_runner(screen->start_x + 1,screen->start_y + 1, screen->width - 2, screen->height - 2, caption);
	}
	scrollok(runner->win,true);
	current_runner_last_line = runner->height - 2; 
	current_runner_last_col  = runner->width - 2; 
	current_runner_current_x = 1;
	current_runner_current_y = 1;
}





int run_program(char *exe, char **arg,char *caption, char *final_prompt){
	int pid;
	int fd_in;
	int fd_out;
	char tempfile[1024];
	sprintf(tempfile,"/tmp/exec_log_%d",getpid());
	unlink(tempfile);
	int last_line;
	int last_col;
	int current_x; 
	int current_y;
	signal(SIGCHLD,reaper);

	if ( sub2->win ){
		create_runner(sub2->start_x + 1,sub2->start_y + 1, sub2->width - 2, sub2->height - 2, caption);
        } else if ( sub1->win ) {
		create_runner(sub1->start_x + 1,sub1->start_y + 1, sub1->width - 2, sub1->height - 2, caption);
        } else {
		create_runner(screen->start_x + 1,screen->start_y + 1, screen->width - 2, screen->height - 2, caption);
	}
	scrollok(runner->win,true);

	last_line = runner->height - 2; 
	last_col  = runner->width - 2; 
	current_x = 1;
	current_y = 1;

	if ((fd_in = open("/dev/zero",O_RDONLY)) < 0 ) return(-1);
	if ((fd_out = open(tempfile,O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR)) < 0 ){
			close(fd_in);
			return(-1);
	}
	if ( (pid = fork()) == 0 ){
		int sid;
		sid = setsid();
		dup2(fd_in,0);
		dup2(fd_out,1);
		dup2(fd_out,2);
		if ( fd_in > 2 )  close(fd_in);
		if ( fd_out > 2 ) close(fd_out);
		if ( execv(exe,arg) < 0 ){
			exit(2);
		}
	} else {
		int log;
		char c;
		sleep(1);
		log = open(tempfile,O_RDONLY | O_NONBLOCK);
		while ( 1 ){
			while ( read(log,&c,1) == 1 ){
			//	putchar(c);
			//
				if ( c == '\r' ){ current_x = 1; continue; }
				if ( c == '\n' ){ 
					current_y++; 
					if ( current_y > last_line ){ 
						int j;
						current_y--;
						for ( ;  current_x <= last_col; current_x++ ){
							mvwaddch(runner->win,current_y, current_x,' ');
						}
						wrefresh(runner->win);
						scroll(runner->win);
						box(runner->win,0,0);
						wrefresh(runner->win);
					}
					current_x = 1;
					continue;
				}
				if ( c == '\t' ) c = ' ';
				if ( isprint(c)){ 
					current_x++;
					if ( current_x > last_col ){
						current_y++; 
						if ( current_y > last_line ){ 
							scroll(runner->win);
							box(runner->win,0,0);
							wrefresh(runner->win);
							current_y--;
						}
						current_x = 1;
					}
					mvwaddch(runner->win,current_y, current_x,c);
					wrefresh(runner->win);
				}
			}
			if ( kill(pid,0) != 0 ) break;
			usleep(1000000);
		}
		close(log);
		unlink(tempfile);
		touchwin(runner->win);
		wrefresh(runner->win);
		if ( final_prompt ) alarm_window(final_prompt,ALARM_INFO,NULL,0);
		end_runner();
		return(last_status);
	}
	
}

void create_sub2(int x,int y,int width,int height,char *caption){
	int w,h,i,j;

	sub2->height  = height;
	sub2->width   = width;
	sub2->start_x = x;
	sub2->start_y = y;

	sub2->border.ls = '|';
	sub2->border.rs = '|';
	sub2->border.ts = '-';
	sub2->border.bs = '-';
	sub2->border.tl = '+';
	sub2->border.tr = '+';
	sub2->border.bl = '+';
	sub2->border.br = '+';


	x = 0;
	y = 0;
	w = sub2->width;
	h = sub2->height;


	if ( sub2->win == NULL ){ sub2->win = newwin(sub2->height,sub2->width,sub2->start_y,sub2->start_x); }
	wattron(sub2->win,COLOR_PAIR(BASE2_COLOR_NORMAL));


	for(j = y; j <= y + h; ++j)
		for(i = x; i <= x + w; ++i)
			mvwaddch(sub2->win,j, i, ' ');

	box(sub2->win,0,0);
	wattron(sub2->win,A_BOLD);
	mvwprintw(sub2->win,y, x + (sub1->width / 2 - strlen(caption) / 2),"%s",caption);
	wrefresh(sub2->win);
	refresh();
}

void create_sub1(){
	int x, y, w, h;
	int i,j;

	sub1->height  = rows - SUBWIN_Y_OFFSET * 2;
	sub1->width   = cols - SUBWIN_X_OFFSET * 2;
	sub1->start_x = SUBWIN_X_OFFSET;
	sub1->start_y = SUBWIN_Y_OFFSET;

	if ( sub1->win == NULL ){ sub1->win = newwin(sub1->height,sub1->width,sub1->start_y,sub1->start_x); }



	x = 0;
	y = 0;
	w = sub1->width;
	h = sub1->height;

	for(j = y; j <= y + h; ++j)
		for(i = x; i <= x + w; ++i)
			mvwaddch(sub1->win,j, i, ' ');


	box(sub1->win,0,0);
	wattron(sub1->win,A_BOLD);
	mvwprintw(sub1->win,y, x + (sub1->width / 2 - strlen(option[current_option].caption) / 2),"%s",option[current_option].caption);
	wattroff(sub1->win,A_BOLD);
	wrefresh(sub1->win);
	refresh();





}

void find_disks(int mode){
	DIR *dir;
	char fname[1024];
	struct dirent *diry;
	u_int64_t size;
	u_int64_t sectors;
	u_int64_t uptime;
	u_int64_t badsectors;
	char israid;
	int partitions;
	char buf[1024];
	FILE *fp;
	struct stat st;
	disks = 0;
	dir = opendir("/sys/class/block");
	if ( dir ){
		while ( (diry = readdir(dir)) != NULL ){
			SkDisk *d;
			if ( strcmp(diry->d_name,".") == 0 ) continue;
			if ( strcmp(diry->d_name,"..") == 0 ) continue;

			israid = 0;
			sprintf(fname,"/sys/class/block/%s/md",diry->d_name);
			if ( stat(fname,&st) == 0 && mode == MODE_ROOT_DISKS ){ israid = 1; continue; }
			if ( stat(fname,&st) == 0 && mode == MODE_FS_DISKS ){ israid = 1;  }

			sprintf(fname,"/sys/class/block/%s/partition",diry->d_name);
			if ( stat(fname,&st) == 0 && mode == MODE_ROOT_DISKS ) continue;
			if ( stat(fname,&st) != 0 && israid == 0 && mode == MODE_FS_DISKS ) continue;

			sprintf(fname,"/sys/class/block/%s/size",diry->d_name);
			fp = fopen(fname,"r");
			if ( fp == NULL ) continue;
			if ( fgets(buf,1024,fp) == NULL ) { fclose(fp); continue; }
			fclose(fp);
			if ( sscanf(buf,"%ju",&size) != 1 || size <= 0  ) continue;
			sectors = size;
			size *= (u_int64_t) BSIZE;
			// printf("/dev/%s -> [%s] RAID: %d\r\n",diry->d_name,showsize(size),israid);
			disk = (struct _disk *)realloc(disk,sizeof(struct _disk) * (disks+1));
			sprintf(disk[disks].devname,"/dev/%s",diry->d_name);
			sprintf(disk[disks].serial,"N.A.");
			sprintf(disk[disks].model,"N.A.");
			sprintf(disk[disks].uptime,"N.A.");
			sprintf(disk[disks].badsectors,"N.A.");
			if ( sk_disk_open(disk[disks].devname,&d) == 0 ){
				if ( sk_disk_smart_read_data(d) == 0 ){
					SkBool available;
					u_int64_t uptime;
					u_int64_t badsectors;
					const SkIdentifyParsedData *data;
					if ( sk_disk_smart_get_power_on(d,&uptime) == 0 ){
						sprintf(disk[disks].uptime,"%ju h",uptime/ ( 1000 * 3600));
					}
					if ( sk_disk_smart_get_bad(d,&badsectors) == 0 ){
						sprintf(disk[disks].badsectors,"%ju",badsectors);
					}
					if ( sk_disk_identify_is_available(d,&available) == 0 && available ){
						if ( sk_disk_identify_parse(d,&data) == 0 ){
							sprintf(disk[disks].serial,"%s",data->serial);
							sprintf(disk[disks].model,"%s",data->model);
						}
					}
				}
				sk_disk_free(d);
			}
			disk[disks].israid = israid;
			disk[disks].size = size;
			disk[disks].sectors = sectors;
			disks++;
		}			
	}
	closedir(dir);
	qsort(disk,disks,sizeof(struct _disk),disk_sorter);

}

int cur_part_action = 0;
int disk_index;
int part_index;

void show_part_options();

int leftright(int ch){
	switch(ch){
		case KEY_ENTER:
		case 0x000A:
			return(0);
			break;
		case KEY_RIGHT:
		case 0x0009:
			cur_part_action++;
			if ( cur_part_action > 3 ) cur_part_action = 0;
			show_part_options();
			break;
		case KEY_LEFT:
		case KEY_BTAB:
			cur_part_action--;
			if ( cur_part_action < 0 ) cur_part_action = 3;
			show_part_options();
			break;

	}	
	return(HANDLER_RETURN_STAY);

}

#define NEW_PARTITION 0
#define DEL_PARTITION 1
#define NEW_LAYOUT    2
#define NEW_LAYOUT2   3
#define NEW_PARTITION_TEXT "<New Partition>"
#define DEL_PARTITION_TEXT "<Del Partition>"
#define NEW_LAYOUT_TEXT    "<Std. layout(EFI, Remain: Linux)>"
#define NEW_LAYOUT2_TEXT   "<Std. RAID layout(EFI, Remain: Linux)>"
#define PART_Y_START 1
#define PART_X_START 1

void show_part_options(){
	int x_offset;
	int y_offset;
	x_offset = 0;
	y_offset = 0;
	wattroff(sub2->win,A_REVERSE);
	if ( cur_part_action == NEW_PARTITION ) wattron(sub2->win,A_REVERSE);
	mvwprintw(sub2->win,PART_Y_START + y_offset, PART_X_START + x_offset, NEW_PARTITION_TEXT);
	x_offset += strlen(NEW_PARTITION_TEXT) + 1;

	wattroff(sub2->win,A_REVERSE);
	if ( cur_part_action == DEL_PARTITION) wattron(sub2->win,A_REVERSE);
	mvwprintw(sub2->win,PART_Y_START + y_offset, PART_X_START + x_offset, DEL_PARTITION_TEXT);
	x_offset += strlen(DEL_PARTITION_TEXT) + 1;
	x_offset = 0;
	y_offset++;

	wattroff(sub2->win,A_REVERSE);
	if ( cur_part_action == NEW_LAYOUT ) wattron(sub2->win,A_REVERSE);
	mvwprintw(sub2->win,PART_Y_START + y_offset, PART_X_START + x_offset, NEW_LAYOUT_TEXT);
	x_offset += strlen(NEW_LAYOUT_TEXT) + 1;

	wattroff(sub2->win,A_REVERSE);
	if ( cur_part_action == NEW_LAYOUT2 ) wattron(sub2->win,A_REVERSE);
	mvwprintw(sub2->win,PART_Y_START + y_offset, PART_X_START + x_offset, NEW_LAYOUT2_TEXT );
	x_offset += strlen(NEW_LAYOUT2_TEXT ) + 1;

	wrefresh(sub2->win);

	return;
}



int wanted_raidlevel; 
#define LEVEL0  "[RAID-0] Stripe"
#define LEVEL1  "[RAID-1] Mirror"
#define LEVEL10 "[RAID-10] Mirror+Stripe"

void show_raidlevel(){
	int x_offset;
	if ( wanted_raidlevel == 1 ){
		x_offset = 1;
		wattroff(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL0);
		x_offset += strlen(LEVEL0) + 1;
		wattron(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL1);
		wattroff(sub2->win, A_REVERSE);
		x_offset += strlen(LEVEL1) + 1;
		wattroff(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL10);
		wattroff(sub2->win, A_REVERSE);
	} else if ( wanted_raidlevel == 0 ){
		x_offset = 1;
		wattron(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL0);
		x_offset += strlen(LEVEL0) + 1;
		wattroff(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL1);
		wattroff(sub2->win, A_REVERSE);
		x_offset += strlen(LEVEL1) + 1;
		wattroff(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL10);
		wattroff(sub2->win, A_REVERSE);
	} else {
		x_offset = 1;
		wattroff(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL0);
		x_offset += strlen(LEVEL0) + 1;
		wattroff(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL1);
		wattroff(sub2->win, A_REVERSE);
		x_offset += strlen(LEVEL1) + 1;
		wattron(sub2->win, A_REVERSE);
		mvwprintw(sub2->win,3,x_offset,LEVEL10);
		wattroff(sub2->win, A_REVERSE);
	}
	wrefresh(sub2->win);
}


int toggle_raidlevel(int key){
	if ( key == KEY_LEFT ){
		wanted_raidlevel--;
		if ( wanted_raidlevel < 0 ) wanted_raidlevel = 0;
		show_raidlevel();
	}
	if ( key == KEY_RIGHT ){
		wanted_raidlevel++;
		if ( wanted_raidlevel > 2 ) wanted_raidlevel = 2;
		show_raidlevel();
	}
	return(HANDLER_RETURN_STAY);
}


void create_raid(){
	char cmd[1024];
	struct _select2 *sel;
	int disks_found;
	int i;
	char buf[1024];
	int array_index;
	char caption[1024];
	wanted_raidlevel = 1;
RERUN_RAID_LIST:
	update_raidlist();
	array_index = 0;
	{
		DIR *dir;
		struct dirent *diry;
		dir = opendir("/dev/");
		if ( dir ){
			while ( (diry = readdir(dir)) != NULL ){
				if ( strncmp(diry->d_name,"md",2) != 0 ) continue;
				if ( strlen(diry->d_name) < 3 ) continue;
				if ( atoi(&diry->d_name[2]) >= array_index ) array_index = atoi(&diry->d_name[2]) + 1;
			}
			closedir(dir);
		}

	}
	touchwin(root);
	refresh();
	attron(COLOR_PAIR(BASE2_COLOR_NORMAL));
	create_sub1();
	wrefresh(sub1->win);

	if ( disk ) { free(disk); disk = NULL; }
	disks = 0;
	find_disks(MODE_FS_DISKS);

	if ( disks == 0 ){
		// Warn, no disks found!
		return;
	}
	sprintf(caption,"Select partitions/arrays for RAID /dev/md%d",array_index);
	create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4, caption);
	sel = (struct _select2 *)malloc(sizeof(struct _select2) * disks);
	bzero(sel,sizeof(struct _select) * disks);
	for ( i = 0; i < disks; i++ ){
		struct _raid *rd;
		char helper[1024];
		char helper2[124];
		if ( (rd = checkraidmember(disk[i].devname)) ){
			strcpy(helper2,showsize(rd->size));
			sprintf(helper,"%s (%s) [%s, Level: %d, Size: %s]",
					disk[i].devname, showsize(disk[i].size),
					rd->devname,rd->level,helper2);
			sel[i].useable = 0;
		} else {
			sel[i].useable = 1;
			sprintf(helper,"%s (%s)",
					disk[i].devname, showsize(disk[i].size));
		}
		sel[i].name     = strdup(helper);
		sel[i].selected = 0;
	}
	mvwprintw(sub2->win,1,1,"<SPACE>:Toggle sel. <UP/DOWN>:Part. <LEFT/RIGHT>: RAID-LEVEL <ESC>:Go back <CR>:Create");
	show_raidlevel();
	wrefresh(sub2->win);
SELECTOR_RERUN: 
	current_select = 0;
	disk_index = run_selector2(NULL,sub2,4,sel,disks,toggle_raidlevel);
	if ( disk_index < 0 ){
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
		return;
	}
	disks_found = 0;
	sprintf(buf,"Are you sure want to create RAID-Level %d (/dev/md%d) on\n",wanted_raidlevel == 2 ? 10 : wanted_raidlevel,array_index);
	for ( i = 0; i < disks; i++ ){
		if ( sel[i].selected && sel[i].useable == 0 ){
			char helper[1024];
			sprintf(helper,"Disk %s\n Not useable (Already RAID-member)!",sel[i].name);
			alarm_window(helper,ALARM_ERROR,NULL,0);
			sel[i].selected = 0;
			goto SELECTOR_RERUN;
		}
		if ( sel[i].selected ){
			disks_found++;
			sprintf(&buf[strlen(buf)],"[%s]",disk[i].devname);
		}
	}
	sprintf(&buf[strlen(buf)],"?");

	if ( disks_found < 2 && wanted_raidlevel < 2){
		alarm_window("You must select at least 2 partitions to build a Level 1 or Level 0 array",ALARM_ERROR,NULL,0);
		for ( i = 0; i < disks; i++ ){
			free(sel[i].name);
		}
		free(sel);
		goto RERUN_RAID_LIST;
	}
	if ( disks_found < 4 && wanted_raidlevel == 2){
		alarm_window("You must select at least 4 partitions to build a Level 10 array",ALARM_ERROR,NULL,0);
		for ( i = 0; i < disks; i++ ){
			free(sel[i].name);
		}
		free(sel);
		goto RERUN_RAID_LIST;
	}
	if ( alarm_window(buf,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
		for ( i = 0; i < disks; i++ ){
			free(sel[i].name);
		}
		free(sel);
	       goto RERUN_RAID_LIST;
	}
	sprintf(buf,"");
	disks_found = 0;
	for ( i = 0; i < disks; i++ ){
		if ( sel[i].selected ){
			disks_found++;
			sprintf(&buf[strlen(buf)]," %s",disk[i].devname);
		}
	}
	if ( wanted_raidlevel == 0 ){
		sprintf(cmd,RAID_0_CMD, array_index, disks_found,buf);
	} else if ( wanted_raidlevel == 1 ) {
		sprintf(cmd,RAID_1_CMD, array_index, disks_found,buf);
	} else {
		sprintf(cmd,RAID_10_CMD, array_index, disks_found,buf);
	}
	{
		int i;
		char *hlp;
		char *hlp2;
		char **arg;
		int args;
		char *ptr;
		int result;
		
		for ( i = 0; i < disks; i++ ){
			if ( sel[i].selected ){
				int jj;
				arg = NULL;
				args = 0;
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));	
				arg[args++] = RAID_CMD;
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));	
				arg[args++] = strdup("--zero-superblock");
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));	
				arg[args++] = strdup(disk[i].devname);
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));	
				arg[args++] = NULL;
				sprintf(buf,"Zeroing superblock of %s",disk[i].devname);
				result = run_program(arg[0],arg,buf,NULL);
				/*
				for ( jj = 0; jj < (args-1); jj++ ) free(arg[jj]);
				free(arg);
				sprintf(buf,"ZERO OF [%s] Result: %d",disk[i].devname,result);
				alarm_window(buf,ALARM_INFO,NULL,0);
				*/
			}
		}
		for ( i = 0; i < disks; i++ ){
			if ( sel[i].selected ){
				char block[512];
				int fd;
				int j;
				bzero(block,512);
				fd = open(disk[i].devname,O_WRONLY);
				if ( fd < 0 ){
					sprintf(buf,"Cannot open '%s' for writing",disk[i].devname);
					alarm_window(buf,ALARM_ERROR,NULL,0);
				} else {
					for ( j = 0; j < 100; j++ ){
						result = write(fd,block,512);
					}
					close(fd);
					/*
					sprintf(buf,"Superblock zeroed at '%s' (%d)",disk[i].devname,result);
					alarm_window(buf,ALARM_INFO,NULL,0);
					*/
				}
			}
		}

		arg = NULL;
		args = 0;
		hlp = strdup(cmd);
		hlp2 = hlp;
		while ( (ptr = strtok(hlp," \t")) != NULL ){
			hlp = NULL;
			arg = (char **)realloc(arg,sizeof(char *) * (args+1));	
			arg[args++] = strdup(ptr);
		}
		arg = (char **)realloc(arg,sizeof(char *) * (args+1));	
		arg[args++] = NULL;

		result = run_program(arg[0],arg,"Creating RAID","RAID completed");
		for ( i = 0; i < args; i++ ){
			if ( arg[i] ) free(arg[i]);
		}
		free(arg);
		free(hlp2);
		{

			char **arg;
			int args;
			char caption[1024];
			char fsname[1024];
			char result[1024];
			sprintf(fsname,"/dev/md%d",array_index);
			arg  = NULL; 
			args = 0;
			arg = (char **)realloc(arg,sizeof(char *) * (args+1));
			arg[args++] = strdup(EXT4_COMMAND);
			arg = (char **)realloc(arg,sizeof(char *) * (args+1));
			arg[args++] = strdup("-v");
			arg = (char **)realloc(arg,sizeof(char *) * (args+1));
			arg[args++] = strdup(fsname);
			arg = (char **)realloc(arg,sizeof(char *) * (args+1));
			arg[args++] = NULL;
			sprintf(fsname,"Creating EXT4 at /dev/md%d",array_index);
			sprintf(result,"EXT4 at /dev/md%d created",array_index);
			run_program(arg[0],arg,fsname,result);
			for ( i = 0; i < args-1; i++ ) free(arg[i]);
			free(arg);
		}
	}
	for ( i = 0; i < disks; i++ ){
		free(sel[i].name);
	}
	free(sel);
	goto RERUN_RAID_LIST;

	
}

void disk_setup(){
	int i;
	int parts;
	int shown;
	struct _select *sel;
	char new_caption[1024];
	char buf[1024];
	struct fdisk_partition *pa;
	struct fdisk_iter *itr;
	size_t partno_list[256];



DISK_GO_AGAIN:
	attron(COLOR_PAIR(BASE2_COLOR_NORMAL));
	create_sub1();
	if ( disk ) { free(disk); disk = NULL; }
	disks = 0;
	find_disks(MODE_ROOT_DISKS);

	if ( disks == 0 ){
		// Warn, no disks found!
		return;
	}

	create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4, "Select disk");
	sel = (struct _select *)malloc(sizeof(struct _select) * disks);
	bzero(sel,sizeof(struct _select) * disks);
	for ( i = 0; i < disks; i++ ){
		char helper[1024];
		sprintf(helper,"%s (%s) Serial:[%s], Bad-Sect: [%s], Model:[%s], Uptime:[%s]",
				disk[i].devname, showsize(disk[i].size), disk[i].serial, disk[i].badsectors, disk[i].model,disk[i].uptime);
		sel[i].name = strdup(helper);
	}
	current_select = 0;
	disk_index = run_selector(NULL,sub2,0,sel,disks,NULL);
	for ( i = 0; i < disks; i++ ){
		free(sel[i].name);
	}
	free(sel);
	if ( disk_index < 0 ){
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
		return;
	}
	shown = 0;
DISK_RELOAD_ME_AGAIN:
        sprintf(new_caption,"Setting up [%s]",disk[disk_index].devname);
        create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4,new_caption);				      

	disk[disk_index].ctx = fdisk_new_context();
	if ( disk[disk_index].ctx == NULL ){
		alarm_window("Cannot get Disk-Handle",ALARM_FATAL,NULL,0);
	}
	if ( fdisk_assign_device(disk[disk_index].ctx,disk[disk_index].devname,0) ){ 
		alarm_window("Cannot assign Disk-Handle",ALARM_FATAL,NULL,0);
	}

	disk[disk_index].cylinders     = fdisk_get_geom_cylinders(disk[disk_index].ctx);
	disk[disk_index].heads         = fdisk_get_geom_heads(disk[disk_index].ctx);
	disk[disk_index].geom_secs     = fdisk_get_geom_sectors(disk[disk_index].ctx);
	disk[disk_index].first_lba     = fdisk_get_first_lba(disk[disk_index].ctx);
	disk[disk_index].last_lba      = fdisk_get_last_lba(disk[disk_index].ctx);
	disk[disk_index].sector_size   = fdisk_get_sector_size(disk[disk_index].ctx);
	disk[disk_index].label         = fdisk_get_label(disk[disk_index].ctx,NULL);
	disk[disk_index].labels        = fdisk_get_nlabels(disk[disk_index].ctx);






	disk[disk_index].tb = NULL;
	if ( fdisk_get_partitions(disk[disk_index].ctx,&disk[disk_index].tb) != 0 ){
		if ( alarm_window("Cannot read Partition-Table\n    Create a new one?",ALARM_OKCANCEL,NULL,0) != ANSWER_OK){
			fdisk_deassign_device(disk[disk_index].ctx,0);
			fdisk_unref_context(disk[disk_index].ctx);
			goto DISK_GO_AGAIN;
		}
		disk[disk_index].tb = fdisk_new_table();
		if ( fdisk_reset_table(disk[disk_index].tb) != 0 ){
			alarm_window("Cannot reset Partition-Table",ALARM_FATAL,NULL,0);
		}
		if ( fdisk_create_disklabel(disk[disk_index].ctx,"GPT") != 0 && fdisk_create_disklabel(disk[disk_index].ctx,"DOS") != 0 ){
			alarm_window("Cannot assigen Disk-Label (neither GPT or DOS)",ALARM_FATAL,NULL,0);
		}
		if ( fdisk_apply_table(disk[disk_index].ctx,disk[disk_index].tb) ){
			alarm_window("Cannot apply table (neither GPT or DOS)",ALARM_FATAL,NULL,0);
		}
		if ( fdisk_write_disklabel(disk[disk_index].ctx) != 0 ){
			alarm_window("Cannot write Disk-Label",ALARM_FATAL,NULL,0);
		}
		fdisk_deassign_device(disk[disk_index].ctx,0);
		fdisk_unref_context(disk[disk_index].ctx);
		goto DISK_RELOAD_ME_AGAIN;
	}
	disk[disk_index].nents = fdisk_table_get_nents(disk[disk_index].tb);

	sprintf(buf,"Disk-info\nLABEL: [%s], Model: [%s]\nCylinders: %jd,Sectors: %jd\nSector-Size: %ld,Heads: %jd\nFirst LBA: %jd, Last-LBA: %jd\nPartitions: %d",
			fdisk_label_get_name(disk[disk_index].label),
			disk[disk_index].model,
			disk[disk_index].cylinders,
			disk[disk_index].geom_secs,
			disk[disk_index].sector_size,
			disk[disk_index].heads,
			disk[disk_index].first_lba,
			disk[disk_index].last_lba,
			disk[disk_index].nents);
	/*
	{
		struct fdisk_label *lb;
		lb = NULL;
		while ( fdisk_next_label(disk[disk_index].ctx,&lb) == 0 ){
			strcat(buf,"[");
			strcat(buf,fdisk_label_get_name(lb));
			strcat(buf,"]");
		}
	}
	*/
	if ( shown == 0 ){
		alarm_window(buf,ALARM_INFO,NULL,0);
	}
	shown = 1;
	pa = NULL;
	parts = 0;
	if ( disk[disk_index].nents ){
		sel = (struct _select *)malloc(sizeof(struct _select) * disk[disk_index].nents);
		bzero(sel,sizeof(struct _select) * disk[disk_index].nents);
	}
	itr = fdisk_new_iter(FDISK_ITER_FORWARD);
	while ( fdisk_table_next_partition(disk[disk_index].tb,itr,&pa) == 0 ){
		const char *name;
		const char *uuid;
		uint64_t start, size;
		fdisk_sector_t end;
		size_t partno;
		const struct fdisk_parttype *typ;
		const char *typname;

		name   = fdisk_partition_get_name(pa);
		uuid   = fdisk_partition_get_uuid(pa);
		end    = fdisk_partition_get_end(pa);
		start  = fdisk_partition_get_start(pa);
		size   = fdisk_partition_get_size(pa);
		partno = fdisk_partition_get_partno(pa);
		partno_list[parts] = partno;
		typname = NULL;
		typ    = fdisk_partition_get_type(pa);
		if ( typ ){
			typname = fdisk_parttype_get_name(typ);
		}

		/*
		sprintf(buf,"Part: %d\nName: [%s]\nUUID: [%s]\nStart: %jd\nSize: %jd\nEnd: %jd\nPartno: %d\nType: [%s]",parts,
				name ? name : "NULL",
				uuid ? uuid : "NULL",
				start,size,end,partno,
				typname ? typname : "NULL" );
		alarm_window(buf,ALARM_INFO,NULL,0);
		*/
		sprintf(buf,"%02d [%s] [%jd - %jd] (%jd Blocks)",partno,typname ? typname : "unknown",start,end,size);
		sel[parts].name = strdup(buf);
		parts++;
	}
	fdisk_free_iter(itr);

	cur_part_action = 0;
	if ( parts == 0 ){ cur_part_action = NEW_LAYOUT; }

	show_part_options();

	current_select = 0;
	part_index = run_selector(NULL,sub2,3,sel,parts,leftright);

	for ( i = 0; i < parts; i++ ){
		free(sel[i].name);
	}
	if ( parts) free(sel);
	
	if ( part_index == -1 ){
		fdisk_unref_table(disk[disk_index].tb);
		fdisk_deassign_device(disk[disk_index].ctx,0);
		fdisk_unref_context(disk[disk_index].ctx);
		goto DISK_GO_AGAIN; 
	}
	if ( cur_part_action == DEL_PARTITION ){
		size_t partno;
		char new_label[1024];


		partno = partno_list[part_index];
		sprintf(new_label,"Delete partion %d?",partno);
		if ( alarm_window(new_label,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
			fdisk_deassign_device(disk[disk_index].ctx,0);
			fdisk_unref_context(disk[disk_index].ctx);
			goto DISK_RELOAD_ME_AGAIN;
		}
		if ( fdisk_delete_partition(disk[disk_index].ctx,partno) != 0 ){
			sprintf(new_label,"Deleting partion %d failed!",partno);
			alarm_window(new_label,ALARM_ERROR,NULL,0);
			fdisk_deassign_device(disk[disk_index].ctx,0);
			fdisk_unref_context(disk[disk_index].ctx);
			goto DISK_RELOAD_ME_AGAIN;
		}
		if ( fdisk_write_disklabel(disk[disk_index].ctx) ){
			alarm_window("Writing partition table failed!",ALARM_ERROR,NULL,0);
			fdisk_deassign_device(disk[disk_index].ctx,0);
			fdisk_unref_context(disk[disk_index].ctx);
			goto DISK_RELOAD_ME_AGAIN;
		}
		fdisk_deassign_device(disk[disk_index].ctx,0);
		fdisk_unref_context(disk[disk_index].ctx);
		sprintf(new_label,"Partion %d successfully deleted!",partno);
		alarm_window(new_label,ALARM_INFO,NULL,0);
		goto DISK_RELOAD_ME_AGAIN;

	}
	if ( cur_part_action == NEW_LAYOUT || cur_part_action == NEW_LAYOUT2  ){

			struct fdisk_partition *part;
			int index_efi;
			int index_linux_raid;
			int index_linux;
			int codes;
			int i;
			uintmax_t first_lba;
			uintmax_t part_size;
			struct fdisk_parttype **code;
			struct fdisk_table *tb;
			char new_label[1024];
			const char *disk_label; // The Partition table-type

			disk[disk_index].tb = fdisk_new_table();
			if ( fdisk_reset_table(disk[disk_index].tb) != 0 ){
				alarm_window("Cannot reset Partition-Table",ALARM_FATAL,NULL,0);
			}
			if ( fdisk_create_disklabel(disk[disk_index].ctx,"GPT") != 0 && fdisk_create_disklabel(disk[disk_index].ctx,"DOS") != 0 ){
				alarm_window("Cannot assigen Disk-Label (neither GPT or DOS)",ALARM_FATAL,NULL,0);
			}
			if ( fdisk_apply_table(disk[disk_index].ctx,disk[disk_index].tb) ){
				alarm_window("Cannot apply table (neither GPT or DOS)",ALARM_FATAL,NULL,0);
			}
			if ( fdisk_write_disklabel(disk[disk_index].ctx) != 0 ){
				alarm_window("Cannot write Disk-Label",ALARM_FATAL,NULL,0);
			}

			disk[disk_index].label         = fdisk_get_label(disk[disk_index].ctx,NULL);
			disk_label = fdisk_label_get_name(disk[disk_index].label);		    
			sprintf(new_label,"Are you sure you want to clear all data\nand create a bootable layout on %s [%s]?",disk[disk_index].devname,disk_label);
			if ( alarm_window(new_label,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			codes = fdisk_label_get_nparttypes(disk[disk_index].label);
			code = (struct fdisk_parttype **)malloc(sizeof(struct fdisk_parttype *) * codes);
			index_efi = -1;
			index_linux = -1;
			index_linux_raid = -1;
			for ( i = 0; i < codes; i++ ){
				const char *name;
				code[i] = fdisk_label_get_parttype(disk[disk_index].label,(size_t)i);
				name = fdisk_parttype_get_name(code[i]);
				if ( index_efi == -1 && strncasecmp(name,"EFI",3) == 0 ) index_efi = i;
				if ( index_linux_raid == -1 && strncasecmp(name,"Linux RAID",10) == 0 ) index_linux_raid = i;
				if ( index_linux_raid == -1 && strncasecmp(name,"Linux-RAID",10) == 0 ) index_linux_raid = i;
				if ( index_linux_raid == -1 && strncasecmp(name,"Linux_RAID",10) == 0 ) index_linux_raid = i;
				if ( index_linux      == -1 && strncasecmp(name,"Linux FILE",10) == 0 ) index_linux = i;
			}
			if ( index_linux_raid == -1 || index_efi == -1 || index_linux == -1 ){
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				alarm_window("Cannot get Credentials",ALARM_FATAL,NULL,0);
			}	
			disk[disk_index].tb = fdisk_new_table();
			if ( fdisk_reset_table(disk[disk_index].tb) != 0 ){
				alarm_window("Cannot reset Partition-Table",ALARM_FATAL,NULL,0);
			}
			if ( fdisk_create_disklabel(disk[disk_index].ctx,"GPT") != 0 && fdisk_create_disklabel(disk[disk_index].ctx,"DOS") != 0 ){
				alarm_window("Cannot assigen Disk-Label (neither GPT or DOS)",ALARM_FATAL,NULL,0);
			}
			if ( fdisk_apply_table(disk[disk_index].ctx,disk[disk_index].tb) ){
				alarm_window("Cannot apply table (neither GPT or DOS)",ALARM_FATAL,NULL,0);
			}
			if ( fdisk_write_disklabel(disk[disk_index].ctx) != 0 ){
				alarm_window("Cannot write Disk-Label",ALARM_FATAL,NULL,0);
			}
			part = fdisk_new_partition();
			fdisk_partition_partno_follow_default(part,1);
			fdisk_partition_set_start(part,disk[disk_index].first_lba);
			fdisk_partition_set_size(part,204800);
			fdisk_partition_set_name(part,"GIX-Linux-EFI");
			fdisk_partition_set_type(part,code[index_efi]);
			fdisk_partition_size_explicit(part,1);
			if ( fdisk_add_partition(disk[disk_index].ctx,part,NULL) ){
				alarm_window("Adding EFI partition failed!",ALARM_ERROR,NULL,0);
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			if ( fdisk_write_disklabel(disk[disk_index].ctx) ){
				alarm_window("Writing partition table failed!",ALARM_ERROR,NULL,0);
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			tb = NULL;
			if ( fdisk_get_partitions(disk[disk_index].ctx,&tb) ){
				alarm_window("Re-loading partition table failed!",ALARM_ERROR,NULL,0);
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}

			part = fdisk_table_get_partition(tb,0); // Get EFI-Partition
			if ( part == NULL ){
				alarm_window("Re-reading partition table failed!",ALARM_ERROR,NULL,0);
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			first_lba = fdisk_partition_get_size(part) + disk[disk_index].first_lba;
			part_size = disk[disk_index].last_lba - first_lba;

			part = fdisk_new_partition();
			fdisk_partition_partno_follow_default(part,1);
			fdisk_partition_set_start(part,first_lba);
			fdisk_partition_set_size(part,part_size);
			fdisk_partition_set_name(part,"GIX-Linux");
			if ( cur_part_action == NEW_LAYOUT2 ){
				fdisk_partition_set_type(part,code[index_linux_raid]);
			} else { 
				fdisk_partition_set_type(part,code[index_linux]);
			}
			fdisk_partition_size_explicit(part,1);
			if ( fdisk_add_partition(disk[disk_index].ctx,part,NULL) ){
				alarm_window("Adding Linux RAID partition failed!",ALARM_ERROR,NULL,0);
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			if ( fdisk_write_disklabel(disk[disk_index].ctx) ){
				alarm_window("Writing partition table failed!",ALARM_ERROR,NULL,0);
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}




			fdisk_deassign_device(disk[disk_index].ctx,0);
			fdisk_unref_context(disk[disk_index].ctx);
			sprintf(new_label,"Basic  layout successfully created, creating EFI-Filesystem now...");
			alarm_window(new_label,ALARM_INFO,NULL,0);
			{
				char **arg;
				int args;
				char caption[1024];
				char efiname[1024];
				char result[1024];
				int i;
				sprintf(efiname,"%s1",disk[disk_index].devname);
				arg  = NULL; 
				args = 0;
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = strdup(VFAT_COMMAND);
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = strdup("-v");
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = strdup(efiname);
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = NULL;
				sprintf(efiname,"Creating VFAT at %s1",disk[disk_index].devname);
				sprintf(result,"VFAT at %s1 created",disk[disk_index].devname);
				run_program(arg[0],arg,efiname,result);
				for ( i = 0; i < args-1; i++ ) free(arg[i]);
				free(arg);
				if ( cur_part_action == NEW_LAYOUT ){
					char **arg;
					int args;
					char caption[1024];
					char efiname[1024];
					char result[1024];
					sprintf(efiname,"%s2",disk[disk_index].devname);
					arg  = NULL; 
					args = 0;
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(EXT4_COMMAND);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup("-v");
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(efiname);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = NULL;
					sprintf(efiname,"Creating EXT4 at %s2",disk[disk_index].devname);
					sprintf(result,"EXT4 at %s2 created",disk[disk_index].devname);
					run_program(arg[0],arg,efiname,result);
					for ( i = 0; i < args-1; i++ ) free(arg[i]);
					free(arg);
				}
			}
			goto DISK_RELOAD_ME_AGAIN;
		}
		if ( cur_part_action == NEW_PARTITION ){
			int longest;
			int new_type;
			struct fdisk_parttype **code;
			int codes = 0;
			uintmax_t first_lba;
			uintmax_t last_lba;
			char buf[1024];
			char new_label[1024];
			const char *disk_label; // The Partition table-type
						
						
						
			disk_label = fdisk_label_get_name(disk[disk_index].label);		    
			codes = fdisk_label_get_nparttypes(disk[disk_index].label);
			code = (struct fdisk_parttype **)malloc(sizeof(struct fdisk_parttype *) * codes);
			sprintf(new_caption,"Create new partition on [%s] (Mode:(%s))",disk[disk_index].devname,disk_label);
			create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4,new_caption);				      
			sel = (struct _select *)malloc(sizeof(struct _select ) * codes);
			bzero(sel,sizeof(struct _select ) * codes);
			longest = 0;
			for ( i = 0; i < codes; i++ ){
				code[i] = fdisk_label_get_parttype(disk[disk_index].label,(size_t)i);
				if ( strlen(fdisk_parttype_get_name(code[i])) > longest ) longest = strlen(fdisk_parttype_get_name(code[i]));
			}
			for ( i = 0; i < codes; i++ ){
				if ( strcmp(disk_label,"gpt") == 0 ){
					sprintf(buf,"%s",
					fdisk_parttype_get_name(code[i]));
				} else {
					sprintf(buf,"[%04X] %s",
					fdisk_parttype_get_code(code[i]),fdisk_parttype_get_name(code[i]));
				}
				{ 
					int j; 
					for ( j = strlen(fdisk_parttype_get_name(code[i])); j < longest; j++ ) strcat(buf," ");
				}
				sel[i].name = strdup(buf);
			}
			current_select = 0;
			new_type = run_selector(NULL,sub2,2,sel,codes,NULL);
			if ( new_type < 0 ) goto DISK_RELOAD_ME_AGAIN;


			for ( i = 0; i < codes; i++ ){
				free(sel[i].name);
			}
			free(sel);
	INPUT_LBA_FIRST:
			// We have a part-type now...continue to start lba...
			sprintf(new_label,"Starting LBA(min: %ju, max: %ju):",disk[disk_index].first_lba,disk[disk_index].last_lba);
			sprintf(buf,"%ju",disk[disk_index].first_lba);
			if ( alarm_window(new_label, ALARM_INPUT, buf, 16) ){
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			sscanf(buf,"%ju",&first_lba);
			if ( first_lba < disk[disk_index].first_lba || first_lba > disk[disk_index].last_lba ){
				sprintf(caption,"Invalid first sector!\nMust be between %jd and %jd",disk[disk_index].first_lba,disk[disk_index].last_lba);
				alarm_window(caption,ALARM_ERROR,NULL,0);
				goto INPUT_LBA_FIRST;
			}	
			/*
			sprintf(new_label,"Using First-LBA: %jd",first_lba);
			alarm_window(new_label,ALARM_INFO,NULL,0);	
			*/
	INPUT_LBA_LAST:
			sprintf(new_label,"Ending LBA(min: %ju, max: %ju), '+SizeKMB' or 'max':",first_lba,disk[disk_index].last_lba);
			sprintf(buf,"%ju",disk[disk_index].last_lba);
			if ( alarm_window(new_label, ALARM_INPUT, buf, 16) ){
				fdisk_deassign_device(disk[disk_index].ctx,0);
				fdisk_unref_context(disk[disk_index].ctx);
				goto DISK_RELOAD_ME_AGAIN;
			}
			if ( strncasecmp(buf,"max",3) == 0 ){
				last_lba = disk[disk_index].last_lba;
			} else {
				if ( buf[0] == '+' ){
					u_int64_t the_size;
					char *ptr;
					sscanf(&buf[1],"%ju",&the_size); 
					ptr = &buf[1];
					while ( *ptr && isdigit(*ptr) ) ptr++;
					if ( *ptr == 'G' ) the_size *= (u_int64_t)1000 * (u_int64_t)1000 * (u_int64_t)1000;
					if ( *ptr == 'M' ) the_size *= (u_int64_t)1000 * (u_int64_t)1000;
					if ( *ptr == 'K' ) the_size *= (u_int64_t)1000;
					the_size /= (u_int64_t)disk[disk_index].sector_size;
					if ( the_size % (u_int64_t)disk[disk_index].sector_size ) the_size++;
					last_lba = first_lba + the_size;
					if ( (last_lba) > disk[disk_index].last_lba ){
						sprintf(caption,"Invalid last sector!\nMust be lower than %jd (calculated: %jd)",disk[disk_index].last_lba,last_lba);
						alarm_window(caption,ALARM_ERROR,NULL,0);
						goto INPUT_LBA_LAST;
					}
				} else {
					sscanf(buf,"%ju",&last_lba);
				}
				if ( last_lba < first_lba || last_lba > disk[disk_index].last_lba ){
					sprintf(caption,"Invalid last sector!\nMust be between %jd and %jd",disk[disk_index].first_lba,disk[disk_index].last_lba);
					alarm_window(caption,ALARM_ERROR,NULL,0);
					goto INPUT_LBA_LAST;
				}	
			}
			sprintf(new_label,"Creating new partition on %s\nFirst-Sector: %ju\nLast-Sector: %ju\nType: [%s]",
					disk[disk_index].devname,
					first_lba, last_lba,
					fdisk_parttype_get_name(code[new_type]));
				
			if ( alarm_window(new_label,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ){
				size_t partno;
				// Create partition here :-)
				struct fdisk_partition *part;
				part = fdisk_new_partition();
				// fdisk_partition_set_bootable(part,false);
				fdisk_partition_partno_follow_default(part,1);
				fdisk_partition_set_start(part,first_lba);
				fdisk_partition_set_size(part,last_lba - first_lba);
				fdisk_partition_set_name(part,"GIX-Linux");
				fdisk_partition_size_explicit(part,1);
				fdisk_partition_set_type(part,code[new_type]);
				if ( fdisk_add_partition(disk[disk_index].ctx,part,&partno) ){
					alarm_window("Adding partition failed!",ALARM_ERROR,NULL,0);
					fdisk_deassign_device(disk[disk_index].ctx,0);
					fdisk_unref_context(disk[disk_index].ctx);
					goto DISK_RELOAD_ME_AGAIN;
				}
				if ( fdisk_write_disklabel(disk[disk_index].ctx) ){
					alarm_window("Writing partition table failed!",ALARM_ERROR,NULL,0);
					fdisk_deassign_device(disk[disk_index].ctx,0);
					fdisk_unref_context(disk[disk_index].ctx);
					goto DISK_RELOAD_ME_AGAIN;
				}
				sprintf(new_label,"Partition Nr. %d successfully created",partno);
				alarm_window(new_label,ALARM_INFO,NULL,0);
			}
			fdisk_deassign_device(disk[disk_index].ctx,0);
			fdisk_unref_context(disk[disk_index].ctx);
			goto DISK_RELOAD_ME_AGAIN;
			
		}

			


		fdisk_unref_table(disk[disk_index].tb);
		fdisk_deassign_device(disk[disk_index].ctx,0);
		fdisk_unref_context(disk[disk_index].ctx);


		





		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
		return;
}

struct _iface {
	char iface_name[64];
	unsigned char mac[128]; 
	int mac_len;
	unsigned char ipv4[4];
	int type; // According to if_arp.h
	int selected;
	int send_socket;
	int recv_socket;
	u_int32_t xid;
	int ifr_index;
	struct sockaddr_ll saddr_l;
};

struct _iface *iface = NULL;
int ifaces = 0;

char *display_mac2(unsigned char  *ift){
	static char retval[1024];
	int i;
	retval[0] = 0x00;
	for ( i = 0; i < 6; i++ ){
		if ( i == 0 ){
			sprintf(&retval[strlen(retval)],"%02X",ift[i]);
		} else {
			sprintf(&retval[strlen(retval)],":%02X",ift[i]);
		}
	}
	return(retval);
}

char *display_mac(struct _iface *ift){
	static char retval[1024];
	int i;
	retval[0] = 0x00;
	for ( i = 0; i < ift->mac_len; i++ ){
		if ( i == 0 ){
			sprintf(&retval[strlen(retval)],"%02X",ift->mac[i]);
		} else {
			sprintf(&retval[strlen(retval)],":%02X",ift->mac[i]);
		}
	}
	return(retval);
}

char *dump_if_flags(struct ifreq *ifr){
	static char response[128];
        response[0] = 0x00;
        if ( ifr->ifr_flags & IFF_UP ) strcat(response,"UP,");
        if ( ifr->ifr_flags & IFF_RUNNING ) strcat(response,"RUNNING,");
        if ( ifr->ifr_flags & IFF_BROADCAST ) strcat(response,"BROADCAST,");
        if ( ifr->ifr_flags & IFF_DEBUG ) strcat(response,"DEBUG,");
        if ( ifr->ifr_flags & IFF_LOOPBACK ) strcat(response,"LOOPBACK,");
        if ( ifr->ifr_flags & IFF_POINTOPOINT ) strcat(response,"POINTOPOINT,");
        if ( ifr->ifr_flags & IFF_NOTRAILERS ) strcat(response,"NOTRAILERS,");
        if ( ifr->ifr_flags & IFF_NOARP ) strcat(response,"NOARP,");
        if ( ifr->ifr_flags & IFF_PROMISC ) strcat(response,"PROMISC,");
        if ( ifr->ifr_flags & IFF_ALLMULTI ) strcat(response,"ALLMULTI,");
        if ( ifr->ifr_flags & IFF_MASTER ) strcat(response,"MASTER,");
        if ( ifr->ifr_flags & IFF_SLAVE ) strcat(response,"SLAVE,");
        if ( ifr->ifr_flags & IFF_MULTICAST ) strcat(response,"MULTICAST,");
        if ( ifr->ifr_flags & IFF_PORTSEL ) strcat(response,"PORTSEL,");
        if ( ifr->ifr_flags & IFF_AUTOMEDIA ) strcat(response,"AUTOMEDIA,");
        if ( ifr->ifr_flags & IFF_DYNAMIC ) strcat(response,"DYNAMIC,");

        if ( strlen(response) && response[strlen(response)-1] == ',' ) response[strlen(response)-1] = 0x00;
        return(response);
}

struct _dhcpoffer {
	int interface;
	unsigned char client_ip[4];
	unsigned char router[4];
	unsigned char dhcp[4];
	unsigned char nameserver[4];
	unsigned char subnet[4];
	unsigned char broadcast[4];
	
};

struct _dhcpoffer *dhcpoffer;
int dhcpoffers;


void process_iface_packet(unsigned char *packet, int packet_len, int iface_idx){
		struct ethhdr *eth;
		struct ip *ip;
		struct gix_udphdr *udp;
		struct bootp_packet *bp;
		int dhcp_offset;
		unsigned char yiaddr[4];
		unsigned char router[4];
		unsigned char nameserver[4];
		unsigned char broadcast[4];
		unsigned char dhcp[4];
		unsigned char subnet[4];
		int i;

		eth = (struct ethhdr *)&packet[0];
		ip = (struct ip *)&packet[sizeof(struct ethhdr)];
		udp = (struct gix_udphdr *)&packet[sizeof(struct ethhdr) + sizeof(struct ip)];
		bp = (struct bootp_packet *)&packet[sizeof(struct ethhdr) + sizeof(struct ip) + sizeof(struct gix_udphdr)];

		dhcp_offset = sizeof(struct ethhdr) + sizeof(struct ip) + sizeof(struct gix_udphdr) + sizeof(struct bootp_packet);

		if ( eth->h_proto != htons(ETH_P_IP) ) return;

		if ( ip->ip_p != IPPROTO_UDP ) return;

		if ( ntohs(udp->dest) != 68 ) return;

		if ( memcmp(&packet[dhcp_offset],dhcpmagic,4) != 0 ) return;

		dhcp_offset += 4;

	
		bzero(router,4);	
		bzero(nameserver,4);	
		bzero(broadcast,4);	
		bzero(dhcp,4);	
		bzero(subnet,4);	
		subnet[0] = 255;
		subnet[1] = 255;
		subnet[2] = 255;
		subnet[3] = 0;
		yiaddr[0] = (bp->yiaddr >> 0)  & 0xFF; 
		yiaddr[1] = (bp->yiaddr >> 8)  & 0xFF; 
		yiaddr[2] = (bp->yiaddr >> 16)  & 0xFF; 
		yiaddr[3] = (bp->yiaddr >> 24)  & 0xFF; 

		for ( i = 0; i < dhcpoffers; i++ ){
			if ( dhcpoffer[i].interface == iface_idx && memcmp(yiaddr,dhcpoffer[i].client_ip,4) == 0 ) break;
		}
		if ( i == dhcpoffers ){
			unsigned char option;
			unsigned char option_len;
			while ( dhcp_offset < packet_len ){
				option = packet[dhcp_offset++];
				if ( option == 0xff ) break; // End of options
				option_len = packet[dhcp_offset++];
				scroll_logger("OPTION: %d, LEN: %d\n",option,option_len);
				if ( option == 3 ){
					memcpy(router,&packet[dhcp_offset],4);
				}
				if ( option  == 1 ){
					memcpy(subnet,&packet[dhcp_offset],4);
				}
				if ( option  == 6 ){
					memcpy(nameserver,&packet[dhcp_offset],4);
				}
				if ( option  == 54 ){
					memcpy(dhcp,&packet[dhcp_offset],4);
				}
				if ( option  == 28 ){
					memcpy(broadcast,&packet[dhcp_offset],4);
				}
				if ( option == 53 )
					if ( packet[dhcp_offset] != 2 ) goto DHCP_NOT_VALID;
				dhcp_offset += option_len;
			}

			dhcpoffer = (struct _dhcpoffer *)realloc(dhcpoffer,sizeof(struct _dhcpoffer) * (dhcpoffers+1));
			bzero(&dhcpoffer[dhcpoffers],sizeof(struct _dhcpoffer));
			memcpy(dhcpoffer[dhcpoffers].client_ip,yiaddr,4);
			memcpy(dhcpoffer[dhcpoffers].router,router,4);
			memcpy(dhcpoffer[dhcpoffers].dhcp,dhcp,4);
			memcpy(dhcpoffer[dhcpoffers].nameserver,nameserver,4);
			memcpy(dhcpoffer[dhcpoffers].broadcast,broadcast,4);
			memcpy(dhcpoffer[dhcpoffers].subnet,subnet,4);
			dhcpoffer[dhcpoffers].interface = iface_idx;

			

			scroll_logger("Received UDP Packet on Interface %s FROM:  [%s] (%d Bytes) %d.%d.%d.%d --> %d.%d.%d.%d,\n               YIADDR: %d.%d.%d.%d, GW: %d.%d.%d.%d, BCAST: %d.%d.%d.%d, NS: %d.%d.%d.%d\n",iface[iface_idx].iface_name, display_mac2(eth->h_source),packet_len,
				( ip->ip_src.s_addr >> 0)  & 0xFF, 
				( ip->ip_src.s_addr >> 8)  & 0xFF, 
				( ip->ip_src.s_addr >> 16) & 0xFF, 
				( ip->ip_src.s_addr >> 24) & 0xFF,
				( ip->ip_dst.s_addr >> 0)  & 0xFF, 
				( ip->ip_dst.s_addr >> 8)  & 0xFF, 
				( ip->ip_dst.s_addr >> 16) & 0xFF, 
				( ip->ip_dst.s_addr >> 24) & 0xFF,
				( bp->yiaddr >> 0)  & 0xFF, 
				( bp->yiaddr >> 8)  & 0xFF, 
				( bp->yiaddr >> 16) & 0xFF, 
				( bp->yiaddr >> 24) & 0xFF,
				router[0],router[1],router[2], router[3],
				broadcast[0],broadcast[1],broadcast[2], broadcast[3],
				nameserver[0],nameserver[1],nameserver[2], nameserver[3]
				);
			dhcpoffers++;	
		}
DHCP_NOT_VALID:
		return;
}


struct _ipconfig {
	int iface;
	unsigned char ip[4];
	unsigned char netmask[4];
	unsigned char gw[4];
	unsigned char dhcp[4];
	unsigned char dns[4];
	unsigned char ftp_server[1024];
	unsigned char ftp_user[1024];
	unsigned char ftp_pwd[1024];
	char prefix[1024]; // A prefix used for...multi-purpose
	char ftp_ip[1024]; // The IP-Address of ftp_server, usefull, if more are used
};

struct _ipconfig ipconfig;


int setup_interface(struct _ipconfig *ipc){
	struct sockaddr_in sai;
	struct ifreq ifr;
	char buf[1024];
	int sock,i; 

	for ( i = 0; i < ifaces; i++ ){
		sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
		if ( sock < 0 ){
			sprintf(buf,"Setting up interface %s failed (Code: %d)",iface[i].iface_name,__LINE__);
			alarm_window(buf,ALARM_ERROR,NULL,0); 
			return(-1);
		}
		sai.sin_family = AF_INET;
		sai.sin_port   = 0;
		memset(&sai.sin_addr.s_addr,0,4);
		bzero(&ifr,sizeof(struct ifreq));
		strcpy(ifr.ifr_name,iface[i].iface_name);
		memcpy(&(ifr.ifr_addr),&sai,sizeof(struct sockaddr_in));
		if ( ioctl(sock,SIOCSIFADDR,&ifr) != 0 ){
			sprintf(buf,"Setting up interface %s failed (Code: %d)",iface[i].iface_name,__LINE__);
			alarm_window(buf,ALARM_ERROR,NULL,0); 
			close(sock);
			return(-1);
		}
		close(sock);
	}



	sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
	if ( sock < 0 ){
		sprintf(buf,"Setting up interface %s failed (Code: %d)",iface[ipc->iface].iface_name,__LINE__);
		alarm_window(buf,ALARM_ERROR,NULL,0); 
		return(-1);
	}
	sai.sin_family = AF_INET;
	sai.sin_port   = 0;
	memcpy(&sai.sin_addr.s_addr,ipc->ip,4);
	bzero(&ifr,sizeof(struct ifreq));
	strcpy(ifr.ifr_name,iface[ipc->iface].iface_name);
	memcpy(&(ifr.ifr_addr),&sai,sizeof(struct sockaddr_in));
	if ( ioctl(sock,SIOCSIFADDR,&ifr) != 0 ){
		sprintf(buf,"Setting up interface %s failed (Code: %d)",iface[ipc->iface].iface_name,__LINE__);
		alarm_window(buf,ALARM_ERROR,NULL,0); 
		close(sock);
		return(-1);
	}
	sai.sin_family = AF_INET;
	sai.sin_port   = 0;
	memcpy(&sai.sin_addr.s_addr,ipc->netmask,4);
	bzero(&ifr,sizeof(struct ifreq));
	strcpy(ifr.ifr_name,iface[ipc->iface].iface_name);
	memcpy(&(ifr.ifr_addr),&sai,sizeof(struct sockaddr_in));
	if ( ioctl(sock,SIOCSIFNETMASK,&ifr) != 0 ){
		sprintf(buf,"Setting up interface %s failed (Code: %d)",iface[ipc->iface].iface_name,__LINE__);
		alarm_window(buf,ALARM_ERROR,NULL,0); 
		close(sock);
		return(-1);
	}
	bzero(buf,16);
	if ( memcmp(ipc->gw,buf,4) != 0 ){
		char print_ip[1024];
		struct rtentry rt2;
		struct sockaddr_in *addr;
		bzero(&rt2,sizeof(struct rtentry));
		sprintf(print_ip,"%d.%d.%d.%d",
				ipc->gw[0], ipc->gw[1],
				ipc->gw[2], ipc->gw[3]);
		addr = (struct sockaddr_in *)&rt2.rt_gateway;
		addr->sin_family = AF_INET;
		addr->sin_port   = 0;
		addr->sin_addr.s_addr = inet_addr(print_ip);
		addr = (struct sockaddr_in *)&rt2.rt_genmask;
		addr->sin_family = AF_INET;
		addr->sin_port   = 0;
		addr->sin_addr.s_addr = (in_addr_t)0;
		addr = (struct sockaddr_in *)&rt2.rt_dst;
		addr->sin_family = AF_INET;
		addr->sin_port   = 0;
		addr->sin_addr.s_addr = (in_addr_t)0;
		rt2.rt_flags = RTF_GATEWAY;
		rt2.rt_metric = 0;
		rt2.rt_dev = iface[ipc->iface].iface_name; 
		if ( ioctl(sock,SIOCADDRT,&rt2) != 0 ){
			sprintf(print_ip,"Failed to set default route (%s)",strerror(errno));
			alarm_window(print_ip,ALARM_ERROR,NULL,0);
		}
	}
	if ( memcmp(ipc->dns,buf,4) != 0 ){
		FILE *fp;
		unlink("/etc/resolv.conf");
		fp = fopen("/etc/resolv.conf","w");
		if ( fp ){
			fprintf(fp,"nameserver %d.%d.%d.%d\n",ipc->dns[0],ipc->dns[1],ipc->dns[2],ipc->dns[3]);
			fclose(fp);
		}
	}
	close(sock);
	return(0);
}


void detect_interfaces(){
	int iface_index;
	int idx;
	DIR *dir;
	struct dirent *diry;
	int i;
	int j;
	struct _select *sel;


	if ( iface ){
		for ( i = 0; i < ifaces; i++ ){
			if ( iface[i].recv_socket ) close(iface[i].recv_socket);
			if ( iface[i].send_socket ) close(iface[i].send_socket);
		}
		free(iface);
		iface = NULL;
	}
	ifaces = 0;

	create_scroller("Detecting network");

	srandom(time(NULL));

	dir = opendir("/sys/class/net");
	if ( dir == NULL ){
		alarm_window("No network environement found!",ALARM_ERROR,NULL,0);
		return;
	}
	while ( (diry = readdir(dir)) != NULL ){
		char buf[1024];
		int sock;
		struct ifreq ifr;
		char fname[1024];
		unsigned char mac[124];
		int if_index;
		int mac_len;
		int type;
		int send_socket;
		FILE *fp; 

		if ( strcmp(diry->d_name,".") == 0 ) continue;
		if ( strcmp(diry->d_name,"..") == 0 ) continue;
		sprintf(fname,"/sys/class/net/%s/type",diry->d_name);
		fp = fopen(fname,"r");
		if ( fp == NULL ) continue;
		if ( fgets(buf,1024,fp) == NULL ){
			fclose(fp);
			continue;
		}
		fclose(fp);
		type = atoi(buf);
		if ( type != ARPHRD_ETHER ) continue;
		sprintf(fname,"/sys/class/net/%s/address",diry->d_name);
		fp = fopen(fname,"r");
		if ( fp == NULL ) continue;
		if ( fgets(buf,1024,fp) == NULL ){
			fclose(fp);
			continue;
		}
		fclose(fp);

		switch(type){
			case ARPHRD_ETHER:
				mac_len = 6;
				break;
			default:
				mac_len = 0;
				break;
		}
		if ( mac_len == 6 ){
			sscanf(buf,"%02X:%02X:%02X:%02X:%02X:%02X",
				&mac[0], &mac[1], &mac[2],
				&mac[3], &mac[4], &mac[5]);
		}

		sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
		if ( sock < 0 ) continue;
		bzero(&ifr,sizeof(struct ifreq));
		strcpy(ifr.ifr_name,diry->d_name);
		if ( ioctl(sock,SIOCGIFINDEX,&ifr) != 0 ){
			close(sock);
			continue;
		}
		if_index = ifr.ifr_ifindex;	
		if ( ioctl(sock,SIOCGIFFLAGS,&ifr) != 0 ){
			close(sock);
			continue;
		}
		

		if ( ( ifr.ifr_flags & IFF_UP ) &&  ( ifr.ifr_flags & IFF_RUNNING ) ){
			// Well...nothing to do...
		} else {
			ifr.ifr_flags |= IFF_UP || IFF_RUNNING;
			if ( ioctl(sock,SIOCSIFFLAGS,&ifr) != 0 ){
				sprintf(buf,"INTERFACE: [%s] [%s--> FLAGS: [%s]\n\nCannot set flags!\n",diry->d_name,dump_if_flags(&ifr));
				alarm_window(buf,ALARM_ERROR,NULL,0);
				close(sock);
				continue;
			}
			scroll_logger("Turning on interface %s",diry->d_name);
			sleep(1);
			c_logger(".");
			sleep(1);
			c_logger(".");
			sleep(1);
			c_logger(".");
			sleep(1);
			c_logger(".\n");

		}
		close(sock); 
		send_socket = socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW);
		if ( send_socket < 0 ){
			sprintf(buf,"INTERFACE: [%s]\n\nCannot open send-socket!\n",diry->d_name);
			alarm_window(buf,ALARM_ERROR,NULL,0);
			close(sock);
			continue;
		}
		sock = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
		if ( sock < 0 ){
			sprintf(buf,"INTERFACE: [%s]\n\nCannot open recv-socket!\n",diry->d_name);
			alarm_window(buf,ALARM_ERROR,NULL,0);
			close(send_socket);
			continue;
		}
		if ( setsockopt(sock,SOL_SOCKET,SO_BINDTODEVICE,diry->d_name,strlen(diry->d_name)) < 0 ){
			sprintf(buf,"INTERFACE: [%s]\n\nCannot bind recv-socket!\n",diry->d_name);
			scroll_logger(buf);
			alarm_window(buf,ALARM_ERROR,NULL,0);
			close(send_socket);
			close(sock);
			continue;
		}
		iface = (struct _iface *)realloc(iface,sizeof(struct _iface) * (ifaces+1));
		bzero(&iface[ifaces],sizeof(struct _iface));
		strcpy(iface[ifaces].iface_name,diry->d_name);
		iface[ifaces].mac_len = mac_len;
		if ( mac_len ){
			memcpy(iface[ifaces].mac,mac,mac_len);
		}
		iface[ifaces].type = type;
		iface[ifaces].send_socket = send_socket;
		iface[ifaces].recv_socket = sock;
		iface[ifaces].xid = random(); 
		iface[ifaces].ifr_index = if_index;
		iface[ifaces].saddr_l.sll_ifindex = if_index;
		iface[ifaces].saddr_l.sll_halen = ETH_ALEN;

		sprintf(buf,"INTERFACE: (%d) [%s] [%s] --> FLAGS: [%s]\n",if_index,iface[ifaces].iface_name,display_mac(&iface[ifaces]),dump_if_flags(&ifr));
		// alarm_window(buf,ALARM_INFO,NULL,0);
		scroll_logger(buf);
		ifaces++;
	}
	closedir(dir);
	scroll_logger("Detecting DHCP..\n");
	for ( idx = 0; idx < ifaces; idx++ ){
		char buf[512];
		int result;
		struct ethhdr *eth;
		struct ip *ip;
		struct gix_udphdr *udp;
		struct bootp_packet *bp;
		unsigned char packet[8192];
		int dhcp_offset;

		eth = (struct ethhdr *)&packet[0];
		ip = (struct ip *)&packet[sizeof(struct ethhdr)];
		udp = (struct gix_udphdr *)&packet[sizeof(struct ethhdr) + sizeof(struct ip)];
		bp = (struct bootp_packet *)&packet[sizeof(struct ethhdr) + sizeof(struct ip) + sizeof(struct gix_udphdr)];
		bzero(packet,8192);

		eth->h_proto = htons(ETH_P_IP);
		memcpy(eth->h_source,iface[idx].mac,6);
		memset(eth->h_dest,0xFF,6);

		ip->ip_v   = 4;
                ip->ip_hl  = 5; // Minimum length
                ip->ip_tos = 0x10;
                ip->ip_len = 0; // Must be filled later
                ip->ip_id  = 0;
                ip->ip_off = 0;
                ip->ip_p   = IPPROTO_UDP;
                ip->ip_ttl = 128; // Enough...we travel only in LAN...but leave enough for DNS-Request
                ip->ip_sum = 0; // Must be filled at the very end
		memcpy(&ip->ip_dst.s_addr,ipbcast,4);
		udp->source = htons(68);
		udp->dest   = htons(67);
		udp->len    = (u_int16_t) 0; // Must be filled later
                udp->check  = (u_int16_t) 0; // If Zero's than it is not used...that's OK :-)


		bp->op    = 1; // DHCP-Discover
		bp->htype = 1; 
		bp->hlen  = 6;
		bp->hops  = 0;
		bp->flags = 0;
		bp->xid   = iface[idx].xid; 
		memcpy(bp->chaddr,eth->h_source,6);

		dhcp_offset = sizeof(struct ethhdr) + sizeof(struct ip) + sizeof(struct gix_udphdr) + sizeof(struct bootp_packet);

		memcpy(&packet[dhcp_offset],dhcpmagic,4); dhcp_offset += 4;

		packet[dhcp_offset++] = 0x35; // First option
		packet[dhcp_offset++] = 0x01; // Length
		packet[dhcp_offset++] = 0x01; // Message Type...01-Discover, 02-Offer, ...
		packet[dhcp_offset++] = 0x37; // List of wanted options
		packet[dhcp_offset++] = 0x09; // Count of wanted options
		packet[dhcp_offset++] = 1; 
		packet[dhcp_offset++] = 3; 
		packet[dhcp_offset++] = 5; 
		packet[dhcp_offset++] = 6; 
		packet[dhcp_offset++] = 13; 
		packet[dhcp_offset++] = 28; 
		packet[dhcp_offset++] = 54; 
		packet[dhcp_offset++] = 66; 
		packet[dhcp_offset++] = 67; 
		packet[dhcp_offset++] = 255;  // End of options

		ip->ip_len = (unsigned short) htons(dhcp_offset - sizeof(struct ethhdr) );
		udp->len = (unsigned short) htons( dhcp_offset - (sizeof(struct ethhdr) + sizeof(struct ip)) );				
		udp->check = udp_checksum(&packet[sizeof(struct ethhdr)+ sizeof(struct ip)], (int) ntohs(udp->len),(struct ip *)&packet[sizeof(struct ethhdr)]);
		ip->ip_sum = ip_checksum(&packet[sizeof(struct ethhdr)],  sizeof(struct ip));
		memcpy(iface[idx].saddr_l.sll_addr,eth->h_dest,6);
	
		result = sendto(iface[idx].send_socket,packet,dhcp_offset,0,(struct sockaddr *)&iface[idx].saddr_l,sizeof(struct sockaddr_ll));
		
		sprintf(buf,"Sending packet (%d Bytes) FROM [%s] --> %d\n", dhcp_offset, iface[idx].iface_name,result);
		scroll_logger(buf);	
	}

	if ( ifaces ) {
		int i;
		time_t start;
		struct pollfd *polly;
		polly = (struct pollfd *)malloc(sizeof(struct pollfd) * ifaces);
		
		start = time(NULL);
		while ( (start + DHCP_TIMEOUT) > time(NULL)){
			for ( i = 0; i < ifaces; i++ ){
				polly[i].fd     = iface[i].recv_socket;
				polly[i].events = POLLIN;
			}
			if ( poll(polly,ifaces,1000) > 0 ){
				for ( i = 0; i < ifaces; i++ ){
					if ( polly[i].revents & POLLIN ){
						unsigned char packin[8192];
						int size;   
						size = recv(polly[i].fd,packin,8192,0);
						process_iface_packet(packin,size,i);
						
					}
				}
			}
		}
	}

	end_scroller();
	attron(COLOR_PAIR(BASE2_COLOR_NORMAL));
	create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4, "Select network interface");
	sel = (struct _select *)malloc(sizeof(struct _select) * (ifaces + dhcpoffers));
	bzero(sel,sizeof(struct _select) * disks);
	for ( i = 0; i < ifaces; i++ ){
		char helper[1024];
		sprintf(helper,"%s [%s] manual configuration",iface[i].iface_name,display_mac(&iface[i]));
		sel[i].name = strdup(helper);
	}
	for ( j = 0; j <  dhcpoffers; j++ ){
		char helper[1024];
		sprintf(helper,"%s [%s] IP: %d.%d.%d.%d, DHCP: %d.%d.%d.%d GW: %d.%d.%d.%d, NS: %d.%d.%d.%d, MASK: %d.%d.%d.%d",
				iface[dhcpoffer[j].interface].iface_name,
				display_mac(&iface[dhcpoffer[j].interface]),
				dhcpoffer[j].client_ip[0], dhcpoffer[j].client_ip[1], dhcpoffer[j].client_ip[2], dhcpoffer[j].client_ip[3],
				dhcpoffer[j].dhcp[0], dhcpoffer[j].dhcp[1], dhcpoffer[j].dhcp[2], dhcpoffer[j].dhcp[3],
				dhcpoffer[j].router[0], dhcpoffer[j].router[1], dhcpoffer[j].router[2], dhcpoffer[j].router[3],
				dhcpoffer[j].nameserver[0], dhcpoffer[j].nameserver[1], dhcpoffer[j].nameserver[2], dhcpoffer[j].nameserver[3],
				dhcpoffer[j].subnet[0], dhcpoffer[j].subnet[1], dhcpoffer[j].subnet[2], dhcpoffer[j].subnet[3]);
		sel[j+i].name = strdup(helper);
	}
	current_select = 0;
	iface_index = run_selector(NULL,sub2,0,sel,ifaces+dhcpoffers,NULL);
	for ( i = 0; i < ifaces + dhcpoffers ; i++ ){
		free(sel[i].name);
	}
	free(sel);
	if ( iface_index < 0 ){
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
		return;
	}
	if ( iface_index >= ifaces ){
		bzero(&ipconfig,sizeof(struct _ipconfig));
		strcpy(ipconfig.ftp_server,FTP_SERVER);
		strcpy(ipconfig.ftp_user,FTP_USER);
		strcpy(ipconfig.ftp_pwd,FTP_PWD);
		ipconfig.iface = dhcpoffer[iface_index - ifaces].interface;
		memcpy(ipconfig.ip,dhcpoffer[iface_index - ifaces].client_ip,4);
		memcpy(ipconfig.gw,dhcpoffer[iface_index - ifaces].router,4);
		memcpy(ipconfig.dhcp,dhcpoffer[iface_index - ifaces].dhcp,4);
		memcpy(ipconfig.dns,dhcpoffer[iface_index - ifaces].nameserver,4);
		memcpy(ipconfig.netmask,dhcpoffer[iface_index - ifaces].subnet,4);
		setup_interface(&ipconfig);
	} else {
		in_addr_t ip;
		unsigned char temp_ip[1024];
		in_addr_t netmask;
		unsigned char temp_netmask[1024];
		in_addr_t dns;
		unsigned char temp_dns[1024];
		in_addr_t gw;
		unsigned char temp_gw[1024];
SETUP_ENTER_IP:
		sprintf(temp_ip,"192.168.0.87");
		if ( alarm_window("Enter IPv4 Address: ",ALARM_INPUT,temp_ip,16) < 0 ){
			return;
		}
		if ( inet_addr(temp_ip) == INADDR_NONE ){
			alarm_window("Invalid IP-Address!",ALARM_ERROR,NULL,0);
			goto SETUP_ENTER_IP;
		} else {
			ip = inet_addr(temp_ip);
			temp_ip[0] = (ip >> 0)  & 0xFF;
			temp_ip[1] = (ip >> 8)  & 0xFF;
			temp_ip[2] = (ip >> 16)  & 0xFF;
			temp_ip[3] = (ip >> 24)  & 0xFF;
		}
SETUP_ENTER_NETMASK:
		sprintf(temp_netmask,"255.255.255.128");
		if ( alarm_window("Enter IPv4 Netmask: ",ALARM_INPUT,temp_netmask,16) < 0 ){
			return;
		}
		if ( inet_addr(temp_netmask) == INADDR_NONE ){
			alarm_window("Invalid IP-NETMASK!",ALARM_ERROR,NULL,0);
			goto SETUP_ENTER_NETMASK;
		} else {
			netmask = inet_addr(temp_netmask);
			temp_netmask[0] = (netmask >> 0)  & 0xFF;
			temp_netmask[1] = (netmask >> 8)  & 0xFF;
			temp_netmask[2] = (netmask >> 16)  & 0xFF;
			temp_netmask[3] = (netmask >> 24)  & 0xFF;
		}
SETUP_ENTER_GW:
		sprintf(temp_gw,"192.168.0.1");
		if ( alarm_window("Enter IPv4 Gateway: ",ALARM_INPUT,temp_gw,16) < 0 ){
			return;
		}
		if ( inet_addr(temp_gw) == INADDR_NONE ){
			alarm_window("Invalid IP-Gateway!",ALARM_ERROR,NULL,0);
			goto SETUP_ENTER_GW;
		} else {
			gw = inet_addr(temp_gw);
			temp_gw[0] = (gw >> 0)  & 0xFF;
			temp_gw[1] = (gw >> 8)  & 0xFF;
			temp_gw[2] = (gw >> 16)  & 0xFF;
			temp_gw[3] = (gw >> 24)  & 0xFF;
		}
SETUP_ENTER_DNS:
		sprintf(temp_dns,"192.168.0.1");
		if ( alarm_window("Enter IPv4 DNS-Server: ",ALARM_INPUT,temp_dns,16) < 0 ){
			return;
		}
		if ( inet_addr(temp_dns) == INADDR_NONE ){
			alarm_window("Invalid IP-DNS-Server!",ALARM_ERROR,NULL,0);
			goto SETUP_ENTER_DNS;
		} else {
			dns = inet_addr(temp_dns);
			temp_dns[0] = (dns >> 0)  & 0xFF;
			temp_dns[1] = (dns >> 8)  & 0xFF;
			temp_dns[2] = (dns >> 16)  & 0xFF;
			temp_dns[3] = (dns >> 24)  & 0xFF;
		}

		bzero(&ipconfig,sizeof(struct _ipconfig));
		strcpy(ipconfig.ftp_server,FTP_SERVER);
		strcpy(ipconfig.ftp_user,FTP_USER);
		strcpy(ipconfig.ftp_pwd,FTP_PWD);
		ipconfig.iface = iface_index;
		memcpy(ipconfig.ip,temp_ip,4);
		memcpy(ipconfig.gw,temp_gw,4);
		memcpy(ipconfig.dns,temp_dns,4);
		memcpy(ipconfig.netmask,temp_netmask,4);
		if ( alarm_window("Restart this interface (OK) or simply leave it running (CANCEL)",ALARM_OKCANCEL,NULL,ANSWER_CANCEL) == ANSWER_OK ){
			setup_interface(&ipconfig);
		}
	}
	alarm_window("Interface SETUP completed successfully!",ALARM_INFO,NULL,0);
}

void do_network(){
	detect_interfaces();	
}




void exit_setup(){
	char **args;
	args = (char **)malloc(2 * sizeof(char *));
	args[0] = strdup("[SHELL]");
	args[1] = NULL;
	endwin();
	if ( execv("/bin/sh",args) < 0 ){
		fprintf(stderr,"EXECV failed (%s)\n",strerror(errno));
		exit(0);
	}
	exit(0);
}

void reboot_system(){
	char **arg;
	int args;

	if ( alarm_window("Are you sure, you want to reboot?",ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ){
		int fd;
		fd = open(SYS_TRIGGER_CTL,O_WRONLY);
		if ( fd ){
			char buf[2];
			buf[0] = '1';
			buf[1] = '\n';
			write(fd,buf,2);
			close(fd);
		}
		fd = open(SYS_TRIGGER,O_WRONLY);
		if ( fd ){
			char buf[2];
			buf[0] = 'b';
			buf[1] = '\n';
			write(fd,buf,2);
			close(fd);
		}
	}
	attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
	erase();
	display_options();
	refresh();
}



void run_main_action(){
	 option[current_option].handler();
}


void display_options(){
	int i;
	int longest_option = 0;

	draw_frame();
	for ( options = 0; option[options].caption != 0; options++ ){
		if ( strlen(option[options].caption) > longest_option ) longest_option = strlen(option[options].caption);
	}
	for ( i = 0; i < options; i++ ){
		move(i * 2 + OPTION_Y_OFFSET, OPTION_X_OFFSET);
		if ( current_option == i ){
			attron(A_REVERSE);
			printw("%s",option[i].caption);
			attroff(A_REVERSE);

		} else {
			attroff(A_REVERSE);
			printw("%s",option[i].caption);
		}
		refresh();
	}

}


void draw_frame(){
	int x;
	int y;

	getmaxyx(stdscr,rows,cols);
	screen->width = cols;
	screen->height = rows;
	if ( o_rows != rows || o_cols != cols ){
		clear();
		o_rows = rows;
		o_cols = cols;
	}
	box(root,0,0);
	// border( '|', '|', '-', '-', '+', '+', '+', '+');	
	y = 0;
	x = cols / 2 - strlen(caption)/2;
	move(0,x);
	attron(A_BOLD);
	printw("%s",caption);
	attroff(A_BOLD);
}

void raid_setup(){
		create_sub1();
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		update_raidlist();
		create_raid();
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
}

void stop_raids(){
		int i;	
		for ( i = 0; i < 256; i++ ){
			struct stat st;
			char fname[1024];
			char caption[1024];
			char result[1024];
			sprintf(fname,"/dev/md%d",i);
			if ( stat(fname,&st) == 0 ){
				char **arg;
				int args;
				int jj;
				arg  = NULL;
				args = 0;
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = strdup(RAID_CMD);
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = strdup("--stop");
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = strdup(fname);
				arg = (char **)realloc(arg,sizeof(char *) * (args+1));
				arg[args++] = NULL;
				sprintf(caption,"Stopping %s",fname);
				sprintf(result,"Stopped %s",fname);
				run_program(arg[0],arg,caption,result);
				for ( jj = 0; jj < (args-1); jj++ ) free(arg[jj]);
				free(arg);
			}
		}
}

void raid_stop(){
		int i;	
		create_sub1();


		create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4, "Stopping RAIDs");
		stop_raids();
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
}

void zero_all_disks(){
		int i;	
		DIR *dir;
		struct dirent *diry;
		create_sub1();
		char zero_block[BSIZE];

		bzero(zero_block,BSIZE);


		create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 4, sub1->height - 4, "Zeroing all disks");
		stop_raids();
		dir = opendir("/dev");
		if ( dir ){
			while ( (diry = readdir(dir)) != NULL ){
				char fname[1024];
				int fd;
				struct stat st;
				if ( strncmp(diry->d_name,"sd",2) != 0 ) continue;
				if ( strlen(diry->d_name) < 4 ) continue;
				sprintf(fname,"/dev/%s",diry->d_name);
				if ( stat(fname,&st) == 0 ){
					char **arg;
					int args;
					int jj;
					int result_tot;
					char result[256];
					arg  = NULL;
					args = 0;
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(RAID_CMD);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup("--zero-superblock");
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(fname);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = NULL;
					sprintf(caption,"Zeroing superblock for %s",fname);
					sprintf(result,"Zeroed superblock for %s",fname);
					run_program(arg[0],arg,caption,result);
					create_scroller("Wiping device-header");
					for ( jj = 0; jj < (args-1); jj++ ) free(arg[jj]);
					free(arg);
					fd = open(fname,O_WRONLY);
					if ( fd ){
						scroll_logger("Wiping %s...\n",fname);
						result_tot = 0;
						for ( i = 0; i < 5000; i++ ){
							int result;
							result = write(fd,zero_block,BSIZE);
							result_tot += result;
							if (( i % 100 ) == 0 ) scroll_logger("Wiping Block: %d --> (Written %d Bytes)\n",i,result_tot);
						}
						close(fd);
					}
					sleep(1);
					end_scroller();
				}

			}
			closedir(dir);
		}
		dir = opendir("/dev");
		if ( dir ){
			while ( (diry = readdir(dir)) != NULL ){
				int jj;
				char fname[1024];
				int fd;
				int result_tot;
				struct stat st;
				if ( strncmp(diry->d_name,"sd",2) != 0 ) continue;
				if ( strlen(diry->d_name) > 3 ) continue;
				sprintf(fname,"/dev/%s",diry->d_name);
				if ( stat(fname,&st) == 0 ){
					char **arg;
					int args;
					int jj;
					int result_tot;
					char result[256];
					arg  = NULL;
					args = 0;
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(RAID_CMD);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup("--zero-superblock");
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(fname);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = NULL;
					sprintf(caption,"Zeroing superblock for %s",fname);
					sprintf(result,"Zeroed superblock for %s",fname);
					run_program(arg[0],arg,caption,result);
					create_scroller("Wiping device-header");
					fd = open(fname,O_WRONLY);
					if ( fd ){
						scroll_logger("Wiping %s...\n",fname);
						result_tot = 0;
						for ( i = 0; i < 5000; i++ ){
							int result;
							result = write(fd,zero_block,BSIZE);
							result_tot += result;
							if (( i % 100 ) == 0 ) scroll_logger("Wiping Block: %d --> (Written %d Bytes)\n",i,result_tot);
						}
						close(fd);
					}
					sleep(1);
					end_scroller();
				}

			}
			closedir(dir);
		}
		alarm_window("All Devices zeroed and partition tables destroyed, please reboot now!",ALARM_INFO,NULL,0);
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
		
}



struct _interface *iff = NULL;
int iffs = 0;

char *root_prefix = NULL;

int interface_sort(const void *_a, const void *_b){
	struct _interface *a;
	struct _interface *b;

	a = (struct _interface *)_a;
	b = (struct _interface *)_b;
	return(strcmp(a->name,b->name));
}


void setup_interfaces(){
		char sysconfig[1024];
		DIR *dir;
		struct dirent *diry;
		int i;
		char dummy[128];


		sprintf(sysconfig,"%s/etc/sysconfig",root_prefix ? root_prefix : "" );

		if ( iff ) free(iff);
		iff = NULL;
		iffs = 0;

		dir = opendir("/sys/class/net");
		if ( dir ){
			while ( (diry = readdir(dir)) != NULL ){
				struct _interface *tif;
				char buf[1024];
				struct stat st;
				FILE *fp;
				char fname[1024];
				char target[1024];


				if ( strcmp(diry->d_name,".") == 0 ) continue;
				if ( strcmp(diry->d_name,"..") == 0 ) continue;
				sprintf(fname,"/sys/class/net/%s",diry->d_name);
				if ( stat(fname,&st) != 0 ) continue;
				if ( readlink(fname,target,1024) == -1 ) continue;
				if ( strstr(target,"/virtual/") ) continue;
				// printf("Interface: [%s] --> [%s]\n", fname,target);			
				if ( (tif = getinterface(sysconfig, diry->d_name)) == NULL ) continue;
				iff = (struct _interface *)realloc(iff,(iffs+1) * sizeof(struct _interface));
				memcpy(&iff[iffs],tif,sizeof(struct _interface));
				iffs++;	

			}
			closedir(dir);
		}
		qsort(iff,iffs,sizeof(struct _interface),interface_sort);
		/*
		for ( i = 0; i < iffs; i++ ){
			printf("INTERFACE: %d\n",i);
			printf("IF-NAME:     [%s]\n",iff[i].name);
			printf("IP4-VALUE:   [%s]\n",display_ipv4(iff[i].ip4,4,dummy));
			printf("GW4-VALUE:   [%s]\n",display_ipv4(iff[i].gw_ip4,4,dummy));
			printf("BR4-VALUE:   [%s]\n",display_ipv4(iff[i].broadcast_ip4,4,dummy));
			printf("PREFIX4-LEN: [%d]\n",iff[i].prefixlen_ip4);
			printf("IP6-VALUE:   [%s]\n",display_ipv6(iff[i].ip6,16,dummy));
			printf("PREFIX6-LEN: [%d]\n",iff[i].prefixlen_ip6);
			printf("SERVICE:     [%s]\n",iff[i].service);
			printf("ONBOOT:      [%d]\n",iff[i].active);
		}
		printf("Found %d interfaces\n",iffs);
		*/
}


void network_setup(){
		dhcpoffers = 0;
		if ( dhcpoffer ) free(dhcpoffer);
		dhcpoffer = NULL;
		create_sub1();

		do_network();

		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		erase();
		display_options();
		refresh();
}
void efi_setup(){
		create_sub1();
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		do_efi();
		erase();
		display_options();
		refresh();
}
void linux_setup(){
		in_addr_t xx;
		unsigned char gateway_ipv4[4];
		unsigned char gateway_ipv6[16];
		int i;
		FILE *fp;
		char fname[1024];
		char help[1024];
		char buf[1024];
		char sysconfig[1024];
		struct stat st;
		create_sub1();
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		if ( stat("/mnt/etc/rc.d",&st) == 0 ){
			root_prefix="/mnt/";
		} else {
			root_prefix="/";
		}
		sprintf(sysconfig,"%s/etc/sysconfig",root_prefix ? root_prefix : "" );
		sprintf(help,"SETUP System (ROOT-PREFIX: [%s]",root_prefix);
		create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 6, sub1->height - 4, help);
		sprintf(fname,"%s/etc/hostname",root_prefix);
		strcpy(buf,"gixlinux2");
		fp = fopen(fname,"r");
		if ( fp ){
			fgets(buf,1024,fp);
			fclose(fp);
		} 
		while ( strlen(buf) && ( buf[strlen(buf)-1] == ' ' || buf[strlen(buf)-1] == '\n' || buf[strlen(buf)-1] == '\r' )) buf[strlen(buf)-1] = 0x00;
ENTER_HOSTNAME: 
		if ( alarm_window("Set Hostname: ",ALARM_INPUT,buf,32) < 0 ) goto END_LINUX;
		while ( strlen(buf) && ( buf[strlen(buf)-1] == ' ' || buf[strlen(buf)-1] == '\n' || buf[strlen(buf)-1] == '\r' )) buf[strlen(buf)-1] = 0x00;
		if ( strlen(buf) > 3 ){
			unlink(fname);
			fp = fopen(fname,"w");
			if ( fp ){
				fprintf(fp,"%s\n",buf);
				fclose(fp);
			} 
		} else {
			alarm_window("Hostname must be at least 3 characters!",ALARM_ERROR,NULL,0);
			goto ENTER_HOSTNAME;
		}

		setup_interfaces();
		memset(gateway_ipv4,0,4);
		memset(gateway_ipv6,0,16);
		for ( i = 0; i < iffs; i++ ){
			int ret;
			unsigned char dummyip[64];
			if ( !is_zero(iff[i].gw_ip4,4) ){ 
				memcpy(gateway_ipv4,iff[i].gw_ip4,4);
				debug_logger("[%s] GW_IP: [%s] IS_ZERO->FALSE!\n",iff[i].name,display_ipv4(iff[i].gw_ip4,4,dummyip));
			} else {
				debug_logger("[%s] GW_IP: [%s] IS_ZERO->TRUE!\n",iff[i].name,display_ipv4(iff[i].gw_ip4,4,dummyip));
			}
			if ( !is_zero(iff[i].gw_ip6,16) ) memcpy(gateway_ipv6,iff[i].gw_ip6,16);
			sprintf(help,"Setting up interface [%s]",iff[i].name);
			create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 6, sub1->height - 4, help);
			sprintf(help,"Use interface [%s]?",iff[i].name);
			ret = alarm_window(help,ALARM_OKCANCEL,"<YES>|<NO>",iff[i].active ? ANSWER_OK : ANSWER_CANCEL);
			if ( ret == ANSWER_CANCEL ){
				iff[i].active = 0;
			} else if ( ret  == ANSWER_OK ){
IP_AGAIN:
				iff[i].active = 1;
				sprintf(help,"IPv4 for [%s]: ",iff[i].name);
				display_ipv4(iff[i].ip4,4,buf);
				if ( is_zero(iff[i].ip4,4) )strcpy(buf,"");
				if ( alarm_window(help,ALARM_INPUT,buf,32) < 0 ) goto END_LINUX;
				while ( strlen(buf) &&  isspace(buf[strlen(buf)-1]) ) buf[strlen(buf)-1] = 0x00;
				if ( strlen(buf) < 1 ){
					bzero(iff[i].ip4,4);
					goto IP_AGAIN3;
				}
				if ( inet_addr(buf)  == INADDR_NONE ){
					alarm_window("Please enter a valid IPv4 address!",ALARM_ERROR,NULL,0);
					goto IP_AGAIN;
				}
				xx = inet_addr(buf);
				iff[i].ip4[3] = ((xx) >> 24) & 0xFF;
                                iff[i].ip4[2] = ((xx) >> 16) & 0xFF;
                                iff[i].ip4[1] = ((xx) >> 8) & 0xFF;
                                iff[i].ip4[0] = ((xx) >> 0) & 0xFF;
IP_AGAIN2:
				sprintf(help,"IPv4 Prefixlen for [%s] (0...32): ",iff[i].name);
				sprintf(buf,"%d",iff[i].prefixlen_ip4);
				if ( alarm_window(help,ALARM_INPUT,buf,2) < 0 ) goto END_LINUX;
				while ( strlen(buf) &&  isspace(buf[strlen(buf)-1]) ) buf[strlen(buf)-1] = 0x00;
				if ( sscanf(buf,"%d",&ret) != 1 ||  ret > 32 || ret < 0 ){
					alarm_window("Please enter a valid IPv4 prefix (0...32)!",ALARM_ERROR,NULL,0);
					goto IP_AGAIN2;
				}
				debug_logger("INTERFACE [%s] PREFIX-LEN: %d\n",iff[i].name,ret);
				iff[i].prefixlen_ip4 = ret;

IP_AGAIN3:
				sprintf(help,"IPv6 for [%s](blank for no addr.): ",iff[i].name);
				display_ipv6(iff[i].ip6,16,buf);
				if ( is_zero(iff[i].ip6,16)) strcpy(buf,"");
				if ( alarm_window(help,ALARM_INPUT,buf,50) < 0 ) goto END_LINUX;
				while ( strlen(buf) &&  isspace(buf[strlen(buf)-1]) ) buf[strlen(buf)-1] = 0x00;
				if ( strlen(buf) == 0 ){
					memset(iff[i].ip6,0,16);
				} else {
					char dummy[129];
					if ( inet_pton(AF_INET6,buf,dummyip) != 1 ){
						alarm_window("Please enter a valid IPv6 address!",ALARM_ERROR,NULL,0);
						goto IP_AGAIN3;
					}	
					memcpy(iff[i].ip6,dummyip,16);
					debug_logger("INTERFACE [%s] IPV6: [%s]\n",iff[i].name,display_ipv6(iff[i].ip6,16,dummy));
IP_AGAIN4:
					sprintf(help,"IPv6 Prefixlen for [%s] (0...128): ",iff[i].name);
					sprintf(buf,"%d",iff[i].prefixlen_ip6);
					if ( alarm_window(help,ALARM_INPUT,buf,3) < 0 ) goto END_LINUX;
					while ( strlen(buf) &&  isspace(buf[strlen(buf)-1]) ) buf[strlen(buf)-1] = 0x00;
					if ( sscanf(buf,"%d",&ret) != 1 ||  ret > 128 || ret < 0 ){
						alarm_window("Please enter a valid IPv6 prefixlen (0...128)!",ALARM_ERROR,NULL,0);
						goto IP_AGAIN4;
					}
					debug_logger("INTERFACE [%s] PREFIX6-LEN: %d\n",iff[i].name,ret);
					iff[i].prefixlen_ip6 = ret;
				}

			} else {
				goto END_LINUX;
			}
		}
IP_AGAIN5:
		display_ipv4(gateway_ipv4,4,buf);
		if ( is_zero(gateway_ipv4,4)) strcpy(buf,"");
		if ( alarm_window("IPv4 Gateway (blank for no gateway): ",ALARM_INPUT,buf,32) < 0 ) goto END_LINUX;
		while ( strlen(buf) &&  isspace(buf[strlen(buf)-1]) ) buf[strlen(buf)-1] = 0x00;
		if ( strlen(buf) == 0 ){
			int j;
			for ( j = 0; j < iffs; j++ ){
				memset(iff[j].gw_ip4,0,4);	
				gix_gen_broadcast_ipv4(iff[j].ip4, iff[j].prefixlen_ip4,iff[j].broadcast_ip4);
			}
			goto IP_AGAIN6;

		}
		if ( inet_addr(buf)  == INADDR_NONE ){
			alarm_window("Please enter a valid IPv4 address!",ALARM_ERROR,NULL,0);
			goto IP_AGAIN5;
		}
		xx = inet_addr(buf);
		gateway_ipv4[3] = ((xx) >> 24) & 0xFF;
		gateway_ipv4[2] = ((xx) >> 16) & 0xFF;
		gateway_ipv4[1] = ((xx) >> 8) & 0xFF;
		gateway_ipv4[0] = ((xx) >> 0) & 0xFF;

		// Now check if gateway is valid...
		for ( i = 0; i < iffs; i++ ){
			char dummy1[256];
			char dummy2[256];
			char dummy3[256];
			char dummy4[256];
			char dummy5[256];
			char dummy6[256];
			unsigned char netmask[4];
			unsigned char result1[4];
			unsigned char result2[4];
			unsigned char result3[4];
			if ( iff[i].active == 0 ) continue;
			gix_genmask_ipv4(iff[i].prefixlen_ip4,netmask);
			gix_apply_netmask_ipv4(netmask,iff[i].ip4,result1);
			gix_apply_netmask_ipv4(netmask,gateway_ipv4,result2);
			gix_gen_broadcast_ipv4(iff[i].ip4, iff[i].prefixlen_ip4, result3);
			debug_logger("[%s] NETMASK: [%s] IPV4: [%s] --> [%s] GW: [%s] --> [%s] (BCAST: [%s])\n",
					iff[i].name,
					display_ipv4(netmask,4,dummy1), 
					display_ipv4(iff[i].ip4,4,dummy2),
					display_ipv4(result1,4,dummy3),
					display_ipv4(gateway_ipv4,4,dummy4), 
					display_ipv4(result2,4,dummy5),
					display_ipv4(result3,4,dummy6));
			if ( memcmp(result1,result2,4) == 0 ){ 
				int j;
				for ( j = 0; j < iffs; j++ ){
					memset(iff[j].gw_ip4,0,4);	
					gix_gen_broadcast_ipv4(iff[j].ip4, iff[j].prefixlen_ip4,iff[j].broadcast_ip4);
				}
				memcpy(iff[i].gw_ip4,gateway_ipv4,4);
				break;
			}
		}
		if ( i == iffs ){
			alarm_window("Please enter a valid IPv4 gate-way address!\nThe given address is not matching any interface!",ALARM_ERROR,NULL,0);
			goto IP_AGAIN5;
		}
IP_AGAIN6:
		display_ipv6(gateway_ipv6,16,buf);
		if ( is_zero(gateway_ipv6,16)) strcpy(buf,"");
		if ( alarm_window("IPv6 Gateway (blank for no gateway): ",ALARM_INPUT,buf,50) < 0 ) goto END_LINUX;
		while ( strlen(buf) &&  isspace(buf[strlen(buf)-1]) ) buf[strlen(buf)-1] = 0x00;
		if ( strlen(buf) == 0 ){
			int j;
			for ( j = 0; j < iffs; j++ ){
				memset(iff[j].gw_ip6,0,16);	
			}
			goto DO_DNS;

		}
		if ( inet_pton(AF_INET6,buf,gateway_ipv6)  != 1 ){
			alarm_window("Please enter a valid IPv6 address!",ALARM_ERROR,NULL,0);
			goto IP_AGAIN6;
		}

		// Now check if gateway is valid...
		for ( i = 0; i < iffs; i++ ){
			char dummy1[256];
			char dummy2[256];
			char dummy3[256];
			char dummy4[256];
			char dummy5[256];
			unsigned char netmask[16];
			unsigned char result1[16];
			unsigned char result2[16];
			if ( iff[i].active == 0 ) continue;
			gix_genmask_ipv6(iff[i].prefixlen_ip4,netmask);
			gix_apply_netmask_ipv6(netmask,iff[i].ip4,result1);
			gix_apply_netmask_ipv6(netmask,gateway_ipv4,result2);
			debug_logger("[%s] NETMASK: [%s] IPV6: [%s] --> [%s] GW: [%s] --> [%s]\n",
					iff[i].name,
					display_ipv6(netmask,16,dummy1), 
					display_ipv6(iff[i].ip6,16,dummy2),
					display_ipv6(result1,16,dummy3),
					display_ipv6(gateway_ipv6,16,dummy4), 
					display_ipv6(result2,16,dummy5));
			if ( memcmp(result1,result2,16) == 0 ){ 
				int j;
				for ( j = 0; j < iffs; j++ ){
					memset(iff[j].gw_ip6,0,16);	
				}
				memcpy(iff[i].gw_ip6,gateway_ipv6,16);
				break;
			}
		}
		if ( i == iffs ){
			alarm_window("Please enter a valid IPv6 gate-way address!\nThe given address is not matching any interface!",ALARM_ERROR,NULL,0);
			goto IP_AGAIN6;
		}
DO_DNS:
		{
			char resolver_file[1024];
			char dns_server[1024];
			unsigned char ip[16];
			char the_ip[256];
			FILE *fp;

			sprintf(resolver_file,"%s/etc/resolv.conf",root_prefix);
DNS_AGAIN: 
			bzero(dns_server,64);
			if ( alarm_window("DNS-Server-IP(IPv4 or IPv6): ",ALARM_INPUT,dns_server,32) < 0 ){
				goto END_LINUX;
			}
			while ( strlen(dns_server) &&  isspace(dns_server[strlen(dns_server)-1]) ) dns_server[strlen(dns_server)-1] = 0x00;
			if ( inet_pton(AF_INET,dns_server,ip) != 1 && inet_pton(AF_INET6,dns_server,ip) != 1 ){
				alarm_window("Please enter a valid IPv4 or IPv6 address!",ALARM_ERROR,NULL,0);
				goto DNS_AGAIN;
			}
			unlink(resolver_file);
			if ( inet_pton(AF_INET,dns_server,ip) == 1 ){
				inet_ntop(AF_INET,ip,the_ip,255);
			} else {
				inet_pton(AF_INET6,dns_server,ip);
				inet_ntop(AF_INET6,ip,the_ip,255);
			}
			fp = fopen(resolver_file,"w");
			if ( fp ){
				fprintf(fp,"nameserver %s\n",the_ip);
				fclose(fp);
			}


		}
WRITE_IP_CONFIG:	
		// Everything done...write the config(s) now
		for ( i = 0; i < iffs; i++ ){
			write_interface(sysconfig,&iff[i]);
		}
		sync();
		umount("/mnt");	
		

END_LINUX:
		erase();
		display_options();
		refresh();
}

#define sock_readline(a,b,c) _sock_readline(__FILE__,__LINE__,(a),(b),(c))
#define sock_writeline(a,b,c) _sock_writeline(__FILE__,__LINE__,(a),(b),(c))
#define FTP_LINE_BUFFER 4096


int _sock_readline(char *file, int line, int sock,char *buf, char verbose){
	char c;
	int received = 0;
	*buf = 0x00;
	while ( recv(sock,&c,1,0) == 1 ){
		if ( c == '\r' ) continue;
		if ( c == '\n' ) break;
		buf[received++] = c;
		buf[received] = 0x00;
		if ( received == (FTP_LINE_BUFFER-1) ) break;
		
	}
	if ( verbose ) scroll_logger("SOCK_IO(%s:%d) (%d)<< %s\n",file,line,received,buf);
	return(received);
}

int _sock_writeline(char *file, int line, int sock, char *buf,char verbose){
	int retval;
	retval = send(sock,buf,strlen(buf),0);
	if ( verbose ) scroll_logger("SOCK_IO(%s:%d) (%d/%d)>> %s",file,line,retval,strlen(buf),buf);
	return(retval);
}


int ftp_login(struct _ipconfig *ipc, char verbose){
	struct addrinfo hints;
	struct addrinfo *result;
	struct addrinfo *rp;
	char buf[FTP_LINE_BUFFER];
	int s;
	int sock;
	int code;

	bzero(&hints,sizeof(struct addrinfo));
	hints.ai_family   = AF_INET;
	hints.ai_socktype = SOCK_STREAM;

	if ( (s = getaddrinfo(ipc->ftp_server,"21",&hints,&result)) != 0 ){
		if ( verbose ) debug_logger("Invalid [%s] --> [%s]\n",ipc->ftp_server,gai_strerror(s));
		return(-1);
	}
	sock = -1;
	for ( rp = result; rp != NULL; rp = rp->ai_next ){
		int save_fd;
		int old_fd;
		struct pollfd fd;
		sock = socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol);
		if ( sock < 0 ){
			if ( verbose ) debug_logger("Invalid [%s] --> Cannot create socket [%s]\n",ipc->ftp_server,strerror(errno));
			return(-1);
		}
		old_fd = fcntl(sock,F_GETFL);
		save_fd = O_NONBLOCK | old_fd;
		fcntl(sock,F_SETFL,save_fd);

		scroll_logger("Trying [%s]...\n",inet_ntoa( ((struct sockaddr_in *)rp->ai_addr)->sin_addr));
		strcpy(ipc->ftp_ip,inet_ntoa( ((struct sockaddr_in *)rp->ai_addr)->sin_addr));
		if ( connect(sock,rp->ai_addr,rp->ai_addrlen) < 0 && errno != EINPROGRESS){
			if ( verbose ) c_logger("\n");
			if ( verbose ) debug_logger("Invalid [%s] --> Cannot connect socket [%s]\n",ipc->ftp_server,strerror(errno));
			close(sock);
			sock = -1;
			continue;	
		}
		fd.events  = POLLIN | POLLHUP | POLLERR | POLLOUT;
		fd.revents = 0;
		fd.fd = sock;
		if ( poll(&fd,1,FTP_CONNECT_TIMEOUT) <= 0 ){
			if ( verbose ) c_logger("\n");
			if ( verbose ) debug_logger("Invalid [%s] --> Cannot connect socket(poll) [timed out]\n",ipc->ftp_server);
			close(sock);
			sock = -1;
			continue;	
		}
		if ( (fd.revents & POLLIN) || (fd.revents & POLLOUT) ){
			fcntl(sock,F_SETFL,old_fd);
			if ( verbose ) debug_logger("OK\n");
			while ( sock_readline(sock,buf,verbose) > 0 && buf[3] == '-' ); 
			code = atoi(buf);
			if ( code != 220 ){
				if ( verbose ) scroll_logger("Invalid [%s] --> Bad prompt! Code: %d\n",ipc->ftp_server,code);
				close(sock);
				sock = -1;
				continue;	
			}
			sprintf(buf,"USER %s\r\n",ipc->ftp_user);
			if ( sock_writeline(sock,buf,verbose) != strlen(buf) ){
				if ( verbose ) debug_logger("Invalid [%s] --> Write failed!\n",ipc->ftp_server);
				close(sock);
				sock = -1;
				continue;	
			}
			while ( sock_readline(sock,buf,verbose) > 0 && buf[3] == '-' ); 
			code = atoi(buf);
			if ( code < 300 || code > 399 ){
				if ( verbose ) debug_logger("Invalid [%s] --> Bad prompt! Code: %d\n",ipc->ftp_server,code);
				close(sock);
				sock = -1;
				continue;	
			}
			sprintf(buf,"PASS %s\r\n",ipc->ftp_pwd);
			if ( sock_writeline(sock,buf,verbose) != strlen(buf) ){
				if ( verbose ) debug_logger("Invalid [%s] --> Write failed!\n",ipc->ftp_server);
				close(sock);
				sock = -1;
				continue;	
			}
			while ( sock_readline(sock,buf,verbose) > 0 && buf[3] == '-' ); 
			code = atoi(buf);
			if ( code < 200 || code > 299 ){
				if ( verbose ) debug_logger("Invalid [%s] --> Bad prompt! Code: %d\n",ipc->ftp_server,code);
				close(sock);
				sock = -1;
				continue;	
			}
			sprintf(buf,"TYPE I\r\n");
			if ( sock_writeline(sock,buf,verbose) != strlen(buf) ){
				if ( verbose ) debug_logger("Invalid [%s] --> Write failed!\n",ipc->ftp_server);
				close(sock);
				sock = -1;
				continue;	
			}
			while ( sock_readline(sock,buf,verbose) > 0 && buf[3] == '-' ); 
			code = atoi(buf);
			if ( code < 200 || code > 299 ){
				if ( verbose ) debug_logger("Invalid [%s] --> Bad prompt! Code: %d\n",ipc->ftp_server,code);
				close(sock);
				sock = -1;
				continue;	
			}
			if ( verbose ) debug_logger("Login success!\n");
			return(sock);
		}
	}
	debug_logger("Tried all possibilities...giving up\n");
	return(-1);
}


void ftp_logout(int sock, char verbose){
	char buf[FTP_LINE_BUFFER];
	sprintf(buf,"QUIT\n");
	if ( sock_writeline(sock,buf,verbose) != strlen(buf) ){
		if ( verbose ) debug_logger("Write failed!\n");
		close(sock);
		return;
	}
	while ( sock_readline(sock,buf,verbose) > 0 && buf[3] == '-' ); 
	close(sock);
	return;
}


struct _ftp_file {
	char *name;
	char *localname;
	int is_tar;
	int is_compressed; // Only allowed, if 'is_tar' == 1 !!!
	u_int64_t size;	
};




struct _ftp_file efi_file[] = { 
		{ "/gixl2/efi/bzImage", "/mnt/bzImage",0,0, 0 },
		{ "/gixl2/efi/initrd.img","/mnt/initrd.img",0,0,0 },
		{ NULL,NULL,0,0,0 } };

struct _ftp_file gixl_file[] = { 
		{ "/gixl2/gixl2_install.tar.xz","/mnt/",1,1,0 },
		{ NULL,NULL,0,0,0 } };

unsigned char fat_magic[] = { 0xEB, 0x3C, 0x90 };



void create_path(char *_path){
	char path[4096];
	char current_dir[4096];
	char current_dir2[4096];
	char *here;
	char *hlp;
	char *dir;
	strcpy(path,_path);
	getcwd(current_dir,4095);	
	// debug_logger("We are here: [%s] --> Creating: [%s]\n",current_dir,path);
	here = path;
	hlp  = here;
	chdir("/");
	while ( (dir = strtok_r(here,"/",&hlp)) != NULL ){
		here = NULL;
		if ( strlen(dir) ){
			mkdir(dir,0755);
			chdir(dir);
			getcwd(current_dir2,4095);	
			// debug_logger("Created: [%s], Current_PATH: [%s]\n",dir,current_dir2);
		}

	}
	chdir(current_dir);


}

#define data (*_data)
#define read_tar_bytes(a,b,c) _read_tar_bytes(__FILE__,__LINE__,(a),(b),(c))

int64_t _read_tar_bytes(char *__file__,int __line__,int fd,u_int64_t file_size,char **_data){
	u_int64_t blocks;
	u_int64_t to_read;

	blocks = file_size / ((u_int64_t)512);
	if ( file_size % ((u_int64_t)512) ) blocks++;
	data = malloc(blocks * ((u_int64_t)512));
	to_read = blocks * ((u_int64_t)512);
	// debug_logger("[%s:%d] Reading %ju Bytes to memory\n",__file__,__line__,to_read);
	while (  to_read > 0 ){
		int64_t recvd;
		recvd = read(fd,&data[blocks * ((u_int64_t)512) - to_read],to_read);
		to_read -= recvd;
	}
	return(blocks * ((int64_t)512));
}

#undef data

#define read_tar_file(a,b,c) _read_tar_file(__FILE__,__LINE__,(a),(b),(c))
int64_t _read_tar_file(char *__file__,int __line__,int fd,u_int64_t file_size,char *fname){
	unsigned char buf[TBUFSIZE];
	u_int64_t blocks;
	u_int64_t to_read;
	u_int64_t tot_read;
	u_int64_t tot_written;
	int fp;
	if ( fname ){
		unlink(fname);
		fp = open(fname,O_WRONLY | O_CREAT,0644);
		if ( fp < 0 ){
			debug_logger("[%s:%d] Cannot open '%s' for writing! (%s)\n",__file__,__line__,fname,strerror(errno));
			return(-1);
		}
	}
	debug_logger("[%s:%d] Opened [%s] for %ju Bytes\n",__file__,__line__,fname,file_size);
	blocks = file_size / ((u_int64_t)512);
	if ( file_size % ((u_int64_t)512) ) blocks++;
	to_read = blocks * ((u_int64_t)512);

	// debug_logger("Reading %ju Bytes to file [%s], TOTAL: %ju\n",file_size,fname,to_read);
	tot_read = 0;
	tot_written = 0;
	while (  to_read > 0 ){
		int block_write;
		int block_read;
		int64_t recvd;
		int64_t recvd2;
		if ( to_read > TBUFSIZE )
			block_read = TBUFSIZE;
		else
			block_read = to_read;
		recvd = read(fd,buf,block_read);
		to_read -= recvd;
		tot_read += recvd;
		recvd2 = recvd;
		if ( tot_read > file_size ) recvd2 = (file_size - tot_written);
		block_write = 0;
		if ( recvd2 ) { 
			if ( fname ){
				block_write = write(fp,buf,recvd2); 
				if ( block_write != recvd2 ) 
					scroll_logger("Short write!!!\n"); 
			} else {
				block_write = recvd2;
			}
		}
		tot_written += block_write;
		// debug_logger("WRITTEN %d Bytes to file (%ju/%ju)\n",recvd,tot_written,file_size);
	}
	if ( fname ) close(fp);
	// debug_logger("Read %ju Bytes to file [%s], TOTAL: %ju (%ju Blocks)\n",file_size,fname,tot_read,blocks);
	return(blocks * ((int64_t)512));
}


int ftp_fetch(int sock,struct _ftp_file *fil, int verbose){
	char cmd[512];
	unsigned char tbuf[TBUFSIZE];
	char reply[1024];
	int code;
	int sockd;
	char *ptr;
	char *ptr2;
	char *hlp;
	char path_copy[1024];
	unsigned int port_low;
	unsigned int port_high;
	unsigned int ip_a;
	unsigned int ip_b;
	unsigned int ip_c;
	unsigned int ip_d;
	struct sockaddr_in data;
	unsigned short port;
	char ip_address[64];
	int file_out;

	sprintf(cmd,"PASV\r\n");
	if ( sock_writeline(sock,cmd,0) != strlen(cmd) ) return(-1);
	while ( sock_readline(sock,reply,0) > 0 && reply[3] == '-' ); 
	code = atoi(reply);
	if ( code < 200 || code > 299 ){
		return(-2);
	}
	ptr = reply;
	while ( *ptr && *ptr != '(' ) ptr++;
	if ( *ptr == 0x00 ){
		return(-3);
	}
	ptr++;
	hlp = ptr;
	ptr2 = strtok_r(ptr,"(),",&hlp);
	if ( ptr2 == NULL ){
		return(-4);
	}
	ip_a = atoi(ptr2);
	ptr2 = strtok_r(NULL,"(),",&hlp);
	if ( ptr2 == NULL ){
		return(-5);
	}
	ip_b = atoi(ptr2);
	ptr2 = strtok_r(NULL,"(),",&hlp);
	if ( ptr2 == NULL ){
		return(-6);
	}
	ip_c = atoi(ptr2);
	ptr2 = strtok_r(NULL,"(),",&hlp);
	if ( ptr2 == NULL ){
		return(-7);
	}
	ip_d = atoi(ptr2);
	ptr2 = strtok_r(NULL,"(),",&hlp);
	if ( ptr2 == NULL ){
		return(-8);
	}
	port_high = atoi(ptr2);
	ptr2 = strtok_r(NULL,"(),",&hlp);
	if ( ptr2 == NULL ){
		return(-9);
	}
	port_low = atoi(ptr2);
	if ( fil->is_tar ){
		create_path(fil->localname);		
	} else {
		char path_to_create[2048];
		char *ptr;

		strcpy(path_to_create,fil->localname);
		ptr = &path_to_create[strlen(path_to_create)-1];
		while ( ptr > path_to_create && *ptr != '/' ) ptr--;
		*ptr = 0x00;
		create_path(path_to_create);		
		unlink(fil->localname);
		file_out = open(fil->localname,O_WRONLY );
		if ( file_out < 0 )file_out = open(fil->localname,O_CREAT | O_WRONLY, 0755);
		if ( file_out < 0 ){
			debug_logger("Failed to open '%s' for writing (%s)\n",fil->localname,strerror(errno));
			return(-10);
		}
	}


	port = ((unsigned short) port_low)  + 256 * ((unsigned short)port_high);
	sprintf(ip_address,"%d.%d.%d.%d",ip_a, ip_b, ip_c, ip_d);
	data.sin_family = AF_INET;
	data.sin_port = htons(port);
	data.sin_addr.s_addr = inet_addr(ip_address);
	sockd = socket(AF_INET,SOCK_STREAM,0);
	if ( sockd < 0 ){
		close(file_out);
		return(-20);		
	}
	if ( connect(sockd,(struct sockaddr *)&data,sizeof(struct sockaddr_in)) < 0 ){
		close(sockd);
		close(file_out);
		return(-21);		
	}
	sprintf(cmd,"RETR %s\r\n",fil->name);
	if ( sock_writeline(sock,cmd,0) != strlen(cmd) ) return(-1);
	while ( sock_readline(sock,reply,0) > 0 && reply[3] == '-' ); 
	code = atoi(reply);
	if ( code < 100 || code > 199 ){
		close(sockd);
		close(file_out);
		return(-22);
	}
	scroll_logger("Installing [%s] to [%s] (%ju Bytes) %s:%u\n",fil->name,fil->localname,fil->size,ip_address,(unsigned int)port);
	if ( fil->is_tar == 0 ){
		u_int64_t received;
		u_int64_t total;
		total = 0;
		while ( (received = recv(sockd,tbuf,TBUFSIZE,0)) > 0 ){
			total += received;
			if ( write(file_out,tbuf,received) != received ){
				close(sockd);
				close(file_out);
				return(-23);
			}
			c_logger("Received %.02f%%       \r", (((double)total) / ((double)fil->size)) * 100.0);
		}
		close(file_out);
		scroll_logger("Installation completed\n");
	} else {
		int pipefd[2];
		signal(SIGCHLD,SIG_DFL);
		if ( pipe(pipefd) < 0 ){
			close(sockd);
			return(-30);
		}
		if ( fork() == 0 ){
			char k_filename[8192];	
			struct tar_header *hd;
			unsigned char buf[512];
			unsigned char zero[512];
			int real_red;
			int still_alive;
			close(pipefd[1]); // Close write end, this process just de-tars...
			strcpy(k_filename,"");
			while ( 1 ){
				struct utimbuf utim;
				int ownerid;
				int groupid;
				int devmajor;
				int devminor;
				time_t modtime;
				int filemode;
				u_int64_t file_size;
				unsigned char file_name[8192];
				unsigned char local_file_name[8192];
				char info[8192];
				real_red = 0;
				// debug_logger("Requesting another 512 Bytes from socket\n");
      	 			while ( real_red != 512 ){
					int red;
					red = read(pipefd[0],&buf[real_red],512 - real_red);
					if ( red < 0 ){
						scroll_logger("PIPE-Broken! (%s)\n",strerror(errno));
						exit(0);
					}
					if ( red == 0 ){
						debug_logger("File finished\n");
						exit(0);
					}
					real_red += red;
				}			
				// debug_logger("Received another 512 Bytes from socket\n");
				bzero(zero,512);
				if ( memcmp(buf,zero,sizeof(struct tar_header)) == 0 ){
						continue;
				}
				memset(zero,'0',512);
				if ( memcmp(buf,zero,sizeof(struct tar_header)) == 0 ){
						continue;
				}
				hd = (struct tar_header *)buf;
				if ( strncasecmp(hd->magic,"ustar",5) != 0 ) continue; // Skip NON USTAR-HEADER
				if ( hd->filesize[0] & 0x80 ){
					char hex_field[32];
					int x;
					bzero(hex_field,32);
					for ( x = 0; x < 11; x++ ){
						sprintf(&hex_field[strlen(hex_field)],"%02X",hd->filesize[1+x]);
					}
					file_size = 0;
					x = sscanf(hex_field,"%llx",&file_size);
					/*
					sprintf(info,"GNU-BASE256: HEX-Field: [%s] --> HEX_FIELD: %ju (%d)\n",hex_field,file_size,x);
					alarm_window(info,ALARM_INFO,NULL,0);
					*/
					if ( x != 1 ) continue;
				} else {
					if ( sscanf(hd->filesize,"%o",&file_size) != 1 ) continue;
				}
				/*
				sprintf(info,"GNU-BASE256: File-Name: [%s] --> SIZE: %ju Bytes\n",hd->filename,file_size);
				alarm_window(info,ALARM_INFO,NULL,0);
				*/
				if ( hd->typeflag[0] == 'L' ){
					char *data;
					read_tar_bytes(pipefd[0],file_size,&data);
					data[file_size]  = 0x00;
					strcpy(file_name,data);
					real_red = 0;
					free(data);
					while ( real_red != 512 ){
						int red;
						red = read(pipefd[0],&buf[real_red],512 - real_red);
						if ( red < 0 ){
							scroll_logger("PIPE-Broken! (%s)\n",strerror(errno));
							exit(0);
						}
						real_red += red;
					}			
					hd = (struct tar_header *)buf; // Get the real-file info after Logic-Link part
					if ( hd->filesize[0] & 0x80 ){
						char hex_field[32];
						int x;
						bzero(hex_field,32);
						for ( x = 0; x < 11; x++ ){
							sprintf(&hex_field[strlen(hex_field)],"%02X",hd->filesize[1+x]);
						}
						file_size = 0;
						x = sscanf(hex_field,"%llx",&file_size);
						/*
						sprintf(info,"GNU-BASE256: HEX-Field: [%s] --> HEX_FIELD: %ju (%d)\n",hex_field,file_size,x);
						alarm_window(info,ALARM_INFO,NULL,0);
						*/
						if ( x != 1 ) continue;
					} else {
						if ( sscanf(hd->filesize,"%o",&file_size) != 1 ) continue;
					}
				} else {
					strcpy(file_name,hd->filename);
				}
				sscanf(hd->ownerid,"%o",&ownerid);
				sscanf(hd->groupid,"%o",&groupid);
				sscanf(hd->modtime,"%o",&modtime);
				sscanf(hd->filemode,"%o",&filemode);
				sscanf(hd->devmajor,"%o",&devmajor);
				sscanf(hd->devminor,"%o",&devminor);
				sprintf(local_file_name,"%s/%s",fil->localname,file_name);
				bzero(&utim,sizeof(struct utimbuf));
				utim.actime  = modtime;
				utim.modtime = modtime;
				/*
				debug_logger(info," NEW PART IN TAR\n");
				debug_logger("File-Name:         [%s]\n",file_name);
				debug_logger("Local-File-Name:   [%s]\n",local_file_name);
				debug_logger("File-Size:         [%ju]\n",file_size);
				debug_logger("Owner-ID:          [%d]\n",ownerid);
				debug_logger("Group-ID:          [%d]\n",groupid);
				debug_logger("MOD-Time:          [%d]\n",modtime);
				debug_logger("File-Mode:         [%.8s] (%d)\n",hd->filemode,filemode);
				debug_logger("MAGIC:             [%.6s]\n",hd->magic);
				debug_logger("TYPEFLAG:          [%.1s]\n",hd->typeflag);
				debug_logger("LINKFILE:          [%.100s]\n",hd->linkname);
				*/
				if ( hd->typeflag[0] == '5' ){
					mkdir(local_file_name,filemode);
					chown(local_file_name,ownerid,groupid);
					utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == '0' || hd->typeflag[0] == 0x00 ){
					read_tar_file(pipefd[0],file_size,local_file_name);
					chown(local_file_name,ownerid,groupid);
					chmod(local_file_name,filemode);
					utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == '6' || hd->typeflag[0] == 6) { // A FIFO
					mkfifo(local_file_name,filemode);	
					chown(local_file_name,ownerid,groupid);
					utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == '3' || hd->typeflag[0] == 3) {
					mknod(local_file_name,filemode | S_IFCHR,makedev(devmajor,devminor));
					chown(local_file_name,ownerid,groupid);
					utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == '4' || hd->typeflag[0] == 4) {
					mknod(local_file_name,filemode | S_IFBLK,makedev(devmajor,devminor));
					chown(local_file_name,ownerid,groupid);
					utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == '2' || hd->typeflag[0] == 2 ) {
					char link_target[8192];
					if ( strlen(k_filename) )
						strcpy(link_target,k_filename);
					else
						strcpy(link_target,hd->linkname);
					symlink(link_target,local_file_name);
					debug_logger("SYM-LINKING: [%s] --> [%s]\n",local_file_name,link_target);
					strcpy(k_filename,"");
					// chown(local_file_name,ownerid,groupid);
					// utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == '1' || hd->typeflag[0] == 1 ) {
					char link_target[8192];
					if ( strlen(k_filename) )
						sprintf(link_target,"%s/%s",fil->localname,k_filename);
					else
						sprintf(link_target,"%s/%s",fil->localname,hd->linkname);
					link(link_target,local_file_name);
					debug_logger("LINKING: [%s] --> [%s]\n",local_file_name,link_target);
					strcpy(k_filename,"");
					// chown(local_file_name,ownerid,groupid);
					// utime(local_file_name,&utim);
				} else if ( hd->typeflag[0] == 'K' ) {
					char *data;
					read_tar_bytes(pipefd[0],file_size,&data);
					data[file_size] = 0x00;
					strcpy(k_filename,data);
					free(data);
					debug_logger("************ K-Link received [%s]\n",k_filename);
				} else {
					debug_logger("###### UNKNOWN PART IN TAR\n");
					debug_logger("######File-Name:         [%s]\n",file_name);
					debug_logger("######Local-File-Name:   [%s]\n",local_file_name);
					debug_logger("######File-Size:         [%ju]\n",file_size);
					debug_logger("######Owner-ID:          [%d]\n",ownerid);
					debug_logger("######Group-ID:          [%d]\n",groupid);
					debug_logger("######MOD-Time:          [%d]\n",modtime);
					debug_logger("######File-Mode:         [%.8s] (%d)\n",hd->filemode,filemode);
					debug_logger("######MAGIC:             [%.6s]\n",hd->magic);
					debug_logger("######TYPEFLAG:          [%.1s]\n",hd->typeflag);
					debug_logger("######LINKFILE:          [%.100s]\n",hd->linkname);
					debug_logger("######Current K-Link:    [%s]\n",k_filename);
					if ( file_size ) read_tar_file(pipefd[0],file_size,NULL);
					if ( hd->typeflag[0] == '2' ) strcpy(k_filename,"");
				}
			}	
			debug_logger("File totally received\n");
			close(pipefd[0]);
			exit(0);	
		} else {
			close(pipefd[0]);
			if ( fil->is_compressed ){ // Process LZMA here, before piping to TAR
				u_int64_t received;
				u_int64_t total_in;
				u_int64_t total_out;
				u_int64_t real_sent;
				u_int64_t cur_sent;
				char ratio[128];
				unsigned char tbuf_in[XZ_CHUNK_SIZE];
				unsigned char tbuf_out[XZ_CHUNK_SIZE];
				char buf[128];
				int lzma_ret;
				lzma_stream strm = LZMA_STREAM_INIT;

				total_in = 0;
				total_out = 0;





				if ( lzma_auto_decoder(&strm,UINT64_MAX,0) != LZMA_OK ){
					sprintf(buf,"Starting LZMA failed (internal error - maybe too less memory)?");
					alarm_window(buf,ALARM_ERROR,NULL,0);
					close(pipefd[1]);
					close(sockd);
					wait(NULL); 
					return(-100);
				}
				while ( (received = recv(sockd,tbuf_in,XZ_CHUNK_SIZE,0)) > 0 ){
					strm.next_in = tbuf_in;
					strm.avail_in = received;
					strm.avail_out = XZ_CHUNK_SIZE;
					strm.next_out = tbuf_out;
					total_in += received;
					do {
						if ( (lzma_ret = lzma_code(&strm, LZMA_RUN)) != LZMA_OK && lzma_ret != LZMA_STREAM_END ){
							sprintf(buf,"Decoding LZMA failed (internal error - maybe too less memory)?");
							alarm_window(buf,ALARM_ERROR,NULL,0);
							close(pipefd[1]);
							close(sockd);
							wait(NULL); 
							return(-101);
						}
						received = XZ_CHUNK_SIZE - strm.avail_out;
						real_sent = 0;
						while ( real_sent < received ){
							cur_sent = write(pipefd[1],&tbuf_out[real_sent],received - real_sent);
							real_sent += cur_sent;
						}
						total_out += received;
						strm.avail_out = XZ_CHUNK_SIZE;
						strm.next_out = tbuf_out;
					} while ( strm.avail_in > 0 );
					if ( total_out ){
						double tot_in;
						double tot_out;
						tot_in = (double) total_in;
						tot_out = (double) total_out;
						sprintf(ratio,"Compression: %.02f%%", 100 * ((tot_out - tot_in)/tot_out));
					} else {
						sprintf(ratio,"");
					}
					c_logger("Received %.02f%%       %s                       \r", (((double)total_in) / ((double)fil->size)) * 100.0,ratio);
					if ( lzma_ret == LZMA_STREAM_END ) break;
				}
				lzma_end(&strm);
				if ( total_out ){
					double tot_in;
					double tot_out;
					tot_in = (double) total_in;
					tot_out = (double) total_out;
					sprintf(ratio,",compression: %.02f%%", 100 * ((tot_out - tot_in)/tot_out));
				} else {
					sprintf(ratio,"         ");
				}
				scroll_logger("Installed%s                                              \n", ratio);
				close(pipefd[1]);
				wait(NULL); // Wait for child to exit...
			} else {
				u_int64_t received;
				u_int64_t total;
				u_int64_t real_sent;
				u_int64_t cur_sent;
				total = 0;
				while ( (received = recv(sockd,tbuf,TBUFSIZE,0)) > 0 ){
					real_sent = 0;
					while ( real_sent < received ){
						cur_sent = write(pipefd[1],&tbuf[real_sent],received - real_sent);
						real_sent += cur_sent;
					}
					total += received;
					c_logger("Received %.02f%%       \r", (((double)total) / ((double)fil->size)) * 100.0);
				}
				close(pipefd[1]);
				wait(NULL); // Wait for child to exit...
			}
			scroll_logger("File [%s] completely processed\n",fil->name);
		}
	}
	close(sockd);
	while ( sock_readline(sock,reply,0) > 0 && reply[3] == '-' ); 
	
	return(0);
}

struct _ext4list {
	char devname[256];
	struct  ext4_super_block superblock;
	char mountdir[256]; // Just for installation
	u_int64_t size;
};

struct  _ext4list *instpart = NULL;
int instparts = 0;
	

void files_setup(){
		int error_found;
		char zero[512];
		char cmd[512];
		char reply[1024];
		unsigned char buf[1024];
		int code;
		char *ptr;
		int retval;
		int sock;
		int i;
		
		create_sub1();
		attroff(COLOR_PAIR(BASE2_COLOR_NORMAL));
		bzero(zero,4);
		create_scroller("Setting up system");
		if ( memcmp(ipconfig.ip,zero,4) == 0 ){
			alarm_window("Please set up network first!",ALARM_ERROR,NULL,0);
			erase();
			display_options();
			refresh();
			return;
		}
LOGIN_FTP:
		strcpy(zero,ipconfig.ftp_server);
		if ( alarm_window("FTP-Server to use (IP or name): ",ALARM_INPUT,zero, 32) < 0 ){
			erase();
			display_options();
			refresh();
			return;
		}
		if ( strlen(zero) ){
			ptr = &zero[strlen(zero)-1];
			while ( ptr > zero && *ptr == ' ' ) { *ptr = 0x00; ptr--; }
		}
		strcpy(ipconfig.ftp_server,zero);
		strcpy(zero,ipconfig.ftp_user);
		if ( alarm_window("FTP-User to use: ",ALARM_INPUT,zero, 32) < 0 ){
			erase();
			display_options();
			refresh();
			return;
		}
		if ( strlen(zero) ){
			ptr = &zero[strlen(zero)-1];
			while ( ptr > zero && *ptr == ' ' ) { *ptr = 0x00; ptr--; }
		}
		strcpy(ipconfig.ftp_user,zero);
		strcpy(zero,ipconfig.ftp_pwd);
		if ( alarm_window("FTP-Password to use: ",ALARM_INPUT,zero, 32) < 0 ){
			erase();
			display_options();
			refresh();
			return;
		}
		if ( strlen(zero) ){
			ptr = &zero[strlen(zero)-1];
			while ( ptr > zero && *ptr == ' ' ) { *ptr = 0x00; ptr--; }
		}
		strcpy(ipconfig.ftp_user,zero);

		scroll_logger("Checking credentials\n");
		if ( (sock = ftp_login(&ipconfig,FTP_DEBUG)) < 0 ){
			if ( alarm_window("Connection to FTP-Server failed! Retry?",ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
			erase();
			display_options();
			refresh();
			return;
		} 
		for ( i = 0; efi_file[i].name != NULL; i++ ){
			int dummy;
			sprintf(cmd,"SIZE %s\r\n",efi_file[i].name);
			if ( sock_writeline(sock,cmd,FTP_DEBUG) != strlen(cmd) ){
				close(sock);
				sprintf(cmd,"FTP-Server does not contain mandatory [%s]\nRetry?",efi_file[i].name);
				if ( alarm_window(cmd,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
				erase();
				display_options();
				refresh();
				return;
			}
			while ( sock_readline(sock,reply,FTP_DEBUG) > 0 && reply[3] == '-' ); 
			code = atoi(reply);
			if ( code < 200 || code >= 300 ){
				close(sock);
				sprintf(cmd,"FTP-Server does not contain mandatory [%s]\nRetry?",efi_file[i].name);
				if ( alarm_window(cmd,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
				erase();
				display_options();
				refresh();
				return;
			}
			if ( sscanf(reply,"%d %ju",&dummy, &efi_file[i].size) != 2 ){
				close(sock);
				sprintf(cmd,"FTP-Server does not contain mandatory [%s]\nRetry?",efi_file[i].name);
				if ( alarm_window(cmd,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
				erase();
				display_options();
				refresh();
				return;
			}
			scroll_logger("[%s] --> %ju Bytes\n",efi_file[i].name,efi_file[i].size);
		}
		for ( i = 0; gixl_file[i].name != NULL; i++ ){
			int dummy;
			sprintf(cmd,"SIZE %s\r\n",gixl_file[i].name);
			if ( sock_writeline(sock,cmd,FTP_DEBUG) != strlen(cmd) ){
				close(sock);
				sprintf(cmd,"FTP-Server does not contain mandatory [%s]\nRetry?",gixl_file[i].name);
				if ( alarm_window(cmd,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
				erase();
				display_options();
				refresh();
				return;
			}
			while ( sock_readline(sock,reply,FTP_DEBUG) > 0 && reply[3] == '-' ); 
			code = atoi(reply);
			if ( code < 200 || code >= 300 ){
				close(sock);
				sprintf(cmd,"FTP-Server does not contain mandatory [%s]\nRetry?",gixl_file[i].name);
				if ( alarm_window(cmd,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
				erase();
				display_options();
				refresh();
				return;
			}
			if ( sscanf(reply,"%d %ju",&dummy, &gixl_file[i].size) != 2 ){
				close(sock);
				sprintf(cmd,"FTP-Server does not contain mandatory [%s]\nRetry?",gixl_file[i].name);
				if ( alarm_window(cmd,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_OK ) goto LOGIN_FTP;
				erase();
				display_options();
				refresh();
				return;
			}
			scroll_logger("[%s] --> %ju Bytes\n",gixl_file[i].name,gixl_file[i].size);
		}

		mkdir("/mnt",0755);
		error_found = 0;

		// First we install the EFI stuff...
		{
			DIR *dir;
			struct dirent *diry;
			dir = opendir("/dev");
			if ( dir ){
				char partname[1024];
				while ( (diry = readdir(dir)) != NULL ){
					strcpy(partname,"");
					if ( strncmp(diry->d_name,"sd",2) == 0 && strlen(diry->d_name) == 4 ){
						sprintf(partname,"/dev/%s",diry->d_name);
					}
					if ( strncmp(diry->d_name,"md",2) == 0 && strlen(diry->d_name) == 3 ){
						sprintf(partname,"/dev/%s",diry->d_name);
					}
					if ( strlen(partname) ){
						int fd;
						debug_logger("Checking partition  [%s]\n",partname);
						fd = open(partname,O_RDONLY);
						if ( fd < 0 ) continue;
						if ( lseek(fd,0,SEEK_SET) < 0 ){
							close(fd);
							continue;
						}
						if ( read(fd,(unsigned char *)buf,512) != 512 ){
							close(fd);
							continue;
						}
						close(fd);
						debug_logger("Checking partition for VFAT: [%s] [0x%02X] [0x%02X] [0x%02X]\n",partname,buf[0],buf[1],buf[2]);
						if ( memcmp(buf,fat_magic,3) == 0 ){
							scroll_logger("[%s] --> Microsoft FAT\n",partname);
							if ( mount(partname,"/mnt","vfat",0,NULL)  < 0 ){
								sprintf(buf,"Failed to mount [%s] as FAT (%s) --> Skip[OK] or abort[CANCEL]?\n",partname,strerror(errno));
								if ( alarm_window(buf,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
									close(sock);
									end_scroller();
									erase();
									display_options();
									refresh();
									return;
								}
							} else {
								for ( i = 0; efi_file[i].name != NULL; i++ ){
									int retval;
									if ( (retval = ftp_fetch(sock,&efi_file[i],FTP_DEBUG)) < 0 ){
										sprintf(buf,"Failed to fetch [%s] as (%s)[%s] --> (%d)\nSkip[OK] or abort[CANCEL]?\n",
												efi_file[i].name,partname,efi_file[i].localname,retval);
										if ( alarm_window(buf,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
											umount("/mnt");
											close(sock);
											end_scroller();
											erase();
											display_options();
											refresh();
											return;
										}
									}
								}
								sync();
								umount("/mnt");
								continue;
							}
						}

					}
				}
				closedir(dir);
			}

		}
		ftp_logout(sock,FTP_DEBUG);
		scroll_logger("----------------------------------------------------------\n");
		scroll_logger("Searching for EXT4 Partitions\n");
		scroll_logger("----------------------------------------------------------\n");
		{
			DIR *dir;
			struct dirent *diry;
			u_int64_t the_size;

			if ( instpart ){ free(instpart); instpart = NULL;}
			instparts = 0;	


			dir = opendir("/dev");
			if ( dir ){
				char partname[1024];
				while ( (diry = readdir(dir)) != NULL ){
					strcpy(partname,"");
					if ( strncmp(diry->d_name,"sd",2) == 0 && strlen(diry->d_name) == 4 ){
						sprintf(partname,"/dev/%s",diry->d_name);
					}
					if ( strncmp(diry->d_name,"md",2) == 0 && strlen(diry->d_name) == 3 ){
						sprintf(partname,"/dev/%s",diry->d_name);
					}
					if ( strlen(partname) ){
						unsigned buf[1024];
						int fd;
						struct ext4_super_block *super;
						debug_logger("Checking partition  [%s]\n",partname);
						fd = open(partname,O_RDONLY);
						if ( fd < 0 ) continue;
						if ( lseek(fd,1024,SEEK_SET) < 0 ){
							close(fd);
							continue;
						}
						if ( read(fd,(unsigned char *)buf,1024) != 1024 ){
							close(fd);
							continue;
						}
						the_size = lseek(fd,0,SEEK_END);
						close(fd);
						super = (struct ext4_super_block *)buf;	
						if ( checkraidmember(partname) ) continue; // Cannot be used for installation
						if ( super->s_magic == EXT4_MAGIC ){
							instpart = (struct _ext4list *)realloc(instpart,sizeof(struct _ext4list) * (instparts+1));
							bzero(&instpart[instparts],sizeof(struct _ext4list));
							memcpy(&instpart[instparts].superblock,super,sizeof(struct ext4_super_block));
							strcpy(instpart[instparts].devname,partname);
							instpart[instparts].size = the_size;
							scroll_logger("[%d]Partition [%s] SIZE: (%s)\n",
								instparts, partname,showsize(the_size));
							instparts++;
						}
					}
				}
				closedir(dir);
			}

		}
		if ( instparts ) {
			char helper[1024];
			int i,j;
			struct _select *sel;
			int instpart_index;
			create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 6, sub1->height - 4, "Select Root-Disk");
			sel = (struct _select *)malloc(sizeof(struct _select) * (instparts+1));
			mvwprintw(sub2->win,2,2, "Select now a root-disk for installing the operating system.");
			mvwprintw(sub2->win,4,2, "       Press <ESC> to abort the installation.");

			bzero(sel,sizeof(struct _select) * (instparts+1));

			for ( i = 0; i < instparts; i++ ){
				struct _raid *rd;
				if ( (rd = getraid(instpart[i].devname)) ){
					int i;
					sprintf(helper,"%s (%s) [RAID%d: ",instpart[i].devname,showsize(instpart[i].size),rd->level);
					for ( j = 0; j < rd->parts; j++ ){
						if ( j ) strcat(helper,", ");
						strcat(helper,rd->part[j].devname);
					}	
					strcat(helper,"]");

				} else {
					sprintf(helper,"%s (%s)",instpart[i].devname,showsize(instpart[i].size));
				}

				sel[i].name = strdup(helper);
			}
			current_select = 0;
			instpart_index = run_selector(NULL,sub2,4,sel,instparts,NULL);
			if ( instpart_index < 0 ){ error_found = 1; goto NO_ROOT_FOUND; }
			for ( i = 0; i < instparts; i++ ){
				free(sel[i].name);
			}
			free(sel);
			sprintf(helper,"Create a new ext4 file-system on [%s] before proceeding?",instpart[instpart_index].devname);
			if ( alarm_window(helper,ALARM_OKCANCEL,NULL,ANSWER_OK)  == ANSWER_OK ){
				{

					char **arg;
					int args;
					char caption[1024];
					char result[1024];
					arg  = NULL;
					args = 0;
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(EXT4_COMMAND);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup("-v");
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = strdup(instpart[instpart_index].devname);
					arg = (char **)realloc(arg,sizeof(char *) * (args+1));
					arg[args++] = NULL;
					sprintf(caption,"Creating EXT4 at %s",instpart[instpart_index].devname);
					sprintf(result,"EXT4 at %s created",instpart[instpart_index].devname);
					run_program(arg[0],arg,caption,result);
					for ( i = 0; i < args-1; i++ ) free(arg[i]);
					free(arg);
				}

			}
			// Mount filesystem now...
			create_scroller("Mounting and installing Root-Filesysem");
			if ( mount(instpart[instpart_index].devname,"/mnt","ext4",0,NULL)  < 0 ){
				error_found = 1;
				sprintf(buf,"Failed to mount [%s] as EXT4 (%s) --> Skip[OK] or abort[CANCEL]?\n",instpart[instpart_index].devname,strerror(errno));
				if ( alarm_window(buf,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
					close(sock);
					end_scroller();
					erase();
					display_options();
					refresh();
					return;
				}
			} else {
				mkdir("/mnt/dev",0755);
				mkdir("/mnt/proc",0755);
				mkdir("/mnt/sys",0755);
				mkdir("/mnt/run",0755);
				mkdir("/mnt/tmp",0777);
				mkdir("/mnt/etc",0755);
				mkdir("/mnt/fast",0755);
				mkdir("/mnt/large",0755);
				if ( (sock = ftp_login(&ipconfig,FTP_DEBUG)) < 0 ){
					alarm_window("Reconnection to FTP-Server failed!\n     (Aborting installation)",ALARM_ERROR,NULL,0);
				} else {
					for ( i = 0; gixl_file[i].name != NULL; i++ ){
						int retval;
						if ( (retval = ftp_fetch(sock,&gixl_file[i],FTP_DEBUG)) < 0 ){
							sprintf(buf,"Failed to fetch [%s] as (%s)[%s]\n (aborting installation)",
									gixl_file[i].name,instpart[instpart_index].devname,gixl_file[i].localname,retval);
							alarm_window(buf,ALARM_ERROR,NULL,0);
							if ( alarm_window(buf,ALARM_OKCANCEL,NULL,ANSWER_OK) == ANSWER_CANCEL ){
								umount("/mnt");
								close(sock);
								end_scroller();
								erase();
								display_options();
								refresh();
								return;
							}
						}
					}
					chmod("/mnt/tmp/",01777); // Include sticky-bit
					sync();
					// umount("/mnt"); // As we continue setup, leave it mounted
					ftp_logout(sock,FTP_DEBUG);
				}
			}
		} else {
NO_ROOT_FOUND:
			alarm_window("No Partition applicable as root-device found!\nInstallation aborted!",ALARM_ERROR,NULL,0);
		}
		scroll_logger("----------------------------------------------------------\n");






		
		if ( error_found == 0 ) alarm_window("System-Setup finished, your system is ready to be configured!",ALARM_INFO,NULL,0);
		end_scroller();
		erase();
		display_options();
		refresh();
}


struct _efivar *evi = NULL;
int evis = 0;

struct _select *evi_sel;
int evi_sels;
// current_select contains the currently selected element

struct _efidisk {
	char device[32];
	int partno; // From /dev/sdaX
	struct fdisk_context *ctx;
	struct fdisk_partition *pa;
	struct fdisk_parttype *pt;
	struct fdisk_label *label;
	u_int64_t start;
	u_int64_t size;
	char uuid[512];
	char label_name[512];
	int label_type;
};

struct _efidisk *efidisk = NULL;
int efidisks = 0;

void add_efi_entry(){
	char fname[1024];
	DIR *dir;
	struct dirent *diry;

	efidisk = NULL;
	efidisks = 0;


	dir = opendir("/dev");
	if ( dir == NULL ) return;

	while ( diry = readdir(dir) ){
		int i,fd;
		char partname[1024];
		char disk[1024];
		unsigned char buf[1024];
		const char *ptr;
		if ( (strncmp(diry->d_name,"sd",2) != 0) || (strlen(diry->d_name) != 4) ) continue;
		sprintf(partname,"/dev/%s",diry->d_name);
		fd = open(partname,O_RDONLY);
		if ( fd < 0 ) continue;
		if ( lseek(fd,0,SEEK_SET) < 0 ){
			close(fd);
			continue;
		}
		if ( read(fd,(unsigned char *)buf,512) != 512 ){
			close(fd);
			continue;
		}
		close(fd);
		if ( memcmp(buf,fat_magic,3) != 0 ) continue;
		strcpy(disk,partname);
		disk[strlen(disk)-1] = 0x00;
		efidisk = (struct _efidisk *)realloc(efidisk,sizeof(struct _efidisk) * (efidisks+1));
		bzero(&efidisk[efidisks],sizeof(struct _efidisk));
		strcpy(efidisk[efidisks].device,disk);
		efidisk[efidisks].partno = atoi(&diry->d_name[3]);
		efidisk[efidisks].ctx = fdisk_new_context();
		if ( fdisk_assign_device(efidisk[efidisks].ctx,efidisk[efidisks].device,1) != 0  ) continue;
		debug_logger("Partition [%d] is a valid canidate for DISK: [%s] %d\n",efidisk[efidisks].partno,efidisk[efidisks].device);
		for ( i = 0; i < 128; i++ ){
			int inuse;
			inuse = fdisk_is_partition_used(efidisk[efidisks].ctx,i);
			if ( inuse == 0 ) continue;
			if ( fdisk_get_partition(efidisk[efidisks].ctx, i, &efidisk[efidisks].pa) ) continue;
			if ( fdisk_partition_get_partno(efidisk[efidisks].pa) == ( efidisk[efidisks].partno - 1) )break;
		}
		efidisk[efidisks].label = fdisk_get_label(efidisk[efidisks].ctx,NULL);
		efidisk[efidisks].pt    = fdisk_label_get_parttype(efidisk[efidisks].label,i);
		efidisk[efidisks].start = fdisk_partition_get_start(efidisk[efidisks].pa);
		efidisk[efidisks].size  = fdisk_partition_get_size(efidisk[efidisks].pa);
		ptr  = fdisk_label_get_name(efidisk[efidisks].label);
		strcpy(efidisk[efidisks].label_name,ptr);
		ptr  = fdisk_partition_get_uuid(efidisk[efidisks].pa);
		strcpy(efidisk[efidisks].uuid,ptr);
		efidisk[efidisks].label_type = fdisk_label_get_type(efidisk[efidisks].label);
		debug_logger("PARTITION[%d] --> SIZE:  %ju\n",i,(efidisk[efidisks].size));
		debug_logger("PARTITION[%d] --> START: %ju\n",i,(efidisk[efidisks].start));
		debug_logger("PARTITION[%d] --> UUID:  [%s]\n",i,(efidisk[efidisks].uuid));
		debug_logger("PARTITION[%d] --> LABEL: [%s]\n",i,(efidisk[efidisks].label_name));
		debug_logger("PARTITION[%d] --> TYPE:  [%d]\n",i,(efidisk[efidisks].label_type));
		


		efidisks++;
	}
	closedir(dir);


}

int efi_action(int key){
	char helper[1024];
	int i,j;
        if ( key == 'd' || key == 'D' ){
		sprintf(helper,"Are you sure, you want to delete this entry?");
		if ( alarm_window(helper,ALARM_OKCANCEL,"<YES>|<NO>",ANSWER_CANCEL) == ANSWER_CANCEL ) return(HANDLER_RETURN_STAY);
                for ( i = 0; i < evi->bootorders; i++ ){
			if ( evi[evi_sel[current_select].internal_id].entrynr == evi->bootorder[i] ){
				char fname[1024];
				sprintf(fname,"%s/%s",EFI_PATH,evi[evi_sel[current_select].internal_id].name);
				unlink(fname);
				debug_logger("Deleted File: [%s]\n",fname);
				for ( j = i; j < (evi->bootorders-1); j++ )
					evi->bootorder[j] = evi->bootorder[j+1];
				break;
			}
		}
		evi->bootorders--;
		efi_write_boot_order(evi->bootorder, evi->bootorders);
		if ( current_select ) current_select--;
		return(HANDLER_RETURN_CURRENT_SELECT);
        }
	if ( key == 'n' || key == 'N' ){
		debug_logger("Trying to create new entry\n");
		add_efi_entry();
		current_select = 0;
		alarm_window("New entry created successfully",ALARM_INFO,NULL,0);
		return(HANDLER_RETURN_CURRENT_SELECT);
	}
        if ( key == '-' ){
		if ( current_select >= evi_sels ) return(HANDLER_RETURN_STAY); // Already at top
                for ( i = 0; i < (evi->bootorders-1); i++ ){
			if ( evi[evi_sel[current_select].internal_id].entrynr == evi->bootorder[i] ){
				if ( i ){
					u_int16_t swap_value;
					swap_value = evi->bootorder[i+1];
					evi->bootorder[i+1] = evi->bootorder[i];
					evi->bootorder[i] = swap_value;
				}
				break;
			}
		}
		if ( current_select < (evi_sels-1)){
			current_select++;
		}
		efi_write_boot_order(evi->bootorder, evi->bootorders);
		return(HANDLER_RETURN_CURRENT_SELECT);
	}
        if ( key == '+' ){
		if ( current_select == 0 ) return(HANDLER_RETURN_STAY); // Already at top
                for ( i = 0; i < evi->bootorders; i++ ){
			if ( evi[evi_sel[current_select].internal_id].entrynr == evi->bootorder[i] ){
				if ( i ){
					u_int16_t swap_value;
					swap_value = evi->bootorder[i-1];
					evi->bootorder[i-1] = evi->bootorder[i];
					evi->bootorder[i] = swap_value;
				}
				break;
			}
		}
		current_select--;
		efi_write_boot_order(evi->bootorder, evi->bootorders);
		return(HANDLER_RETURN_CURRENT_SELECT);
	}
        if ( key == KEY_RIGHT ){
        }
        return(HANDLER_RETURN_STAY);
}



void do_efi(){
	int i;
	int entry_index;
	current_select = 0;
DO_EFI:
	evis = load_efi_vars(&evi);
	for ( i = 0; i < evis; i++ ){
		dump_efi(&evi[i]);
	}

	create_sub2(sub1->start_x + 2, sub1->start_y + 2, sub1->width - 6, sub1->height - 4, "Manage EFI-Bootlist");
	evi_sels = 0;
	evi_sel  = NULL;
	for ( i = 0; i < evis; i++ ){
		if ( evi[i].entrynr == 0xFFFF ) continue;
		char helper[1024];
		evi_sel = (struct _select *)realloc(evi_sel,(evi_sels+1) * sizeof(struct _select));
		bzero(&evi_sel[evi_sels],sizeof(struct _select));
		sprintf(helper,"[%04X] (%c) [%ls] {%s}",evi[i].entrynr, evi[i].active ? '*' : ' ', evi[i].description,&(evi[i].name)[9]);
		evi_sel[evi_sels].name = strdup(helper);
		evi_sel[evi_sels].internal_id = i;
		evi_sels++;
	}
	mvwprintw(sub2->win,1,1,"<D> Delete <N>Insert new");
	mvwprintw(sub2->win,2,1,"<+> Move entry up <-> Move entry down");
	if ( (entry_index = run_selector(NULL,sub2,5,evi_sel,evi_sels,efi_action)) < 0 ) return;
	goto DO_EFI;
}




int main(int argc, char **argv){
	WINDOW *sub;
	int ch;
	int result;
	int args;
	char **arg;

/*
	struct _raid *rd;

	rd = getraid("/dev/sdc1");
	printf("RAID-CHECKING [/dev/sdc1] --> [%s]\n", rd == NULL ? "NULL" : rd->devname);
	rd = getraid("/dev/sdb1");
	printf("RAID-CHECKING [/dev/sdb1] --> [%s]\n", rd == NULL ? "NULL" : rd->devname);
	rd = getraid("/dev/sdb2");
	printf("RAID-CHECKING [/dev/sdb2] --> [%s]\n", rd == NULL ? "NULL" : rd->devname);
	rd = getraid("/dev/sda2");
	printf("RAID-CHECKING [/dev/sda2] --> [%s]\n", rd == NULL ? "NULL" : rd->devname);

	exit(0);


	setup_interfaces();
	exit(0);

	{
		struct _efivar *evi;
		int evis;
		int i;
		debug_logger("LOAD_EFI_VARS RETURND: %d\n",(evis = load_efi_vars(&evi)));
		for ( i = 0; i < evis; i++ ){
			dump_efi(&evi[i]);
		}
		exit(0);
	}

*/

	memset(ipbcast,255,4);
	dhcpmagic[0] = 0x63;
	dhcpmagic[1] = 0x82;
	dhcpmagic[2] = 0x53;
	dhcpmagic[3] = 0x63;


	sprintf(caption,"%s Setup",GIX_VERSION);



/*
	arg = NULL;
	args = 0;
	arg = (char **)realloc(arg,sizeof(char *) * (args+1));
	arg[args++] = strdup("[GIXSETUP]");

	arg = (char **)realloc(arg,sizeof(char *) * (args+1));
	arg[args++] = strdup("-asl");

	arg = (char **)realloc(arg,sizeof(char *) * (args+1));
	arg[args++] = strdup("/big");

	arg = (char **)realloc(arg,sizeof(char *) * (args+1));
	arg[args++] = NULL;

	result = run_program("/usr/bin/ls",arg);

	printf("\n\nRESULT: %d\n",result);

	exit(0);
*/

	sub1  = &_sub1;
	sub2  = &_sub2;
	walarm = &_walarm;
	screen = &_screen;
	runner = &_runner;

	bzero(sub1,sizeof(WIN));
	bzero(sub2,sizeof(WIN));
	bzero(walarm,sizeof(WIN));
	bzero(runner,sizeof(WIN));

	o_rows = 0;
	o_cols = 0;

	root = initscr();
	screen->win = root;
	screen->start_x = 0;
	screen->start_y = 0;
	box(root,0,0);
	start_color();
	init_pair(BASE2_COLOR_NORMAL,COLOR_BLACK, COLOR_CYAN);
	init_pair(BASE2_COLOR_ERROR,COLOR_RED, COLOR_CYAN);
	init_pair(BASE_COLOR_ERROR,COLOR_RED, COLOR_BLACK);
	init_pair(ALARM_COLOR_FATAL,COLOR_BLACK, COLOR_RED);     // ERROR
	init_pair(ALARM_COLOR_INFO,COLOR_BLACK, COLOR_GREEN);   // INFO
	init_pair(ALARM_COLOR_WARNING,COLOR_BLACK, COLOR_YELLOW);  // WARNING
	init_pair(ALARM_COLOR_OKCANCEL,COLOR_BLACK, COLOR_MAGENTA); // OK/CANCEL
	raw();
	keypad(stdscr,TRUE);
	noecho();
	/*
	while ( 1 ){
		ch = getch();
		printf("CH = %d\r\n",ch);
	}
	*/
	curs_set(0);
	display_options();
	refresh();
	while ( (ch = getch()) ){
		if ( ch == KEY_UP ){
			current_option--;
			if ( current_option < 0  ) current_option = options - 1;
			display_options();
			continue;
		}
		if ( ch == KEY_DOWN ){
			current_option++;
			if ( current_option >= options ) current_option = 0;
			display_options();
			continue;
		}
		if ( ch == KEY_ENTER || ch == 0x000A){
			run_main_action();
			continue;
		}
		if ( ch == 0x001B ) break;
	}
	erase();
	refresh();
	endwin();

	return(0);
}
