/* varmon.c VA RAID Monitor (VARMon)
    
Linux RAID Monitor for Mylex DAC960/1100 RAID controllers

Copyright 1999 by VA Linux Systems
Original author Dragan Stancevic <visitor@valinux.com>
Modification by Julien Danjou <julien@danjou.info>
    
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
Free Software Foundation.
    
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for complete details.
    
The author respectfully requests that any modifications to this software be
sent directly to him for evaluation and testing.
    
*/
 
/*
 Patches for varmon 1.0.2 submitted by:
	Wei Gao <wgao@valinux.com>, 
	Kurt Garloff <garloff@suse.de>
	
	Thanks.
*/
 
#include <errno.h>
#include <ctype.h>
#include <ncurses.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <scsi/scsi.h>
#include "DAC960.h"
#include "varmon.h"

/*
-------------------------------------------------------------------------------
Silently log the actions.
*/
int debugs(char *msg){
	FILE *log;

	log = fopen(".varmon.log", "a");
	if(!log){
		/*Exit silently*/
		return 0;
	}
	fputs(msg, log);
	fclose(log);
	return 1;
}
 
int debugi(int msg){
	FILE *log;
		 
	log = fopen(".varmon.log", "a");
	if(!log){
		/*Exit silently*/
		return 0;
	}
	fprintf(log, "[%d]", msg);
	fclose(log);
	return 1;
}  

// V2 support
#define BYTE_0(x)     (unsigned char)(x & 0xFF)
#define BYTE_1(x)     (unsigned char)((x >> 8) & 0xFF)
static int v2_SCSI_cmd(int fd, int cdb_s, unsigned char *cdb, int c, int t, 
  int C, int data_s, unsigned char * data, int sense_s, unsigned char *sense) 
{
	int rc;
#define v2_scsi_cmd	v2_user_cmd.CommandMailbox.SCSI_10

	DAC960_V2_UserCommand_T	v2_user_cmd ;
	memset((char *)&v2_user_cmd, 0, sizeof(v2_user_cmd));
        memcpy(v2_scsi_cmd.SCSI_CDB, cdb, cdb_s);
	v2_scsi_cmd.CommandOpcode	= DAC960_V2_SCSI_10_Passthru;
	v2_scsi_cmd.CommandTimeout.TimeoutValue = 
		DAC960_V1_DCDB_Timeout_10_seconds;
	v2_scsi_cmd.DataTransferSize	= (data_s > 0 ? data_s : -data_s);
	v2_scsi_cmd.PhysicalDevice.TargetID	= t;
	v2_scsi_cmd.PhysicalDevice.Channel	= c;
	v2_scsi_cmd.PhysicalDevice.Controller	= C;
	v2_scsi_cmd.CDBLength		= cdb_s;
	v2_user_cmd.DataTransferLength	= data_s;
	v2_user_cmd.DataTransferBuffer	= data;
	v2_user_cmd.RequestSenseLength	= sense_s;
	v2_user_cmd.RequestSenseBuffer	= sense;
	rc = ioctl(fd,DAC960_IOCTL_V2_EXECUTE_COMMAND,&v2_user_cmd);
	return rc;
}

// End V2 support

/* Send the command to the DAC driver. */
static int snd_cmd(int bus_h, DAC960_V1_DCDB_T *dcdb, void *tr_data, int tr_len, int controller){
	int status = 0;
	DAC960_V1_UserCommand_T usr_cmd;

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

	usr_cmd.ControllerNumber = controller;
	usr_cmd.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
	usr_cmd.DataTransferLength = tr_len;
	usr_cmd.DataTransferBuffer = tr_data;
	usr_cmd.DCDB = dcdb;

	status = ioctl(bus_h, DAC960_IOCTL_V1_EXECUTE_COMMAND, &usr_cmd);
	if (status == -1) {
		perror("\nFailed sending command to DAC driver");
		exit(2);
	}
	return(status);
}                              

/* Get the information from the backplane. */
int get_backplane_info(int what, SAFTE_T *safte, int controller, int cur_bp){
	int bus_h, status, tr_len = 64, i;
	int channel = safte->bp[cur_bp].channel;
	int id  = safte->bp[cur_bp].id;


	static int fans = 0, power_s = 0, slots = 0, temp_s = 0;
	unsigned char *p;

	char bus_n[] = "/dev/rd/c0d0";
	char bus_n_devfs[] = "/dev/rd/disc0/disc";
	char error_m[80];
	unsigned char tr_data[1024];
	DAC960_V1_DCDB_T dcdb;
	


	if((bus_h = open(bus_n, O_RDWR|O_NONBLOCK)) == -1)
	{
	  if((bus_h = open(bus_n_devfs, O_RDWR|O_NONBLOCK)) == -1)
	  {
		sprintf(error_m, "\nFailed to open %s", bus_n);
		perror(error_m);
		exit(1);
	  }
	}
	
	memset(tr_data, 0, 1024);
	memset(&dcdb, 0, sizeof(DAC960_V1_DCDB_T));
	
	switch(what){
	  case DEVICES:
	    if (IS_FIRMWARE_LEVEL_2(controller)) {
	      unsigned char cdb[10] = 
	      {SCSI_READ_BUFFER,0x1,0x0,0x0,0x0,0x0,0x0,
	       BYTE_1(tr_len),BYTE_0(tr_len),0x0};
	      status = v2_SCSI_cmd(bus_h, sizeof(cdb), cdb, channel, id, 
                           controller, tr_len, tr_data, 0, NULL); 
	    }
	    else {
	      dcdb.Channel = channel;
	      dcdb.TargetID = id;
	      dcdb.Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
	      dcdb.EarlyStatus = false;
	      dcdb.Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
	      dcdb.NoAutomaticRequestSense = false;
	      dcdb.DisconnectPermitted = true;
	      dcdb.TransferLength = tr_len;
	      dcdb.CDBLength =10;
	      dcdb.TransferLengthHigh4 =0;
	      dcdb.SenseLength = sizeof(dcdb.SenseData);
	      dcdb.CDB[0] = SCSI_READ_BUFFER;
	      dcdb.CDB[1] = 0x1; /* Mode is SAF-TE format */
	      dcdb.CDB[2] = 0x0; /* Read enclosure config */
	      dcdb.CDB[3] = 0x0;
	      dcdb.CDB[4] = 0x0;
	      dcdb.CDB[5] = 0x0;
	      dcdb.CDB[6] = 0x0;
	      dcdb.CDB[7] = (tr_len & 0xFF00) >> 8;
	      dcdb.CDB[8] = (tr_len & 0xFF);
	      dcdb.CDB[9] = 0x0;
 
	      status = snd_cmd(bus_h, &dcdb, tr_data, tr_len, controller);
	    }
	    fans = (int) tr_data[0];
	    power_s   = (int) tr_data[1];
	    slots = (int) tr_data[2];
	    temp_s = (int) tr_data[4];
	  break;
			
	  case TEMPERATURE:
	    tr_len = fans + power_s + slots + temp_s + 5;
	    if (IS_FIRMWARE_LEVEL_2(controller)) {
	      unsigned char cdb[10] = 
	      {SCSI_READ_BUFFER,0x1,0x1,0x0,0x0,0x0,0x0,
	       BYTE_1(tr_len),BYTE_0(tr_len),0x0};
	      status = v2_SCSI_cmd(bus_h, sizeof(cdb), cdb, channel, id, 
                           controller, tr_len, tr_data, 0, NULL);
	    }
	    else {
	      dcdb.Channel = channel;
	      dcdb.TargetID = id;
	      dcdb.Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
	      dcdb.EarlyStatus = false;
	      dcdb.Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
	      dcdb.NoAutomaticRequestSense = false;
	      dcdb.DisconnectPermitted = true;
	      dcdb.TransferLength = tr_len;
	      dcdb.CDBLength = 10;
	      dcdb.TransferLengthHigh4 = 0;
	      dcdb.SenseLength = sizeof(dcdb.SenseData);
	      dcdb.CDB[0] = SCSI_READ_BUFFER;
	      dcdb.CDB[1] = 0x1; /* Mode is SAF-TE format */
	      dcdb.CDB[2] = 0x1; /* Read enclosure config */
	      dcdb.CDB[3] = 0x0;
	      dcdb.CDB[4] = 0x0;
	      dcdb.CDB[5] = 0x0;
	      dcdb.CDB[6] = 0x0;
	      dcdb.CDB[7] = (tr_len & 0xFF00) >> 8;
	      dcdb.CDB[8] = (tr_len & 0xFF);
	      dcdb.CDB[9] = 0x0;
   
	      status = snd_cmd(bus_h, &dcdb, tr_data, tr_len, controller);
	    }
		
		p = tr_data;
		for (i=0; i < fans; i++){
			/*intf("Fan[%d] status",i);*/
				if (*p == 0x0)
					strcpy(safte->bp[cur_bp].fan[i], "ON");
					/*printf("operational\n");*/
				else if (*p == 0x01)
					strcpy(safte->bp[cur_bp].fan[i], "OFF");
					/*printf("malfunction\n");*/
				else if (*p == 0x02)
					strcpy(safte->bp[cur_bp].fan[i], "NONE");
					/*printf("not installed\n");*/
/*				else if (*p == 0x80)
					printf("status not reportable\n");
				else
					printf("broken\n");*/
				p++;
			}

			 for (i=0; i < power_s; i++){
				/*printf("Power Supply[%d] status",i);*/
				if (*p == 0x0)
					strcpy(safte->bp[cur_bp].ps[i], "ON");
					/*printf("operational and on\n");*/
				else if (*p == 0x01)
					strcpy(safte->bp[cur_bp].ps[i], "OFF");
					/*printf("operational and off\n");*/
				else if (*p == 0x10)
					strcpy(safte->bp[cur_bp].ps[i], "ERR");
					/*printf("malfunction and commanded on\n");*/
				else if (*p == 0x11)
					strcpy(safte->bp[cur_bp].ps[i], "ERR");
					/*printf("malfunction and commanded off\n");*/
				else if (*p == 0x20)
					strcpy(safte->bp[cur_bp].ps[i], "NONE");
					/*printf("not installed\n");*/
/*				else if (*p == 0x21)
					printf("installed\n");
				else if (*p == 0x80)
					printf("status not reportable\n");
				else
					printf("broken\n");*/
				p++;
			}      
/*
			for (i=0; i < slots; i++){
				printf("Device slot %d SCSI-ID -=> %d\n",i, (char )*p);
				p++;
			}*/
			p += (slots + 1 +1);
/*			printf("Door lock status -=> ");
			if (*p == 0x0)
				printf("locked\n");
			else if (*p == 0x01)
				printf("unlocked / no door lock\n");
			else if (*p == 0x80)
				printf("status not reportable\n");
			else
				printf("broken\n");
			p++;*/
/*
			printf("Speaker status -=> ");
			if (*p == 0x0)
				printf("Speaker off / no speaker installed\n");
			else if (*p == 0x01)
				printf("Speaker on\n");
			else
				printf("broken\n");
			p++;*/
			/*p += fans + slots + power_s + 1 + 1;*/
			for (i=0; i < temp_s; i++){
				if(safte->bp[cur_bp].got_nstor)
					sprintf(safte->bp[cur_bp].temp[i], "%d",
							(int)((float)((float)5/(float)9)*(*p-42)));
				else
					sprintf(safte->bp[cur_bp].temp[i], "%d", *p);
				p++;
			}
/*			{
			unsigned char   bitcnt;
			unsigned char   bitmask;
			unsigned char   tmp;

			if (*p & 0x80){
				printf("Enclosure Temperature Alert -=> [");
				for (bitcnt =0;bitcnt < 7; bitcnt++){
					bitmask = 0x1 << bitcnt;
					tmp = ((*p & bitmask) >> bitcnt);
					if (tmp == 0x1)
						printf("TEMP t%d\n",(8+bitcnt));
				}
				p++;
				for (bitcnt =0;bitcnt < 8; bitcnt++){
					bitmask = 0x1 << bitcnt;
					tmp = ((*p & bitmask) >> bitcnt);
					if (tmp == 0x1)
						printf("t%d ",bitcnt);
				}
				printf("]\n");
				p++;
			}
			else {
				printf("Enclosure Temperatures normal\n");
				p++;
				p++;
			}
			} 	*/
		break;
		}
	close(bus_h);
return 1;
}

/*------------------------------------------------------------------*/
struct {
	int controller_number;
	int channel;
	int target;
} backplane[32];

static int inquiry (int fd, int channel, int target,  DAC960_SCSI_Inquiry_T *inqptr, int controller){
	DAC960_V1_DCDB_T DCDB;
	int status;

	if (IS_FIRMWARE_LEVEL_2(controller)) {
		unsigned char cdb[6] = {0x12,0x0,0x0,0x0,sizeof(*inqptr),0x0};
		return v2_SCSI_cmd(fd, 6, cdb, channel, target, 
		controller, sizeof(*inqptr), (unsigned char *)inqptr, 0, NULL);
	}

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

	DCDB.Channel = channel;
	DCDB.TargetID = target;
	DCDB.Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
	DCDB.EarlyStatus = false;
	DCDB.Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
	DCDB.NoAutomaticRequestSense = false;
	DCDB.DisconnectPermitted = true;
	DCDB.TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
	DCDB.CDBLength =6;
	DCDB.TransferLengthHigh4 =0;
	DCDB.SenseLength = sizeof(DCDB.SenseData);
	DCDB.CDB[0] = 0x12;
	DCDB.CDB[1] = 0x0;
	DCDB.CDB[2] = 0x0;
	DCDB.CDB[3] = 0x0;
	DCDB.CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
	DCDB.CDB[5] = 0x0;

	status = snd_cmd(fd, &DCDB, inqptr, sizeof(DAC960_SCSI_Inquiry_T), controller);
	return(status);
}

static int tur(int fd, int channel, int target, int controller){
	DAC960_V1_DCDB_T DCDB;
	int status;

	if (IS_FIRMWARE_LEVEL_2(controller)) {
		unsigned char cdb[6] = {0x0,0x0,0x0,0x0,0x0,0x0};
		return v2_SCSI_cmd(fd, 6, cdb, channel, target, 
			controller, 0, NULL, 0, NULL);
	}

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

	DCDB.Channel = channel;
	DCDB.TargetID = target;
	DCDB.Direction = DAC960_V1_DCDB_NoDataTransfer;
	DCDB.EarlyStatus = false;
	DCDB.Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
	DCDB.NoAutomaticRequestSense = false;
	DCDB.DisconnectPermitted = true;
	DCDB.TransferLength = 0;
	DCDB.CDBLength =6;
	DCDB.TransferLengthHigh4 =0;
	DCDB.SenseLength = sizeof(DCDB.SenseData);
	DCDB.CDB[0] = TEST_UNIT_READY;
	DCDB.CDB[1] = 0x0;
	DCDB.CDB[2] = 0x0;
	DCDB.CDB[3] = 0x0;
	DCDB.CDB[4] = 0x0;
	DCDB.CDB[5] = 0x0;

	status = snd_cmd(fd, &DCDB, 0, 0, controller);
	return(status);
}
	
int detect_backplane(){
	int fd;
	DAC960_SCSI_Inquiry_T inq;
	int num_controllers;
	int controller_number;
	struct utsname ut;

	uname(&ut);
	
	/* If running 2.6 kernel */
	if(!strncmp("2.6", ut.release, 3))
	{
	  if((fd = open("/dev/dac960_gam", O_RDWR | O_NONBLOCK)) < 0)
	  {
		printf("Unable to open device (%m)\n");
		exit(1);
	  }
	}
	/* 2.4 kernel */
	else
	{
	  if((fd = open("/dev/rd/c0d0", O_RDWR | O_NONBLOCK))<0)
	  {
		/* devfs ? */
		if((fd = open("/dev/rd/disc0/disc", O_RDWR | O_NONBLOCK))<0)
		{
		  printf("Unable to open device (%m)\n");
		  exit(1);
		}
	  }
	}
	
	num_controllers = ioctl(fd, DAC960_IOCTL_GET_CONTROLLER_COUNT, 0);

	if(num_controllers <0){
		printf("get_controller_count ioctl() failed (%m)\n");
		exit(-1);
	}
	printf("\n");	
/*	printf("Scanning all channels for devices:\n");*/
	for(controller_number =0; controller_number < num_controllers; controller_number++){
		DAC960_ControllerInfo_T info;
	    int channel, target;

		info.ControllerNumber = controller_number;
		
		if(ioctl(fd, DAC960_IOCTL_GET_CONTROLLER_INFO, &info) <0){
			printf("Unable to get controller info (%m)\n");
			exit(-1);
		}
/*V2 support*/	snap_all[controller_number].FirmwareType = info.FirmwareType;  
		printf ("DAC960: Ctrlr %d, PCI %02x:%02x:%02x, IRQ %d, "
		"Channels %d\n", info.ControllerNumber, info.PCI_Bus, 
		info.PCI_Device, info.PCI_Function, info.IRQ_Channel, 
		info.Channels);
		printf ("DAC960: Model %s, Firmware %s\n", info.ModelName, 
		info.FirmwareVersion);
    	for(channel =0; channel < info.Channels; channel++)
			for(target =0; target < DAC960_V1_MaxTargets; target++){
				int status;
				
				printf("\rScanning Controller[%d], Channel[%d], ID[%d]  ", controller_number,
						channel, target);
				status = tur(fd, channel, target, controller_number);
#ifdef I_THOUGH_STATUS_0_MEANS_TUR_OK
				if (status != 0x0e){
#else
				if (status == 0){
#endif
					fflush(stdout);
					status = inquiry(fd, channel, target, &inq, controller_number);
					if ((!strncmp(inq.VendorIdentification,"QLogic",6)) ||
						(!strncmp(inq.VendorIdentification,"VA Linux",8))){
						int k;
						
						k = snap_all[controller_number].safte.no_bp;
						
						if(!strncmp(inq.VendorIdentification,"VA LinuxnexStor",15))
							snap_all[controller_number].safte.bp[k].got_nstor = 1;
						else
							snap_all[controller_number].safte.bp[k].got_nstor = 0;


						snap_all[controller_number].got_safte = 1;
						snap_all[controller_number].safte.bp[k].channel = channel;
						snap_all[controller_number].safte.bp[k].id = target;
						snap_all[controller_number].safte.no_bp++;

					}
				}
				}
	}
	close(fd);
	return 1;
}

int msg_box(char *cmd, int buttons){

	WINDOW *msgw;
	char msg1[] = "Are you sure you want to ";
	char msg_line[200];
	char msg_tmp[200];
	char *begin;
	char *delimit;
	int msg_len;

	int response = KEY_RIGHT, key;
	int dummy;
	
	strcpy(msg_tmp, msg1);
	
	if(buttons & B_OK){
		strcpy(msg_tmp, cmd);
		strcpy(msg_line, msg_tmp);
	}else if(buttons & B_NONE){
		strcpy(msg_tmp, cmd);
		strcpy(msg_line, msg_tmp);
	}else if((delimit = index(cmd, ' '))){
		begin = cmd;
		if((strstr(cmd, "check-consistency"))){
			strncat(msg_tmp, cmd, (delimit-begin));
			strcat(msg_tmp, " of RAID array");
			strcat(msg_tmp, delimit);
		}else {
			strncat(msg_tmp, cmd, (delimit-begin));
			strcat(msg_tmp, " device");
			strcat(msg_tmp, delimit);
		}
		strcat(msg_tmp, "?");
		strcpy(msg_line, msg_tmp);
	} else {
		strcat(msg_tmp, "cancel any rebuild or consistency check in progress?");
		strcpy(msg_line, msg_tmp);
	} 

	msgw = subwin(stdscr, 6, 45, ((LINES-5)/2), 18);

	if((buttons & B_YES_NO)){
		wattrset(msgw, A_BOLD|COLOR_PAIR(RED_YELLOW));
		wmove(msgw,0,0);
		for(dummy = 0; dummy <= ((msgw->_maxx+1)*(msgw->_maxy+1)) ; dummy++)
			waddch(msgw,' ');
		box(msgw,0,0);
		
		wattrset(msgw, A_DIM|COLOR_PAIR(BLUE_WHITE));
		mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)-(strlen(" YES"))), " YES ");
		wattrset(msgw, A_BOLD|COLOR_PAIR(BLUE_WHITE));
		mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)+(strlen("NO "))), " NO ");
		wattrset(msgw, A_BOLD|COLOR_PAIR(RED_YELLOW));

		
	}else if ((buttons & B_OK)){
		
		if(buttons & B_ERR)
			wattrset(msgw, A_BOLD|COLOR_PAIR(RED_YELLOW));
		else
			wattrset(msgw, A_BOLD|COLOR_PAIR(CYAN_YELLOW));
		
		wmove(msgw,0,0);
		for(dummy = 0; dummy <= ((msgw->_maxx+1)*(msgw->_maxy+1)) ; dummy++)
			waddch(msgw,' ');
		box(msgw,0,0);
			
		if(buttons & B_ERR)
			wattrset(msgw, A_BOLD|COLOR_PAIR(BLUE_WHITE));
		else
			wattrset(msgw, A_BOLD|COLOR_PAIR(BLUE_YELLOW));

		mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)-((strlen(" OK ")/2))), " OK ");
		
		if(buttons & B_ERR)
			wattrset(msgw, A_BOLD|COLOR_PAIR(RED_YELLOW));
		else
			wattrset(msgw, A_BOLD|COLOR_PAIR(CYAN_YELLOW));

	}else if ((buttons & B_NONE)){
		wattrset(msgw, A_BOLD|COLOR_PAIR(CYAN_YELLOW));
		wmove(msgw,0,0);
		for(dummy = 0; dummy <= ((msgw->_maxx+1)*(msgw->_maxy+1)) ; dummy++)
			waddch(msgw,' ');
		box(msgw,0,0);
	}

	msg_len = strlen(msg_tmp);
	if(msg_len > 43){
		begin = msg_tmp;
		for(dummy = 1; msg_len; dummy++){
			strncpy(msg_line, begin, 43);
			msg_line[42] = '\0';
			if(strlen(msg_line) > 41){
				delimit = rindex(msg_line, ' ');
			} else delimit = 0;
			if(delimit){
				*delimit = '\0';
				begin += (delimit-msg_line);
				begin++;
				mvwaddstr(msgw, dummy, ((msgw->_maxx/2)-((strlen(msg_line)/2))), msg_line);
			}else{
				mvwaddstr(msgw, dummy, ((msgw->_maxx/2)-((strlen(msg_line)/2))), msg_line);
				break;
			}
			msg_len = strlen(begin);
		}
	}else{
		mvwaddstr(msgw, 1, ((msgw->_maxx/2)-((strlen(msg_line)/2))), msg_line);
	
	}

	clearok(stdscr, TRUE);
	refresh();
	clearok(stdscr, FALSE);
	
	wrefresh(msgw);
	refresh();
	
	if ((buttons & B_NONE)){
		delwin(msgw);
		return 0;
	}
	while ((key = wgetch(stdscr))){
		if(key == KEY_ESCPE){
			response = key;
			break;
		}
		if((key == KEY_RETURN) || (key == KEY_RETURN1)){
			break;
		}
		if(key == KEY_LEFT){
			wattrset(msgw, A_BOLD|COLOR_PAIR(BLUE_WHITE));
			mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)-(strlen(" YES"))), " YES ");
			wattrset(msgw, A_DIM|COLOR_PAIR(BLUE_WHITE));
			mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)+(strlen("NO "))), " NO ");
			wattrset(msgw, A_BOLD|COLOR_PAIR(RED_YELLOW));
			response = KEY_LEFT;
		}else if(key == KEY_RIGHT){
			wattrset(msgw, A_BOLD|COLOR_PAIR(BLUE_WHITE));
			mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)+(strlen("NO "))), " NO ");
			wattrset(msgw, A_DIM|COLOR_PAIR(BLUE_WHITE));
			mvwaddstr(msgw, (msgw->_maxy - 1), ((msgw->_maxx/2)-(strlen(" YES"))), " YES ");
			wattrset(msgw, A_BOLD|COLOR_PAIR(RED_YELLOW));
			response = KEY_RIGHT;
		}
		wrefresh(msgw);
		refresh();
	}
	clearok(stdscr, TRUE);
	delwin(msgw);
	refresh();
	clearok(stdscr, FALSE);

	return response;
}

/*
-------------------------------------------------------------------------------
Execute commads.
*/
int command(char *target, char *msg){
	FILE *targeth;
	int run_cmd = 0;
	char buffer[200];
	char buffer_old[200];
	char seconds = 1;
		
	run_cmd = msg_box(msg, B_YES_NO);
	switch(run_cmd){
		case KEY_ESCPE:
		case KEY_RIGHT:
			run_cmd = msg_box("Operation canceled.", B_OK);
			return 0;
		break;
		
		case KEY_LEFT:
			run_cmd = msg_box("Operation in progress, this might"
					" take a few moments. Please wait...", B_NONE);

			targeth = fopen(target, "r+");
			if(!target){
				run_cmd = msg_box("Error communicating to the DAC driver!",
					   	B_OK|B_ERR);
				return 0;
			}
			
			/* It's trick to make the driver reset the user command */
			fputs("Run varmon -b", targeth);

			rewind(targeth);
			fgets(buffer_old, 200, targeth);
			rewind(targeth);
			fputs(msg, targeth);
			rewind(targeth);
			while(seconds){
				fgets(buffer, 200, targeth);
				rewind(targeth);

				if(strcmp(buffer_old, buffer)){
					*rindex(buffer, '\n') = 0;
					run_cmd = msg_box(buffer, B_OK);
					break;
				}
				
				if (seconds > 10){
					run_cmd = msg_box("Error communicating to the DAC"
							" driver! Giving up...", (B_OK|B_ERR));
						break;
				}
				sleep(1);
				seconds++;
			}

			fclose(targeth);
		break;
		
		default:
			return 0;
	
	}
	return 1;
}

/*
-------------------------------------------------------------------------------
Parse the target into lines for the parse_line,
I know I know, there is a function called fgets,
but there was a bug in one version of the
driver concerning sequential reads from proc
which would fail in reading all the information
so we try to have support for that version of the
driver too.
*/
int extract_data(char **buffer,char *file){

	int fileID, read_size, max_alow = MAX_READ;/*, to;*/
	char *data;

	cycle:

	fileID = open(file, O_RDONLY);
	if (fileID == -1){
		debugs("\nFailed to open file:");
		debugs(file);
		return 0;
	}

	data = calloc(max_alow, sizeof(char));
	while((read_size = read(fileID, data, max_alow))){
		if(read_size == max_alow){
			close(fileID);
			max_alow *= 2;
/*			Not enough stack, resizing.*/
			free(data);
			goto cycle;       

		}
	}

/*	NOTE Instead of freing the data we just pass it on
	to the function we got called within, let them worry
	about it.
*/
	*buffer = data;
/*	Passing on the stack.*/

	close(fileID);

	return 1;
}

/*
-------------------------------------------------------------------------------
Parse the data into single lines, one at the time.
Preparation to parse all the data into the data structure.
*/
int get_line(char *line, char *stat_path, int reset_flag){
	char **datap, *data = "Null";
	static char *offset;
	static char old_path[100];
	static int offsetc = 0;
	static int got_data = 0;
	static int e_of = 0;
	int linec;
/*	Init pointer to a pointer to a char*/
	datap = &data;

/*	If reset of the virtual lseek is
	required set the end of file flag*/
	if(!reset_flag) e_of = 1;

/*	Flag, an error has ocured*/

/*	Is the end of file flag up?
 	if so set it to ! end of file
 	and return 0*/	
	if(e_of){
		e_of = 0;
		offsetc = 0;
		return 0;
	}
	
	if(!strstr(stat_path, old_path)){
		got_data = 0;
	}

	if(!got_data){
	/*		Flag, an error has ocured*/
		if(!extract_data(datap, stat_path)){
		       	return 2;
		}
		got_data = 1;
		offset = *datap;
		offsetc = 0;
		strcpy(old_path, stat_path);

	}

	for(linec = 0; offset[offsetc] != '\n'; offsetc++, linec++)
		line[linec] = offset[offsetc];

	line[linec] = '\0';

	if(offset[(offsetc+1)] == '\0'){
/*
		Freeing the inherited stack.
*/
		free(offset);
		offsetc = 0;
		got_data = 0;
		e_of = 1;
       /*		return 0;*/
	}else{
	
		offsetc++;
	
	}
	
	return 1;
}


/*
-------------------------------------------------------------------------------
Parse the lines into data structure
This function parses the information from the stream directly
*/

int get_stat(SWINDOWS *all_win, CARD *card_pool, TAB *tab_pool){
	int cur_card, maxx, maxy, del_yy = 2, del_xx = 1;
	
	maxy = all_win->status_win->_maxy;
	maxx = all_win->status_win->_maxx;

/*		Repaint our screen
*/
	wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));
	wmove(all_win->status_win, del_yy, del_xx);
	for(;del_yy < (maxy+1) ; del_yy++){
		for(del_xx = 1; del_xx < maxx; del_xx++)
			waddch(all_win->status_win, ' ');
		del_xx = 1;
		wmove(all_win->status_win, del_yy, del_xx);
	}

/*	Walk trough the pages and get data from it, after that
	flush it on the screen.
*/
	for(cur_card = 0; cur_card < no_pages; cur_card++){

/*		Does this card have focus?
*/
		if(card_pool[cur_card].focus){

/*			Does this tab have focus?
*/
			if(tab_pool[0].focus){
				
/*				Display all the cyan characters
*/   
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_CYAN));

				mvwaddstr(all_win->status_win,
				2, 2, "Card:");
				
				mvwaddstr(all_win->status_win,
				3, 2, "Channels:");
				
				mvwaddstr(all_win->status_win,
				4, 2, "Memory:");
				
				mvwaddstr(all_win->status_win,
				5, 2, "Firmware:");
				
				mvwaddstr(all_win->status_win,
				maxy-4, 2, "Author:");
				
				mvwaddstr(all_win->status_win,
				maxy-3, 2, "Ver.:");
				
				mvwaddstr(all_win->status_win,
				maxy-2, 2, "Kernel:");

				mvwaddstr(all_win->status_win,
				maxy-1, 2, "Host:");

				mvwaddstr(all_win->status_win,
				7, 2, "Controller Q Depth:");
				
				mvwaddstr(all_win->status_win,
				8, 2, "Driver Q Depth:");
				
				mvwaddstr(all_win->status_win,
				9, 2, "Stripe Size:");
				
				mvwaddstr(all_win->status_win,
				10, 2, "Segment Size:");
				
				mvwaddstr(all_win->status_win,
				11, 2, "Max Block/Command:");
				
				mvwaddstr(all_win->status_win,
				12, 2, "Max Scatter/Gather:");
				
				mvwaddstr(all_win->status_win,
				13, 2, "BIOS Geometry:");
				
				mvwaddstr(all_win->status_win,
				14, 2, "SAF-TE:");

				mvwaddstr(all_win->status_win,
				2, 30, "PCI Bus:");
				
				mvwaddstr(all_win->status_win,
				3, 30, "Device:");
				
				mvwaddstr(all_win->status_win,
				4, 30, "Function:");
				
				mvwaddstr(all_win->status_win,
				5, 30, "IRQ:");

				/*mvwaddstr(all_win->status_win,
				6, 30, "I/O Address:");*/

				mvwaddstr(all_win->status_win,
				6, 30, "PCI Address:");
				
				mvwaddstr(all_win->status_win,
				7, 30, "Mapped to:");
				
				if(snap_all[cur_card].got_safte){
					int a,b,d;
					char c[4];

					for(a = 0, d = 9; a < snap_all[cur_card].safte.no_bp; a++){
						sprintf(c, "C%d", snap_all[cur_card].safte.bp[a].channel);
						for(b = 0; b < 3; b++){
							mvwaddstr(all_win->status_win, (b+d), 28, c);
							switch(b){
								case 0:
									mvwaddstr(all_win->status_win, (b+d),
										   	31, "Fan0:");
									mvwaddstr(all_win->status_win, (b+d),
										   	42, "Fan1:");
									mvwaddstr(all_win->status_win, (b+d),
										   	53, "Fan2:");
								break;
							
								case 1:
									mvwaddstr(all_win->status_win, (b+d),
										   	31, "Temp0:    C");
									mvwaddch(all_win->status_win, (b+d),
										   	40, ACS_DEGREE);
									mvwaddstr(all_win->status_win, (b+d),
										   	46, "Temp1:    C");
									mvwaddch(all_win->status_win, (b+d),
										   	55, ACS_DEGREE);
								break;	
								
								case 2:
									mvwaddstr(all_win->status_win, (b+d),
										   	31, "Power0:");
									mvwaddstr(all_win->status_win, (b+d),
										   	46, "Power1:");
								break;
							
							}
						}
						d += b;
						d++;
					}
					
				}

/*				Display all the yellow characters
*/   
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_YELLOW));

				mvwaddstr(all_win->status_win,
				2, 12, snap_all[cur_card].c_type);
				
				mvwaddstr(all_win->status_win,
				3, 12, snap_all[cur_card].chnl);
				
				mvwaddstr(all_win->status_win,
				4, 12, snap_all[cur_card].mem);
				
				mvwaddstr(all_win->status_win,
				5, 12, snap_all[cur_card].frmw);
				
				mvwaddstr(all_win->status_win,
				maxy-4, 9, snap_all[cur_card].dr_au);

				mvwaddstr(all_win->status_win,
				maxy-3, 9, snap_all[cur_card].dr_ver);
				
				mvwaddnstr(all_win->status_win,
				maxy-2, 9, OS.release, 15);
				
				mvwaddnstr(all_win->status_win,
				maxy-1,9, OS.nodename, 15);

				mvwaddstr(all_win->status_win,
				7, 21, snap_all[cur_card].cq_depth);
				
				mvwaddstr(all_win->status_win,
				8, 21, snap_all[cur_card].dq_depth);
				
				mvwaddstr(all_win->status_win,
				9, 21, snap_all[cur_card].stripe_size);
				
				mvwaddstr(all_win->status_win,
				10, 21, snap_all[cur_card].seg_size);
				
				mvwaddstr(all_win->status_win,
				11, 21, snap_all[cur_card].max_block_com);
				
				mvwaddstr(all_win->status_win,
				12, 21, snap_all[cur_card].max_sg_seg);
				
				mvwaddstr(all_win->status_win,
				13, 21, snap_all[cur_card].bios_geo);
				
				if(snap_all[cur_card].fault_mngmt)
					mvwaddstr(all_win->status_win,
					14, 21, "ON");
				else
					mvwaddstr(all_win->status_win,
					14, 21, "OFF");

				mvwaddstr(all_win->status_win,
				2, 49, snap_all[cur_card].pci_bus);
				
				mvwaddstr(all_win->status_win,
				3, 49, snap_all[cur_card].device);

				mvwaddstr(all_win->status_win,
				4, 49, snap_all[cur_card].function);
				
				mvwaddstr(all_win->status_win,
				5, 49, snap_all[cur_card].irq);
				
				/*mvwaddstr(all_win->status_win,
				6, 49, snap_all[cur_card].io_addr);*/
				
				mvwaddstr(all_win->status_win,
				6, 49, snap_all[cur_card].pci_addr);
				
				mvwaddstr(all_win->status_win,
				7, 49, snap_all[cur_card].pci_mapped);

/*				mvwaddstr(all_win->status_win,
				17, 47, OS.sysname);

				mvwaddstr(all_win->status_win,
				17, 53, OS.machine);

				mvwaddnstr(all_win->status_win,
				18,47, OS.nodename, 15);

				mvwaddnstr(all_win->status_win,
				19, 47, OS.release, 15);*/
			
			
				if(snap_all[cur_card].got_safte){
					int a,b,d;
					char c[4];

					for(a = 0, d = 9; a < snap_all[cur_card].safte.no_bp; a++){
						sprintf(c, "C%d", snap_all[cur_card].safte.bp[a].channel);
						for(b = 0; b < 3; b++){
							switch(b){
								case 0:
									mvwaddstr(all_win->status_win, (b+d),
										   	36, (strlen(snap_all[cur_card].safte.bp[a].fan[0])?
										   	snap_all[cur_card].safte.bp[a].fan[0] : "N/A"));

									mvwaddstr(all_win->status_win, (b+d),
										   	47, (strlen(snap_all[cur_card].safte.bp[a].fan[1])?
										   	snap_all[cur_card].safte.bp[a].fan[1] : "N/A"));
									
									mvwaddstr(all_win->status_win, (b+d),
										   	58, (strlen(snap_all[cur_card].safte.bp[a].fan[2])?
										   	snap_all[cur_card].safte.bp[a].fan[2] : "N/A"));
								break;

								case 1:
									mvwaddstr(all_win->status_win, (b+d),
										   	37, (strlen(snap_all[cur_card].safte.bp[a].temp[0])?
										   	snap_all[cur_card].safte.bp[a].temp[0] : "N/A"));

									mvwaddstr(all_win->status_win, (b+d),
										   	52, (strlen(snap_all[cur_card].safte.bp[a].temp[1])?
										   	snap_all[cur_card].safte.bp[a].temp[1] : "N/A"));
								break;

								case 2:
									mvwaddstr(all_win->status_win, (b+d),
										   	38, (strlen(snap_all[cur_card].safte.bp[a].ps[0])?
										   	snap_all[cur_card].safte.bp[a].ps[0] : "N/A"));

									mvwaddstr(all_win->status_win, (b+d),
										   	53, (strlen(snap_all[cur_card].safte.bp[a].ps[1])?
										   	snap_all[cur_card].safte.bp[a].ps[1] : "N/A"));
								break;
							}
						}
						d += b;
						d++;
					}
																			  
				}

/*				Display all the white characters
*/   
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_WHITE));

				/*mvwaddch(all_win->status_win,
				2, 27, ACS_ULCORNER);*/

				mvwaddch(all_win->status_win,
				6, 27, ACS_URCORNER);
				
				/*whline(all_win->status_win, ACS_HLINE, maxx-28);*/
				
				/*waddstr(all_win->status_win,
				"System Settings");*/
				
				/*mvwaddch(all_win->status_win,
				2, maxx, ACS_RTEE);*/
				
				mvwvline(all_win->status_win, 7, 27,
				ACS_VLINE, (maxy-7));

				mvwaddch(all_win->status_win,
				6, 0, ACS_LTEE);

				mvwhline(all_win->status_win, 6, 1,
				ACS_HLINE, 26);
				
				waddstr(all_win->status_win, "Controller Settings");
				
				/*mvwaddch(all_win->status_win,
				6, 27, ACS_RTEE);*/

				mvwhline(all_win->status_win, 8, 28,
				ACS_HLINE, (maxx-28));

				mvwhline(all_win->status_win, 12, 28,
				ACS_HLINE, (maxx-28));

				mvwhline(all_win->status_win, 16, 28,
				ACS_HLINE, (maxx-28));

				mvwaddch(all_win->status_win,
				8, maxx, ACS_RTEE);

				mvwaddstr(all_win->status_win,
				8, 28, "SAF-TE Information");

				mvwaddch(all_win->status_win,
				8, 27, ACS_LTEE);

				/*mvwhline(all_win->status_win, 15, 29,
				ACS_HLINE, (maxx-29));*/

				/*mvwaddstr(all_win->status_win,
				16, 29, "OS Info");*/

				mvwaddch(all_win->status_win,
				maxy, 27, ACS_BTEE);

				mvwaddch(all_win->status_win,
				(maxy-5), 0, ACS_LTEE);

				whline(all_win->status_win, ACS_HLINE, 26);
				
				mvwaddstr(all_win->status_win,
				maxy-5, 1, "General Driver Info");

				mvwaddch(all_win->status_win,
				maxy-5, 27, ACS_RTEE);

				/*mvwaddch(all_win->status_win,
				16, 27, ACS_LTEE);*/

				/*mvwaddch(all_win->status_win,
				16, maxx, ACS_RTEE);*/
			}

/*			Does this tab have focus?
*/
			if(tab_pool[1].focus){
				int matrixx0 = 2, matrixy0 = 4;
				int matrixx1 = 23, matrixy1 = 4;
				int matrixx2 = 44, matrixy2 = 4;
				int counter;
				char ds_size[10];
				float df_size ;

				/*Asume there are no devices present*/
				wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_CYAN));
				mvwaddstr(all_win->status_win, 2, matrixx0, "CH:0 No Devices");
				mvwaddstr(all_win->status_win, 2, matrixx1, "CH:1 No Devices");
				mvwaddstr(all_win->status_win, 2, matrixx2, "CH:2 No Devices");

				for(counter = 0; counter < snap_all[cur_card].no_ph_dev;
				counter++){
/*				
				Set the display matrix
*/
					if(snap_all[cur_card].ph_dev[counter].state[0] == 'D')
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_RED));
					else if(snap_all[cur_card].ph_dev[counter].state[0] == 'O')
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_GREEN));
					else
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_YELLOW));

					df_size = atol(snap_all[cur_card].ph_dev[counter].blocks);
					
					if((snap_all[cur_card].ph_dev[counter].state[0] == 'n')
						|| (snap_all[cur_card].ph_dev[counter].state[0] == 'F')
						|| (snap_all[cur_card].ph_dev[counter].state[0] == 'S'))
						strcpy(ds_size, "");
					else
						sprintf(ds_size, "%.1fGB", ((df_size*512)/(float)1073741824));

					if(snap_all[cur_card].ph_dev[counter].target[0] == '0'){

						if((snap_all[cur_card].ph_dev[counter].focus) &&
							(lock == LOCK_CMD)){

							wattrset(all_win->status_win, CARDLIST_NOFOCUS);
							mvwhline(all_win->status_win, matrixy0, (matrixx0-1),
							' ', 20);
						}

						mvwaddstr(all_win->status_win,
						matrixy0, matrixx0 + 10,
					   	ds_size);

						mvwaddstr(all_win->status_win,
						matrixy0, matrixx0 + 5,
					   	snap_all[cur_card].ph_dev[counter].state);

						mvwaddstr(all_win->status_win,
						matrixy0++, matrixx0,
					   	snap_all[cur_card].ph_dev[counter].target);
						
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_CYAN));

						mvwhline(all_win->status_win, 2, (matrixx0-1),
						' ', 17);
						mvwaddstr(all_win->status_win, 2, matrixx0 - 1, "CH:ID");
						mvwaddstr(all_win->status_win, 2, matrixx0 + 5, "STAT");
						mvwaddstr(all_win->status_win, 2, matrixx0 + 10, "Size");

					}

					if(snap_all[cur_card].ph_dev[counter].target[0] == '1'){
						
						if((snap_all[cur_card].ph_dev[counter].focus) &&
							(lock == LOCK_CMD)){

							wattrset(all_win->status_win, CARDLIST_NOFOCUS);
							mvwhline(all_win->status_win, matrixy1, (matrixx1-1),
							' ', 20);
						}

						mvwaddstr(all_win->status_win,
						matrixy1, matrixx1 + 10,
					   	ds_size);

						mvwaddstr(all_win->status_win,
						matrixy1, matrixx1 + 5,
					   	snap_all[cur_card].ph_dev[counter].state);

						mvwaddstr(all_win->status_win,
						matrixy1++, matrixx1,
					   	snap_all[cur_card].ph_dev[counter].target);

/*						Display all the cyan characters
*/   
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_CYAN));

						mvwhline(all_win->status_win, 2, (matrixx1-1),
						' ', 17);
						mvwaddstr(all_win->status_win, 2, matrixx1-1, "CH:ID");
						mvwaddstr(all_win->status_win, 2, matrixx1 + 5, "STAT");
						mvwaddstr(all_win->status_win, 2, matrixx1 + 10, "Size");
					}

					if(snap_all[cur_card].ph_dev[counter].target[0] == '2'){
						
						if((snap_all[cur_card].ph_dev[counter].focus) &&
							(lock == LOCK_CMD)){

							wattrset(all_win->status_win, CARDLIST_NOFOCUS);
							mvwhline(all_win->status_win, matrixy2, (matrixx2-1),
							' ', 19);
						}

						mvwaddstr(all_win->status_win,
						matrixy2, matrixx2 + 10,
					   	ds_size);

						mvwaddstr(all_win->status_win,
						matrixy2, matrixx2 + 5,
					   	snap_all[cur_card].ph_dev[counter].state);

						mvwaddstr(all_win->status_win,
						matrixy2++, matrixx2,
					   	snap_all[cur_card].ph_dev[counter].target);

/*						Display all the cyan characters
*/   
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_CYAN));

						mvwhline(all_win->status_win, 2, (matrixx2-1),
						' ', 17);
						mvwaddstr(all_win->status_win, 2, matrixx2-1, "CH:ID");
						mvwaddstr(all_win->status_win, 2, matrixx2 + 5, "STAT");
						mvwaddstr(all_win->status_win, 2, matrixx2 + 10, "Size");
					}
				}

/*				Display all the white characters
*/   
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_WHITE));

				mvwhline(all_win->status_win, 3, 1,
				ACS_HLINE, (maxx-1));
				
				mvwvline(all_win->status_win, 2, (matrixx1-2),
				ACS_VLINE, (maxy-2));

				mvwvline(all_win->status_win, 2, (matrixx2-2),
				ACS_VLINE, (maxy-2));

				mvwaddch(all_win->status_win,
				3, 0, ACS_LTEE);

				mvwaddch(all_win->status_win,
				3, maxx, ACS_RTEE);
				
				mvwaddch(all_win->status_win,
				3, (matrixx1-2), ACS_PLUS);

				mvwaddch(all_win->status_win,
				3, (matrixx2-2), ACS_PLUS);

				mvwaddch(all_win->status_win,
				1, (matrixx1-2), ACS_TTEE);

				mvwaddch(all_win->status_win,
				1, (matrixx2-2), ACS_TTEE);

				mvwaddch(all_win->status_win,
				maxy, (matrixx1-2), ACS_BTEE);

				mvwaddch(all_win->status_win,
				maxy, (matrixx2-2), ACS_BTEE);
			}

/*			Does this tab have focus?
*/
			if(tab_pool[2].focus){
				int matrixx0 = 1, matrixy0 = 4;
				int counter, mid = 31;
				char *offset;
				char ds_size[10];
				float df_size ;

/*				Display all the cyan characters
*/ 
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_CYAN));

				mvwaddstr(all_win->status_win, 2, matrixx0, "DEV");
				mvwaddstr(all_win->status_win, 2, matrixx0 + 6, "STAT");
				mvwaddstr(all_win->status_win, 2, matrixx0 + 13, "Size");
				mvwaddstr(all_win->status_win, 2, matrixx0 + 20, "Opt");
				mvwaddstr(all_win->status_win, 2, matrixx0 + 24, "Level");

				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_GREEN));

				for(counter = 0; counter < snap_all[cur_card].no_lg_drv;
				counter++){
					offset = rindex(snap_all[cur_card].lg_drv[counter].dev_name, '/');
					offset++;

					if(counter == 16){
					   	matrixx0 = mid;
					   	matrixx0++;
						matrixy0 = 4;

						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_CYAN));

						mvwaddstr(all_win->status_win, 2, matrixx0, "DEV");
						mvwaddstr(all_win->status_win, 2, matrixx0 + 6, "STAT");
						mvwaddstr(all_win->status_win, 2, matrixx0 + 13, "Size");
						mvwaddstr(all_win->status_win, 2, matrixx0 + 20, "Opt");
						mvwaddstr(all_win->status_win, 2, matrixx0 + 24, "Level");
						
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_GREEN));
					}
						
					if((snap_all[cur_card].lg_drv[counter].focus) &&
							(lock == LOCK_DEV)){
							wattrset(all_win->status_win, CARDLIST_NOFOCUS);
							mvwhline(all_win->status_win, matrixy0, matrixx0,
							' ', 30);
					}else if(snap_all[cur_card].lg_drv[counter].state[1] == 'F')
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_RED));
					else if(snap_all[cur_card].lg_drv[counter].state[1] == 'N')
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_GREEN));
					else
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_YELLOW));

					mvwaddstr(all_win->status_win,
					matrixy0, matrixx0 + 6,
				   	snap_all[cur_card].lg_drv[counter].state);

					df_size = atol(snap_all[cur_card].lg_drv[counter].blocks);
					sprintf(ds_size, "%.1fGB", ((df_size*512)/(float)1073741824));

					mvwaddstr(all_win->status_win,
					matrixy0, matrixx0 + 12,
				   	ds_size);

					mvwaddstr(all_win->status_win,
					matrixy0, matrixx0 + 20,
				   	snap_all[cur_card].lg_drv[counter].wrt_opt);

					mvwaddstr(all_win->status_win,
					matrixy0, matrixx0 + 23,
				   	snap_all[cur_card].lg_drv[counter].raid_l);

					mvwaddstr(all_win->status_win,
					matrixy0++, matrixx0,
				   	offset);


				}

/*				Display all the white characters
*/   
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_WHITE));

				mvwhline(all_win->status_win, 3, 1,
				ACS_HLINE, (maxx-1));
				
				mvwaddch(all_win->status_win,
				3, 0, ACS_LTEE);

				mvwaddch(all_win->status_win,
				3, maxx, ACS_RTEE);
				
				mvwaddch(all_win->status_win,
				3, mid, ACS_TTEE);

				mvwaddch(all_win->status_win,
				maxy, mid, ACS_BTEE);


				mvwvline(all_win->status_win, 4, mid,
				ACS_VLINE, (maxy-4));

			}

/*			Does this tab have focus?
*/
			if(tab_pool[3].focus){
				int matrixx = 2, matrixy = 3;
				int i;
				
				wattrset(all_win->status_win,
				A_BOLD|COLOR_PAIR(BLUE_WHITE));

				mvwaddch(all_win->status_win,
				2, 0, ACS_LTEE);

				mvwaddch(all_win->status_win,
				2, maxx, ACS_RTEE);

				mvwhline(all_win->status_win, 2, 1,
				ACS_HLINE, (maxx-1));

				mvwaddch(all_win->status_win,
				2, 14, ACS_TTEE);
				
				
				mvwaddch(all_win->status_win,
				10, 0, ACS_LTEE);

				mvwaddch(all_win->status_win,
				10, maxx, ACS_RTEE);

				mvwhline(all_win->status_win, 10, 1,
				ACS_HLINE, (maxx-1));

				mvwaddch(all_win->status_win,
				10, 14, ACS_BTEE);

				mvwvline(all_win->status_win, 3, 14,
				ACS_VLINE, 7);
				
				matrixx = 30;
				matrixy = 2;

				mvwaddstr(all_win->status_win,
				matrixy, matrixx, "Description");

				matrixx = 2;

				mvwaddstr(all_win->status_win,
				matrixy, matrixx, "Commands");

				mvwaddstr(all_win->status_win,
				matrixy, matrixx, "Commands");

				mvwaddch(all_win->status_win,
				12, 5, ACS_ULCORNER);
				
				mvwaddch(all_win->status_win,
				12, 58, ACS_URCORNER);

				mvwhline(all_win->status_win, 12, 6,
				ACS_HLINE, 52);

				mvwvline(all_win->status_win, 13, 5,
				ACS_VLINE, 4);
				
				mvwhline(all_win->status_win, 14, 7,
				ACS_CKBOARD, 50);
				
				mvwhline(all_win->status_win, 15, 7,
				ACS_CKBOARD, 50);

				mvwvline(all_win->status_win, 13, 58,
				ACS_VLINE, 4);
				
				mvwhline(all_win->status_win, 17, 6,
				ACS_HLINE, 52);

				mvwaddch(all_win->status_win,
				17, 5, ACS_LLCORNER);
				
				mvwaddch(all_win->status_win,
				17, 58, ACS_LRCORNER);

				if(!snap_all[cur_card].rebuild){
					mvwaddstr(all_win->status_win,
					12, 11, "No Rebuild or Consistency Check in Progress");
				}else{
					char put_line[80];
					int percent;
					percent = atoi(snap_all[cur_card].rb_done);
					percent /= 2;
					
					wattrset(all_win->status_win,
					A_REVERSE|COLOR_PAIR(CYAN_GREEN));
					mvwhline(all_win->status_win, 14, 7,
					' ', percent);
				
					mvwhline(all_win->status_win, 15, 7,
					' ', percent);
					
					wattrset(all_win->status_win,
					A_BOLD|COLOR_PAIR(BLUE_WHITE));

					if(snap_all[cur_card].rebuild == REBUILD){
						sprintf(put_line, "Drive (%s) is being rebuilt.",
						snap_all[cur_card].rb_dev);
					}else{
						sprintf(put_line, "Checking Consistency on (%s).",
						snap_all[cur_card].rb_dev);
					}


					mvwaddstr(all_win->status_win,
					13, 13, put_line);
					
					sprintf(put_line, "%s%% is done.",
							snap_all[cur_card].rb_done);

					mvwaddstr(all_win->status_win,
					16, 26, put_line);
				}

				matrixy = 3;

/*				Display all the cyan characters
*/ 
				wattrset(all_win->status_win,
				A_DIM|COLOR_PAIR(BLUE_CYAN));

				for(i = 0; i < 6; i++){
					if((lock == LOCK_CARDS) && cmd[i].focus){
						wattrset(all_win->status_win,
						CARDLIST_NOFOCUS);
						mvwhline(all_win->status_win, matrixy, 2,
						' ', 11);
						
						mvwaddstr(all_win->status_win,
						matrixy++, matrixx, cmd[i].name);
						
						wattrset(all_win->status_win,
						COLOR_PAIR(BLUE_WHITE));

						if(i == 0){
							mvwaddstr(all_win->status_win,
							3, 16, "This command kills physical device(s) in the");
							
							mvwaddstr(all_win->status_win,
							4, 16, "chain.");
							
							mvwaddstr(all_win->status_win,
							6, 16, "Caution: device(s) you select will be marked");
							
							mvwaddstr(all_win->status_win,
							7, 16, "as DED, press ENTER to get into device");
							
							mvwaddstr(all_win->status_win,
							8, 16, "selection or ESC to exit from Command mode.");
							
						}else if(i == 1){
							
							mvwaddstr(all_win->status_win,
							3, 16, "This command forces physical device(s) in the");
							
							mvwaddstr(all_win->status_win,
							4, 16, "chain to become Online.");
							
							mvwaddstr(all_win->status_win,
							6, 16, "Caution: device(s) you select will be marked");
							
							mvwaddstr(all_win->status_win,
							7, 16, "as ONL, press ENTER to get into device");
							
							mvwaddstr(all_win->status_win,
							8, 16, "selection or ESC to exit from Command mode.");

						}else if(i == 2){

							mvwaddstr(all_win->status_win,
							3, 16, "This command forces physical device(s) in the");
							
							mvwaddstr(all_win->status_win,
							4, 16, "chain to become Standby.");
							
							mvwaddstr(all_win->status_win,
							6, 16, "Caution: device(s) you select will be marked");
							
							mvwaddstr(all_win->status_win,
							7, 16, "as SBY, press ENTER to get into device");
							
							mvwaddstr(all_win->status_win,
							8, 16, "selection or ESC to exit from Command mode.");
							
						}else if(i == 3){

							mvwaddstr(all_win->status_win,
							3, 16, "This command initializes an asynchronous");
							
							mvwaddstr(all_win->status_win,
							4, 16, "rebuild on to a selected physical device.");
							
							mvwaddstr(all_win->status_win,
							6, 16, "Press ENTER to get into device selection or");
							
							mvwaddstr(all_win->status_win,
							7, 16, "ESC to exit from Command mode.");
							
						}else if(i == 4){

							mvwaddstr(all_win->status_win,
							3, 16, "This command initializes an asynchronous");
							
							mvwaddstr(all_win->status_win,
							4, 16, "process where the integrity of redundant data");
							
							mvwaddstr(all_win->status_win,
							5, 16, "on a selected RAID array is verified.");
							
							mvwaddstr(all_win->status_win,
							7, 16, "Press ENTER to get into array selection or");
							
							mvwaddstr(all_win->status_win,
							8, 16, "ESC to exit from Command mode.");

							
						}else if(i == 5){
							
							mvwaddstr(all_win->status_win,
							3, 16, "This command cancels any rebuild or");
							
							mvwaddstr(all_win->status_win,
							4, 16, "consistency check in progress.");
							
							mvwaddstr(all_win->status_win,
							6, 16, "Press ENTER to cancel activity or ESC to exit");
							
							mvwaddstr(all_win->status_win,
							7, 16, "from Command mode.");
						}else if(i == 6){
							
							mvwaddstr(all_win->status_win,
							4, 16, "Press ENTER to cancel any consistency check in");
							
							mvwaddstr(all_win->status_win,
							5, 16, "progress, or press ESC to exit Expert Mode.");
							
						}

					}else if((lock == LOCK_CARDS)&& !cmd[i].focus){
						wattrset(all_win->status_win,
						A_BOLD|COLOR_PAIR(BLUE_CYAN));
						
						mvwaddstr(all_win->status_win,
						matrixy++, matrixx, cmd[i].name);
					}else{
						wattrset(all_win->status_win,
						A_DIM|COLOR_PAIR(BLUE_CYAN));
						
						mvwaddstr(all_win->status_win,
						matrixy++, matrixx, cmd[i].name);
					}

				}

/*				Display all the yellow characters
*/   
				if(lock == NO_LOCK){
					wattrset(all_win->status_win,
					COLOR_PAIR(BLUE_WHITE));

					mvwaddstr(all_win->status_win,
					4, 17, "The \"Expert\" tab allows you to manipulate");
				
					mvwaddstr(all_win->status_win,
					5, 17, "current RAID status. Use UP/DOWN arrows to");
				
					mvwaddstr(all_win->status_win,
					6, 17, "select a card than press ENTER to lock the");
					
					mvwaddstr(all_win->status_win,
					7, 17, "selected card.");
				}
				
			}	

		}	
	}	
	return 1;	
}
	
/*
--------------------------------------------------------------------------------
	Interact with user*/
void mv_fc(SWINDOWS *all_win, CARD *card_pool, TAB *tab_pool, int key_press, int no_cards){
	int dummy = 0, x = 0, card_focus = 0, tab_focus = 0;
	int dummy1 = 0;
        size_t dummy2 = 0;
	char line[80];
	
	if(key_press != KEY_INIT){
		for(;dummy < no_cards; dummy++)
			if(card_pool[dummy].focus) card_focus = dummy;
		dummy = 0;
		for(;dummy < NO_TABS; dummy++)
			if(tab_pool[dummy].focus) tab_focus = dummy;

	}
	
	dummy = 0;
	switch (key_press){
		case KEY_INIT:
			for(;dummy < no_pages; dummy++){
				if(card_pool[dummy].focus){

	            	if(lock) wattrset(all_win->cardlist, CARDLIST_LOCKED);
					else if(!snap_all[dummy].got_dead)
						wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_GREEN));
					else if(snap_all[dummy].got_dead == 1)
						wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_YELLOW));
					else if(snap_all[dummy].got_dead == 2)
						wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_RED));
					
					strcpy(line, snap_all[dummy].c_type);
					if(snap_all[dummy].got_dead)
						strcat(line, "*");
					else
						strcat(line, " ");
					strcat(line, snap_all[dummy].chnl);
					strcat(line, "C");

				    mvwaddstr(all_win->cardlist,
					card_pool[dummy].y, card_pool[dummy].x,
					line);
					
				} else {
					if(!snap_all[dummy].got_dead)
						wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_GREEN));
					else if(snap_all[dummy].got_dead == 1)
						wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_YELLOW));
					else if(snap_all[dummy].got_dead == 2)
						wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_RED));
						
/*					wattrset(all_win->cardlist, CARDLIST_NOFOCUS);*/
					strcpy(line, snap_all[dummy].c_type);
					if(snap_all[dummy].got_dead)
						strcat(line, "*");
					else
						strcat(line, " ");
					strcat(line, snap_all[dummy].chnl);
					strcat(line, "C");

				    mvwaddstr(all_win->cardlist,
					card_pool[dummy].y, card_pool[dummy].x,
					line);
					
				}
			}
			
           	if(lock)wattrset(all_win->cardlist, CARDLIST_LOCKED);
			else wattrset(all_win->cardlist, CARDLIST_NOFOCUS);

			box(all_win->cardlist,0,0);
		    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");

			dummy = 0;
			wmove(all_win->status_win, 0,0);
			wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));
			box(all_win->status_win, 0,0);
			for(;dummy < NO_TABS; dummy++){

				if(!tab_pool[dummy].focus){
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_YELLOW)); 
					waddch(all_win->status_win, ' ');
					waddstr(all_win->status_win, tab_pool[dummy].label);
					waddch(all_win->status_win, ' ');
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));


				}else{
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));
					waddch(all_win->status_win, tab_pool[dummy].lpad);
					waddstr(all_win->status_win, tab_pool[dummy].label);
					waddch(all_win->status_win, tab_pool[dummy].rpad);
				}
				for(dummy1 = 0; dummy1 < tab_pool[dummy].x; dummy1++) waddch(all_win->status_win, ' ');
				x += (2+strlen(tab_pool[dummy].label)+tab_pool[dummy].x);
			}
			
			whline(all_win->status_win, ' ', (all_win->status_win->_maxx-x)+1);


			dummy = 0;
			x = 0;
			wmove(all_win->status_win, 1,0);
			for(;dummy < NO_TABS; dummy++){
				if(!tab_pool[dummy].focus){
					if(dummy == 0)
						waddch(all_win->status_win, ACS_ULCORNER);
					else
						waddch(all_win->status_win, ACS_HLINE);

					for(dummy2 = 0; dummy2 < strlen(tab_pool[dummy].label); dummy2++) waddch(all_win->status_win, ACS_HLINE);
					waddch(all_win->status_win, ACS_HLINE);
				}else {
					waddch(all_win->status_win, tab_pool[dummy].llpad);
					for(dummy2 = 0; dummy2 < strlen(tab_pool[dummy].label); dummy2++) waddch(all_win->status_win, ' ');
					waddch(all_win->status_win, tab_pool[dummy].lrpad);
				}
				for(dummy1 = 0; dummy1 < tab_pool[dummy].x; dummy1++) waddch(all_win->status_win, ACS_HLINE);
				x += (2+strlen(tab_pool[dummy].label)+tab_pool[dummy].x);
			}
			whline(all_win->status_win, ACS_HLINE, (all_win->status_win->_maxx-x));
			mvwaddch(all_win->status_win, 1, all_win->status_win->_maxx, ACS_URCORNER);
			
			get_stat(all_win, card_pool, tab_pool);
			
			wrefresh(all_win->cardlist);
			wrefresh(all_win->status_win);
			move(0,0);
			
			refresh();

		break;

		case KEY_DOWN:
			if(lock == LOCK_CARDS){
				int i;
				for(i = 0; i < 6; i++){
					if(cmd[i].focus){
						cmd[i].focus = 0;
						if((i+1) == 6)
							cmd[0].focus = '0';
						else
							cmd[(i+1)].focus = '0';
						break;
					}
				}

				get_stat(all_win, card_pool, tab_pool);
				wrefresh(all_win->status_win);
				refresh();
				break;
			}
			
			if(lock == LOCK_CMD){
				int i;
				for(i = 0; i < snap_all[card_focus].no_ph_dev; i++)
					if(snap_all[card_focus].ph_dev[i].focus){
						if((i+1) == snap_all[card_focus].no_ph_dev){
							snap_all[card_focus].ph_dev[0].focus = '0';
							snap_all[card_focus].ph_dev[i].focus = 0;
							break;
						}else{
						   	snap_all[card_focus].ph_dev[(i+1)].focus = '0';
						   	snap_all[card_focus].ph_dev[i].focus = 0;
							break;
						}
					}
				get_stat(all_win, card_pool, tab_pool);
				wrefresh(all_win->status_win);
				refresh();
				break;
			}
			
			
			if(lock == LOCK_DEV){
				int i;
				for(i = 0; i < snap_all[card_focus].no_lg_drv; i++)
					if(snap_all[card_focus].lg_drv[i].focus){
						if((i+1) == snap_all[card_focus].no_lg_drv){
							if(i){
								snap_all[card_focus].lg_drv[0].focus = '0';
								snap_all[card_focus].lg_drv[i].focus = 0;
							}
							break;
						}else{
						   	snap_all[card_focus].lg_drv[(i+1)].focus = '0';
						   	snap_all[card_focus].lg_drv[i].focus = 0;
							break;
						}
					}
				get_stat(all_win, card_pool, tab_pool);
				wrefresh(all_win->status_win);
				refresh();
				break;
			}


			if(no_cards == 1) break;
			card_pool[card_focus].focus = 0;
			wattrset(all_win->cardlist, CARDLIST_NOFOCUS);
			
			

			strcpy(line, snap_all[card_focus].c_type);
			if(snap_all[card_focus].got_dead)
				strcat(line, "*");
			else
				strcat(line, " ");
			strcat(line, snap_all[card_focus].chnl);
			strcat(line, "C");


			box(all_win->cardlist,0,0);
		    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");

			if(!snap_all[card_focus].got_dead)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_GREEN));
			else if(snap_all[card_focus].got_dead == 1)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_YELLOW));
			else if(snap_all[card_focus].got_dead == 2)
					wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_RED));

		    mvwaddstr(all_win->cardlist, card_pool[card_focus].y,
			card_pool[card_focus].x, line);

			if((card_focus+1) == no_cards) card_focus = 0;
			else card_focus++;

			card_pool[card_focus].focus = '0' ;
			
		        
			if(!snap_all[card_focus].got_dead)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_GREEN));
			else if(snap_all[card_focus].got_dead == 1)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_YELLOW));
			else if(snap_all[card_focus].got_dead == 2)
					wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_RED));

			strcpy(line, snap_all[card_focus].c_type);
			if(snap_all[card_focus].got_dead)
				strcat(line, "*");
			else
				strcat(line, " ");
			strcat(line, snap_all[card_focus].chnl);
			strcat(line, "C");
			
			mvwaddstr(all_win->cardlist, card_pool[card_focus].y,
			card_pool[card_focus].x, line);
		        
			wattrset(all_win->cardlist, CARDLIST_NOFOCUS);

			get_stat(all_win, card_pool, tab_pool);

			wrefresh(all_win->status_win);
			
			wrefresh(all_win->cardlist);
			refresh();
		break;

		case KEY_UP:
			if(lock == LOCK_CARDS){
				int i;
				for(i = 5; i > -1; i--){
					if(cmd[i].focus){
						cmd[i].focus = 0;
						if((i-1) == -1)
							cmd[5].focus = '0';
						else
							cmd[(i-1)].focus = '0';
						break;
					}
				}

				get_stat(all_win, card_pool, tab_pool);
				wrefresh(all_win->status_win);
				refresh();
				break;
			}

			if(lock == LOCK_CMD){
				int i, no_drv;

				i = snap_all[card_focus].no_ph_dev;
				i--;
				no_drv = i;

				for(; i > -1; i--)
					if(snap_all[card_focus].ph_dev[i].focus){
						if((i-1) == -1){
							snap_all[card_focus].ph_dev[no_drv].focus = '0';
							snap_all[card_focus].ph_dev[i].focus = 0;
							break;
						}else{
						   	snap_all[card_focus].ph_dev[(i-1)].focus = '0';
						   	snap_all[card_focus].ph_dev[i].focus = 0;
							break;
						}
					}
				get_stat(all_win, card_pool, tab_pool);
				wrefresh(all_win->status_win);
				refresh();
				break;
			}
			
			if(lock == LOCK_DEV){
				int i, no_dev;

				i = snap_all[card_focus].no_lg_drv;
				i--;
				no_dev = i;

				for(; i > -1; i--)
					if(snap_all[card_focus].lg_drv[i].focus){
						if(((i-1) == -1)){
							if(no_dev){
								snap_all[card_focus].lg_drv[no_dev].focus = '0';
								snap_all[card_focus].lg_drv[i].focus = 0;
							}
							break;
						}else{
						   	snap_all[card_focus].lg_drv[(i-1)].focus = '0';
						   	snap_all[card_focus].lg_drv[i].focus = 0;
							break;
						}
					}
				get_stat(all_win, card_pool, tab_pool);
				wrefresh(all_win->status_win);
				refresh();
				break;
			}
			
			

			if(no_cards ==  1) break;
			card_pool[card_focus].focus = 0;
			wattrset(all_win->cardlist, CARDLIST_NOFOCUS);

			box(all_win->cardlist,0,0);
		    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");

			if(!snap_all[card_focus].got_dead)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_GREEN));
			else if(snap_all[card_focus].got_dead == 1)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_YELLOW));
			else if(snap_all[card_focus].got_dead == 2)
					wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(CYAN_RED));

			strcpy(line, snap_all[card_focus].c_type);
			if(snap_all[card_focus].got_dead)
				strcat(line, "*");
			else
				strcat(line, " ");
			strcat(line, snap_all[card_focus].chnl);
			strcat(line, "C");
			
			mvwaddstr(all_win->cardlist, card_pool[card_focus].y,
			card_pool[card_focus].x, line);

			wattrset(all_win->cardlist, CARDLIST_FOCUS);
			if(!card_focus) card_focus = (no_cards-1); else card_focus--;

			card_pool[card_focus].focus = '0' ;

			if(!snap_all[card_focus].got_dead)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_GREEN));
			else if(snap_all[card_focus].got_dead == 1)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_YELLOW));
			else if(snap_all[card_focus].got_dead == 2)
					wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_RED));

			strcpy(line, snap_all[card_focus].c_type);
			if(snap_all[card_focus].got_dead)
				strcat(line, "*");
			else
				strcat(line, " ");
			strcat(line, snap_all[card_focus].chnl);
			strcat(line, "C");
			
			mvwaddstr(all_win->cardlist, card_pool[card_focus].y,
			card_pool[card_focus].x, line);
			
			wattrset(all_win->cardlist, CARDLIST_NOFOCUS);

			get_stat(all_win, card_pool, tab_pool);

			wrefresh(all_win->status_win);
			
			
			wrefresh(all_win->cardlist);
			refresh();
		break;

		case KEY_ESCPE:
			if(lock == LOCK_CMD || lock == LOCK_DEV) {
				int i;
				lock = NO_LOCK;
				for(i = 0; i < 4; i++)
					tab_pool[i].focus = 0;
				tab_pool[3].focus = '0';
				mv_fc(all_win, card_pool, tab_pool, KEY_INIT, no_pages);
				return;;
			}
			if(lock == LOCK_CARDS) lock = NO_LOCK;
            wattrset(all_win->cardlist, CARDLIST_NOFOCUS); 
			box(all_win->cardlist,0,0);
		    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");

			strcpy(line, snap_all[card_focus].c_type);
			if(snap_all[card_focus].got_dead)
				strcat(line, "*");
			else
				strcat(line, " ");
			strcat(line, snap_all[card_focus].chnl);
			strcat(line, "C");
			
/*            wattrset(all_win->cardlist, CARDLIST_FOCUS); */

			if(!snap_all[card_focus].got_dead)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_GREEN));
			else if(snap_all[card_focus].got_dead == 1)
				wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_YELLOW));
			else if(snap_all[card_focus].got_dead == 2)
					wattrset(all_win->cardlist, A_BOLD|COLOR_PAIR(BLUE_RED));
					
			mvwaddstr(all_win->cardlist, card_pool[card_focus].y,
			card_pool[card_focus].x, line);
			get_stat(all_win, card_pool, tab_pool);
			wrefresh(all_win->status_win);
			wrefresh(all_win->cardlist);

		break;

		case KEY_RETURN:
		case KEY_RETURN1:
			if(lock == LOCK_CARDS){
				int i;
				
				for(i = 0; i < snap_all[card_focus].no_ph_dev; i++){
					snap_all[card_focus].ph_dev[i].focus = 0;
				}
				for(i = 0; i < snap_all[card_focus].no_lg_drv; i++){
					snap_all[card_focus].lg_drv[i].focus = 0;
				}
				snap_all[card_focus].ph_dev[0].focus = '0';
				snap_all[card_focus].lg_drv[0].focus = '0';
				
				for(i = 0; i < 4; i++)
					tab_pool[i].focus = 0;
				if(cmd[4].focus){
					lock = LOCK_DEV;
				}else if(cmd[5].focus){
					char msg[200], path[200], *tmp;
					tab_pool[3].focus = '0';
					strcpy(msg, "cancel-rebuild");
					strcpy(path, snap_all[card_focus].card_path);
					tmp = rindex(path, '/');
					tmp++;
					*tmp = 0;
					strcat(path, "user_command");
					command(path, msg);
				/*}else if(cmd[6].focus){
					char msg[200], path[200], *tmp;
					tab_pool[3].focus = '0';
					strcpy(msg, "cancel-consistency-check");
					strcpy(path, snap_all[card_focus].card_path);
					tmp = rindex(path, '/');
					tmp++;
					*tmp = 0;
					strcat(path, "user_command");
					command(path, msg);*/
				}else{
					tab_pool[2].focus = '0';
					lock = LOCK_CMD;
				}
				
				mv_fc(all_win, card_pool, tab_pool, KEY_LEFT, no_pages);
				
				return;
			}

			if(lock == LOCK_CMD){
				char msg[200], path[200], *tmp;
				int i, j;

				for(i = 0; i < 6; i++){
					if(cmd[i].focus)
						break;
				}

				for(j = 0; j < snap_all[card_focus].no_ph_dev; j++){
					if(snap_all[card_focus].ph_dev[j].focus)
						break;
				}
				
				if(i == 0){
					sprintf(msg, "kill %s", snap_all[card_focus].ph_dev[j].target);
				}else if(i == 1){
					sprintf(msg, "make-online %s", snap_all[card_focus].ph_dev[j].target);
				}else if(i == 2){
					sprintf(msg, "make-standby %s", snap_all[card_focus].ph_dev[j].target);
				}else if(i == 3){
					sprintf(msg, "rebuild %s", snap_all[card_focus].ph_dev[j].target);
				}
				strcpy(path, snap_all[card_focus].card_path);
				tmp = rindex(path, '/');
				tmp++;
				*tmp = 0;
				strcat(path, "user_command");
				command(path, msg);
	
			}
				
			if(lock == LOCK_DEV){
				char msg[200], path[200], *tmp;
				int i, j;

				for(i = 0; i < 6; i++){
					if(cmd[i].focus)
						break;
				}

				for(j = 0; j < snap_all[card_focus].no_lg_drv; j++){
					if(snap_all[card_focus].lg_drv[j].focus)
						break;
				}
			
				if(i == 4){
					char *offset;
					offset = strstr(snap_all[card_focus].lg_drv[j].dev_name, "/c");
					offset +=4;
					sprintf(msg, "check-consistency %s", offset);
				}
				
				strcpy(path, snap_all[card_focus].card_path);
				tmp = rindex(path, '/');
				tmp++;
				*tmp = 0;
				strcat(path, "user_command");
				command(path, msg);
			}

			if(tab_pool[3].focus){
				int i;
	            wattrset(all_win->cardlist, CARDLIST_LOCKED);
				box(all_win->cardlist,0,0);
			    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");

				strcpy(line, snap_all[card_focus].c_type);
				if(snap_all[card_focus].got_dead)
					strcat(line, "*");
				else
					strcat(line, " ");
				strcat(line, snap_all[card_focus].chnl);
				strcat(line, "C");
			
				mvwaddstr(all_win->cardlist, card_pool[card_focus].y,
				card_pool[card_focus].x, line);

				lock = LOCK_CARDS;
				for(i = 0; i < 6; i++)
					cmd[i].focus = 0;
				cmd[0].focus = '0';

				get_stat(all_win, card_pool, tab_pool);
				
	            wattrset(all_win->cardlist, CARDLIST_NOFOCUS); 
				wrefresh(all_win->cardlist);
				wrefresh(all_win->status_win);
				refresh();
			}
		break;

		case KEY_RIGHT:
			if(lock == LOCK_CARDS) break;
			if(lock == NO_LOCK){
				wattrset(all_win->cardlist, CARDLIST_NOFOCUS);
				box(all_win->cardlist,0,0);
			    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");
			}

			wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE)); 
			box(all_win->status_win, 0, 0);
			
			if(lock == LOCK_CMD){
				tab_pool[tab_focus].focus = 0;
				tab_pool[1].focus = '0';
			}else if(lock == LOCK_DEV){
				tab_pool[tab_focus].focus = 0;
				tab_pool[2].focus = '0';
			}else {
				tab_pool[tab_focus].focus = 0;
				if((tab_focus+1) == NO_TABS) tab_focus = 0; else tab_focus++;
				tab_pool[tab_focus].focus = '0';
			}

			dummy = 0;
			wmove(all_win->status_win, 0,0);
			for(;dummy < NO_TABS; dummy++){

				if(!tab_pool[dummy].focus){
					wattrset(all_win->status_win, COLOR_PAIR(BLUE_BLACK)); 
					waddch(all_win->status_win, ' ');
					waddstr(all_win->status_win, tab_pool[dummy].label);
					waddch(all_win->status_win, ' ');
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));


				}else{
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));
					waddch(all_win->status_win, tab_pool[dummy].lpad);
					waddstr(all_win->status_win, tab_pool[dummy].label);
					waddch(all_win->status_win, tab_pool[dummy].rpad);
				}
				for(dummy1 = 0; dummy1 < tab_pool[dummy].x; dummy1++) waddch(all_win->status_win, ' ');
				x += (2+strlen(tab_pool[dummy].label)+tab_pool[dummy].x);
			}
			whline(all_win->status_win, ' ', (all_win->status_win->_maxx-x)+1);
			dummy = 0;
			x = 0;
			wmove(all_win->status_win, 1,0);
			for(;dummy < NO_TABS; dummy++){
				if(!tab_pool[dummy].focus){
					if(dummy) waddch(all_win->status_win, ACS_HLINE);
					else waddch(all_win->status_win, ACS_ULCORNER);
					for(dummy2 = 0; dummy2 < strlen(tab_pool[dummy].label); dummy2++) waddch(all_win->status_win, ACS_HLINE);
					waddch(all_win->status_win, ACS_HLINE);
				}else {
					waddch(all_win->status_win, tab_pool[dummy].llpad);
					for(dummy2 = 0; dummy2 < strlen(tab_pool[dummy].label); dummy2++) waddch(all_win->status_win, ' ');
					waddch(all_win->status_win, tab_pool[dummy].lrpad);
				}
				for(dummy1 = 0; dummy1 < tab_pool[dummy].x; dummy1++) waddch(all_win->status_win, ACS_HLINE);
				x += (2+strlen(tab_pool[dummy].label)+tab_pool[dummy].x);
			}
			whline(all_win->status_win, ACS_HLINE, (all_win->status_win->_maxx-x));
			mvwaddch(all_win->status_win, 1, all_win->status_win->_maxx, ACS_URCORNER);
			dummy = 0;
			
			get_stat(all_win, card_pool, tab_pool);
			
			wrefresh(all_win->status_win);
			wrefresh(all_win->cardlist);
			refresh();
		break;

		case KEY_LEFT:
			if(lock == LOCK_CARDS) break;
			if(lock == NO_LOCK){
				wattrset(all_win->cardlist, CARDLIST_NOFOCUS);
				box(all_win->cardlist,0,0);
			    mvwaddstr(all_win->cardlist, 0,1, "Detected cards");
			}

			wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE)); 
			box(all_win->status_win, 0, 0);
			

			if(lock == LOCK_CMD){
				tab_pool[tab_focus].focus = 0;
				tab_pool[1].focus = '0';
			}else if(lock == LOCK_DEV){
				tab_pool[tab_focus].focus = 0;
				tab_pool[2].focus = '0';
			}else {
				tab_pool[tab_focus].focus = 0;
				if(!tab_focus) tab_focus = (NO_TABS-1); else tab_focus--;
				tab_pool[tab_focus].focus = '0';
			}
			
			
			dummy = 0;
			wmove(all_win->status_win, 0,0);
			for(;dummy < NO_TABS; dummy++){

				if(!tab_pool[dummy].focus){
					wattrset(all_win->status_win, COLOR_PAIR(BLUE_BLACK)); 
					waddch(all_win->status_win, ' ');
					waddstr(all_win->status_win, tab_pool[dummy].label);
					waddch(all_win->status_win, ' ');
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));


				}else{
					wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));
					waddch(all_win->status_win, tab_pool[dummy].lpad);
					waddstr(all_win->status_win, tab_pool[dummy].label);
					waddch(all_win->status_win, tab_pool[dummy].rpad);
				}
				for(dummy1 = 0; dummy1 < tab_pool[dummy].x; dummy1++) waddch(all_win->status_win, ' ');
				x += (2+strlen(tab_pool[dummy].label)+tab_pool[dummy].x);
			}
			whline(all_win->status_win, ' ', (all_win->status_win->_maxx-x)+1);

			dummy = 0;
			x = 0;
			wmove(all_win->status_win, 1,0);
			for(;dummy < NO_TABS; dummy++){
				if(!tab_pool[dummy].focus){
					if(dummy) waddch(all_win->status_win, ACS_HLINE);
					else waddch(all_win->status_win, ACS_ULCORNER);
					for(dummy2 = 0; dummy2 < strlen(tab_pool[dummy].label); dummy2++) waddch(all_win->status_win, ACS_HLINE);
					waddch(all_win->status_win, ACS_HLINE);
				}else {
					waddch(all_win->status_win, tab_pool[dummy].llpad);
					for(dummy2 = 0; dummy2 < strlen(tab_pool[dummy].label); dummy2++) waddch(all_win->status_win, ' ');
					waddch(all_win->status_win, tab_pool[dummy].lrpad);
				}
				for(dummy1 = 0; dummy1 < tab_pool[dummy].x; dummy1++) waddch(all_win->status_win, ACS_HLINE);
				x += (2+strlen(tab_pool[dummy].label)+tab_pool[dummy].x);
			}
			whline(all_win->status_win, ACS_HLINE, (all_win->status_win->_maxx-x));
			mvwaddch(all_win->status_win, 1, all_win->status_win->_maxx, ACS_URCORNER);

			get_stat(all_win, card_pool, tab_pool);

			wrefresh(all_win->status_win);
			wrefresh(all_win->cardlist);
			refresh();
		break;


	}
}

/*
--------------------------------------------------------------------------------
	Build the card pool from the extracted information*/
void init_matrix(CARD *card_pool, TAB *tab_pool, int no_cards){
	int dummy = 0, pad_x = 2, pad_y = 2;

	for(;dummy < no_cards; dummy++){
		card_pool[dummy].x = pad_x;
		card_pool[dummy].y = pad_y;
		pad_y += 2;
	}
	dummy = 0;
	for(;dummy < NO_TABS; dummy++){
		tab_pool[dummy].x = 3;
	}
}

int init_card_pool(CARD *card_pool, TAB *tab_pool, int no_cards){
	card_pool[0].focus = '0';
	init_matrix(card_pool, tab_pool, no_cards);
return 1;
}

void init_tab_pool(CARD *card_pool, TAB *tab_pool, int no_cards){
	int dummy = 0;
	
	for(;dummy < NO_TABS; dummy++){
		if(dummy == 0){
			strcpy(tab_pool[dummy].label, "Status");
			tab_pool[dummy].focus = '0';
			tab_pool[dummy].lpad = ACS_ULCORNER;
			tab_pool[dummy].rpad = ACS_URCORNER;
			tab_pool[dummy].llpad = ACS_VLINE;
			tab_pool[dummy].lrpad = ACS_LLCORNER;
		}
		
		if(dummy == 1){
			strcpy(tab_pool[dummy].label, "Devices");
			tab_pool[dummy].focus = 0;
			tab_pool[dummy].lpad = ACS_ULCORNER;
			tab_pool[dummy].rpad = ACS_URCORNER;
			tab_pool[dummy].llpad = ACS_LRCORNER;
			tab_pool[dummy].lrpad = ACS_LLCORNER;
		}

		if(dummy == 2){
			strcpy(tab_pool[dummy].label, "Arrays");
			tab_pool[dummy].focus = 0;
			tab_pool[dummy].lpad = ACS_ULCORNER;
			tab_pool[dummy].rpad = ACS_URCORNER;
			tab_pool[dummy].llpad = ACS_LRCORNER;
			tab_pool[dummy].lrpad = ACS_LLCORNER;
		}

		if(dummy == 3){
			strcpy(tab_pool[dummy].label, "Expert");
			tab_pool[dummy].focus = 0;
			tab_pool[dummy].lpad = ACS_ULCORNER;
			tab_pool[dummy].rpad = ACS_URCORNER;
			tab_pool[dummy].llpad = ACS_LRCORNER;
			tab_pool[dummy].lrpad = ACS_LLCORNER;
		}

	}
	init_matrix(card_pool, tab_pool, no_cards);
}


/*
--------------------------------------------------------------------------------
	Trash UI at the end or in case of failure*/
void trash_UI(SWINDOWS *all_win, int fail_stat){
   
  switch(fail_stat)
  {
  case STATUS_WIN_FAIL:
	goto status_fail;
  case CARDLIST_FAIL:
	goto cardlist_fail;
  case TITLE_FAIL:
	goto title_fail;
  case BOTTOM_FAIL:
			goto bottom_fail;
  case TRASH_ALL:
	goto trash_all;
  case INIT_CARD_FAIL:
	printf("\nDriver not compatible.\n");
	goto init_card_fail;
  }
  
 trash_all:
  werase(all_win->status_win);
  delwin(all_win->status_win);
 status_fail:
  werase(all_win->cardlist);
  delwin(all_win->cardlist);
 cardlist_fail:
  werase(all_win->title);
  delwin(all_win->title);
 title_fail:
  werase(all_win->bottom);
  delwin(all_win->bottom);
 bottom_fail:
  werase(all_win->root);
  refresh();
  delwin(all_win->root);
  endwin();
 init_card_fail:
  return;
}

/*
--------------------------------------------------------------------------------
	Build the user interface */
int build_UI(SWINDOWS *all_win, CARD *card_pool, TAB *tab_pool, int no_cards){
	int dummy, fail_stat = 0;

	if(!(init_card_pool(card_pool, tab_pool, no_cards))) {
		fail_stat = INIT_CARD_FAIL;
		goto hyper;
	}

    all_win->root = initscr();
	if(LINES < 25 || COLS < 80){
		fprintf(stderr, "Terminal size = %dx%d. Please resize your window to atleast 80x25.", COLS, LINES);
		trash_UI(all_win, BOTTOM_FAIL);
		return 0;
	}
	start_color();
	noecho();
        if(!has_colors()){
		fail_stat = BOTTOM_FAIL;
		goto hyper;
	}

	init_tab_pool(card_pool, tab_pool, no_cards);

	init_pair(YELLOW_GREEN, COLOR_GREEN, COLOR_YELLOW);
	init_pair(GREEN_BLACK, COLOR_BLACK, COLOR_GREEN);
	init_pair(BLUE_BLACK, COLOR_BLACK, COLOR_BLUE);
    init_pair(CYAN_BLACK, COLOR_BLACK, COLOR_CYAN);
    init_pair(RED_YELLOW, COLOR_YELLOW, COLOR_RED);
    init_pair(BLACK_YELLOW, COLOR_YELLOW, COLOR_BLACK);
    init_pair(WHITE_BLUE, COLOR_BLUE, COLOR_WHITE);
    init_pair(CYAN_WHITE, COLOR_WHITE, COLOR_CYAN);
    init_pair(CYAN_GREEN, COLOR_GREEN, COLOR_CYAN);
    init_pair(CYAN_RED, COLOR_RED, COLOR_CYAN);
    init_pair(CYAN_YELLOW, COLOR_YELLOW, COLOR_CYAN);
    init_pair(BLACK_WHITE, COLOR_WHITE, COLOR_BLACK);
    init_pair(BLUE_WHITE, COLOR_WHITE, COLOR_BLUE);
    init_pair(BLUE_YELLOW, COLOR_YELLOW, COLOR_BLUE);
    init_pair(BLUE_RED, COLOR_RED, COLOR_BLUE);
    init_pair(BLUE_CYAN, COLOR_CYAN, COLOR_BLUE);
    init_pair(BLUE_GREEN, COLOR_GREEN, COLOR_BLUE);
        
	if(!(all_win->bottom = subwin(all_win->root, 1, COLS, LINES-1, 0))){
		fail_stat = BOTTOM_FAIL;
		goto hyper;
	}
        if(!(all_win->title = subwin(all_win->root, 3, COLS, 0, 0))){
		fail_stat = TITLE_FAIL;
		goto hyper;
	}
        if(!(all_win->cardlist = subwin(all_win->root, LINES-6, 16, 4, 0))){
		fail_stat = CARDLIST_FAIL;
		goto hyper;
	}
        if(!(all_win->status_win = subwin(all_win->root, LINES-4, COLS-17, 3, 17))){
		fail_stat = STATUS_WIN_FAIL;
		goto hyper;
	}

	hyper:
		if(fail_stat != NO_WIN_FAIL){
			trash_UI(all_win, fail_stat);
			return 0;
		}
		else {
			wattrset(all_win->root, A_DIM|COLOR_PAIR(BLACK_WHITE));
       		wattrset(all_win->title, TITLE_NOFOCUS);
			wattrset(all_win->bottom, A_BOLD|COLOR_PAIR(RED_YELLOW));
			wattrset(all_win->cardlist,  CARDLIST_NOFOCUS);
			wattrset(all_win->status_win, A_BOLD|COLOR_PAIR(BLUE_WHITE));
			wmove(all_win->root,0,0); 
			for(dummy = 0; dummy < COLS*LINES ; dummy++) waddch(all_win->root,ACS_CKBOARD);
			
			wmove(all_win->title,0,0);
			for(dummy = 0; dummy < COLS*3 ; dummy++) waddch(all_win->title,' ');

			wmove(all_win->bottom,0,0);
			for(dummy = 0; dummy < COLS ; dummy++) waddch(all_win->bottom,' ');

			wmove(all_win->cardlist,0,0);
			for(dummy = 0; dummy <= ((all_win->cardlist->_maxx+1)*(all_win->cardlist->_maxy+1)) ; dummy++)
				 waddch(all_win->cardlist,' ');

			wmove(all_win->status_win,0,0);
			for(dummy = 0; dummy <= ((all_win->status_win->_maxx+1)*(all_win->status_win->_maxy+1)) ; dummy++)
				 waddch(all_win->status_win,' ');

			box(all_win->title,0,0);
			box(all_win->cardlist,0,0);
			box(all_win->status_win,0,0);

		        mvwaddstr(all_win->title, 0, ((COLS/2)-16), "=<| VA RAID Monitor (VARMon) |>="); 
		        mvwaddstr(all_win->title, 1, ((COLS/2)-25), "Ver. 1.2.1 by Julien Danjou <julien@danjou.info>"); 

		        mvwaddstr(all_win->bottom, 0, 1, "<ESC> - Exit | <R> - Refresh | <RETURN> - Lock");
		        mvwaddstr(all_win->cardlist, 0,1, "Detected cards");

			mv_fc(all_win, card_pool, tab_pool, KEY_INIT, no_pages);

		}
return 1;
}

/*
--------------------------------------------------------------------------------
	Get a snapshot of the status and put it in the SNAPSHOT array.
	This is the main parser.
*/
void get_snap(){

	char *offset, line[90];
	int result, cur_card, offset_c, ph_dev_c, lg_drv_c, i;
	
	

	for(cur_card = 0; cur_card < no_pages; cur_card++){
		ph_dev_c = 0;
		lg_drv_c = 0;
		snap_all[cur_card].got_dead = 0;
		while((result = get_line(line, snap_all[cur_card].card_path, 1))){

			/*Get driver version*/
			if((offset = strstr(line, "Driver Version"))){
				/*Position to the end of "Driver ..."*/
				offset += 15;
				offset_c = 0;

				while(offset[offset_c] != ' '){
					snap_all[cur_card].dr_ver[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].dr_ver[offset_c] = 0;
			}

			/*Get author's name*/
			if((offset = strstr(line, "Copyright"))){
				offset = strstr(offset, "by ");
				offset += 3;
				offset_c = 0;

				while(offset[offset_c] != '<'){
					snap_all[cur_card].dr_au[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].dr_au[(offset_c - 1)] = 0;
			}
			/*Get card type*/
			if((offset = strstr(line, "Configuring"))){
				offset = strstr(offset, "DAC");
				offset_c = 0;
// V2
// The better way would be get the string, not hard code it.
// The problem is that the LABEL on UI is too short for some controllers,
// so for now we code it this way.  Should re-visite this piece later. 
if (!offset) {
	char *h ;
	if ((h = strstr(line,"eXtremeRAID 2000")))
		strcpy(snap_all[cur_card].c_type, "eRAID 2000");
	if ((h = strstr(line,"eXtremeRAID 3000")))
		strcpy(snap_all[cur_card].c_type, "eRAID 3000");
	else if ((h = strstr(line,"352")))
		strcpy(snap_all[cur_card].c_type, "aRAID 352");
	else if ((h = strstr(line,"160")))
		strcpy(snap_all[cur_card].c_type, "aRAID 160");
	else if ((h = strstr(line,"170")))
		strcpy(snap_all[cur_card].c_type, "aRAID 170");
	else continue;
}
else {
// V2

				while(offset[offset_c] != ' '){
					snap_all[cur_card].c_type[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].c_type[offset_c] = 0;
}
			}
			/*Get firmware version*/
			if((offset = strstr(line, "Firmware"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;
//V2
if (offset[0] >= '6')
	snap_all[cur_card].FirmwareType = 2;
//V2
				while(offset[offset_c] != ','){
					snap_all[cur_card].frmw[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].frmw[offset_c] = 0;
			}

			/*Get number of channels on per card*/
			if((offset = strstr(line, "Channels"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].chnl[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].chnl[offset_c] = 0;
			}
			
			/*Get memory size per card*/
			if((offset = strstr(line, "Memory"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != 0){
					snap_all[cur_card].mem[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].mem[offset_c] = 0;
			}
			
			/*Get PCI bus per card*/
			if((offset = strstr(line, "PCI Bus"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].pci_bus[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].pci_bus[offset_c] = 0;
			}
			
			/*Get device per card*/
			if((offset = strstr(line, "Device: "))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].device[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].device[offset_c] = 0;
			}
			
			/*Get function per card*/
			if((offset = strstr(line, "Function:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].function[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].function[offset_c] = 0;
			}
			
			/*Get I/O address per card*/
			if((offset = strstr(line, "I/O Address:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != 0){
					snap_all[cur_card].io_addr[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].io_addr[offset_c] = 0;
			}
			
			/*Get PCI address per card*/
			if((offset = strstr(line, "PCI Address:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ' '){
					snap_all[cur_card].pci_addr[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].pci_addr[offset_c] = 0;
			}

			/*Get memory mapped address per card*/
			if((offset = strstr(line, "mapped at"))){
				offset += 10;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].pci_mapped[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].pci_mapped[offset_c] = 0;
			}
			
			/*Get IRQ per card*/
			if((offset = strstr(line, "IRQ Channel:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != 0){
					snap_all[cur_card].irq[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].irq[offset_c] = 0;
			}
		
			/*Get Controller Queue depth per card*/
			if((offset = strstr(line, "Controller Queue Depth:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].cq_depth[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].cq_depth[offset_c] = 0;
			}
			
			/*Get Maximum Blocks per Command - per card*/
			if((offset = strstr(line, "Blocks per Command:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != 0){
					snap_all[cur_card].max_block_com[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].max_block_com[offset_c] = 0;
			}
			
			/*Get Driver Que depth per card*/
			if((offset = strstr(line, "Driver Queue Depth:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].dq_depth[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].dq_depth[offset_c] = 0;
			}
			
			/*Get Max Scatter/Gather Segments per card*/
			if((offset = strstr(line, "Gather Segments:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != 0){
					snap_all[cur_card].max_sg_seg[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].max_sg_seg[offset_c] = 0;
			}
//V2  Scatter/Gather
			if((offset = strstr(line, "Gather Limit:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;
				while(offset[offset_c] != ' '){
					snap_all[cur_card].max_sg_seg[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].max_sg_seg[offset_c] = 0;
			}
			
			/*Get Stripe Size per card*/
			if((offset = strstr(line, "Stripe Size:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != ','){
					snap_all[cur_card].stripe_size[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].stripe_size[offset_c] = 0;
			}

			/*Get Segment Size per card*/
			if((offset = strstr(line, "Segment Size:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;
//V2
				if (IS_FIRMWARE_LEVEL_2(cur_card)) {
				  strcpy(snap_all[cur_card].seg_size,offset);
				}
				else {
//V2
				while(offset[offset_c] != ','){
					snap_all[cur_card].seg_size[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].seg_size[offset_c] = 0;
				}
			}
			/*Get Segment Size per card*/
			if((offset = strstr(line, "BIOS Geometry:"))){
				offset = strstr(offset, ":");
				offset += 2;
				offset_c = 0;

				while(offset[offset_c] != 0){
					snap_all[cur_card].bios_geo[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].bios_geo[offset_c] = 0;
			}

			/*Get SAF-TE Fault per card*/
			if((offset = strstr(line, "SAF-TE"))){
				if((offset = strstr(line, "Enabled")))
					snap_all[cur_card].fault_mngmt = 1;
				else
					snap_all[cur_card].fault_mngmt = 0;
			}
			
			/*Get Physical Devices per card*/
			if((offset = strstr(line, "Vendor:"))){
				if((offset = strstr(line, ":"))){
					offset--;
					offset_c = 0;
					while(offset[offset_c] != ' '){
						snap_all[cur_card].ph_dev[ph_dev_c].target[offset_c] = offset[offset_c];
						offset_c++;
					}
					snap_all[cur_card].ph_dev[ph_dev_c].target[offset_c] = 0;
				}
				if((offset = strstr(line, "VALinux")) || (offset = strstr(line, "VA Linux"))){
					if((offset = strstr(line, "Fullon 2x2")))
						strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "Fullon 2x2");
					else if((offset = strstr(line, "nexStor")))
						strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "nexStor");
					ph_dev_c++;
				}else if((offset = strstr(line, "ESG-SHV"))){
					strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "SCA HSBP M6");
					ph_dev_c++;
				}
			}
			if((offset = strstr(line, "Disk"))){
				if(!lock && !ph_dev_c)
					snap_all[cur_card].ph_dev[ph_dev_c].focus = '0';
				else if(!lock)
					snap_all[cur_card].ph_dev[ph_dev_c].focus = 0;

				if((offset = strstr(line, "Online"))){
					strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "ONL");
				}

				if((offset = strstr(line, "Dead"))){
					strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "DED*");
				}

				if((offset = strstr(line, "Standby"))){
					strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "SBY");
				}

				if((offset = strstr(line, "Write-Only"))){
					strcpy(snap_all[cur_card].ph_dev[ph_dev_c].state, "WON");
				}
				
				if((offset = strstr(line, ","))){
					offset += 2;
					offset_c = 0;
					while(offset[offset_c] != ' '){
						snap_all[cur_card].ph_dev[ph_dev_c].blocks[offset_c] = offset[offset_c];
						offset_c++;
					}
					snap_all[cur_card].ph_dev[ph_dev_c].blocks[offset_c] = 0;
				}
				
				if((offset = strstr(line, "Disk:"))){
					offset = strstr(line, ":");
					offset--;
					offset_c = 0;
					while(offset[offset_c] != ' '){
						snap_all[cur_card].ph_dev[ph_dev_c].target[offset_c] = offset[offset_c];
						offset_c++;
					}
					snap_all[cur_card].ph_dev[ph_dev_c++].target[offset_c] = 0;
				}else if((offset = strstr(line, "Disk Status")))
					ph_dev_c++;
			};
			

			/*Get Logical Devices per card*/
			if((offset = strstr(line, "RAID-"))){

				if(!lock && !lg_drv_c)
					snap_all[cur_card].lg_drv[lg_drv_c].focus = '0';
				else if(!lock)
					snap_all[cur_card].lg_drv[lg_drv_c].focus = 0;

				offset_c = 0;
				while(offset[offset_c] != ','){
					snap_all[cur_card].lg_drv[lg_drv_c].raid_l[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].lg_drv[lg_drv_c].raid_l[offset_c] = 0;
				
				if((offset = strstr(line, "Online"))){
					strcpy(snap_all[cur_card].lg_drv[lg_drv_c].state, "ONL");
				}

				if((offset = strstr(line, "Offline"))){
					strcpy(snap_all[cur_card].lg_drv[lg_drv_c].state, "OFL*");
					snap_all[cur_card].got_dead = 2;
				}

				if((offset = strstr(line, "Critical"))){
					strcpy(snap_all[cur_card].lg_drv[lg_drv_c].state, "CRT*");
					if(!snap_all[cur_card].got_dead) snap_all[cur_card].got_dead = 1;
				}
				
				if((offset = strstr(line, ","))){
					offset++;
					if((offset = strstr(offset, ","))){
						offset_c = 0;
						offset += 2;
						while(offset[offset_c] != ' '){
							snap_all[cur_card].lg_drv[lg_drv_c].blocks[offset_c] = offset[offset_c];
							offset_c++;
						}
						snap_all[cur_card].lg_drv[lg_drv_c].blocks[offset_c] = 0;
					}
				}

				if((offset = strstr(line, "Write Thru"))){
					strcpy(snap_all[cur_card].lg_drv[lg_drv_c].wrt_opt, "WT");
				}
				
				if((offset = strstr(line, "Write Back"))){
					strcpy(snap_all[cur_card].lg_drv[lg_drv_c].wrt_opt, "WB");
				}

				if((offset = strstr(line, "/"))){
					offset_c = 0;
					while(offset[offset_c] != ':'){
						snap_all[cur_card].lg_drv[lg_drv_c].dev_name[offset_c] = offset[offset_c];
						offset_c++;
					}
					snap_all[cur_card].lg_drv[lg_drv_c++].dev_name[offset_c] = 0;
				}
			}

			/*Check for Rebuild in progress*/
			if((offset = strstr(line, "Rebuild in Progress"))){
				snap_all[cur_card].rebuild = REBUILD;
				offset_c = 0;
				offset = index(line, '(');
				offset++;
				while(offset[offset_c] != ')'){
					snap_all[cur_card].rb_dev[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].rb_dev[offset_c] = 0;

				offset_c = 0;
				offset = index(line, '%');
				while(*offset != ' ')
					offset--;
				offset++;
				while(offset[offset_c] != '%'){
					snap_all[cur_card].rb_done[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].rb_done[offset_c] = 0;

			}else if((offset = strstr(line, "Consistency Check in Progress:"))){
			/*Check for Consistency Check in progress*/
				snap_all[cur_card].rebuild = CONSISTENCY;
				offset_c = 0;
				offset = index(line, '(');
				offset++;

				while(offset[offset_c] != ')'){
					snap_all[cur_card].rb_dev[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].rb_dev[offset_c] = 0;

				offset_c = 0;
				offset = index(line, '%');
				while(*offset != ' ')
					offset--;
				offset++;
				while(offset[offset_c] != '%'){
					snap_all[cur_card].rb_done[offset_c] = offset[offset_c];
					offset_c++;
				}
				snap_all[cur_card].rb_done[offset_c] = 0;
				
			}else{
				snap_all[cur_card].rebuild = NO_REBUILD;
				snap_all[cur_card].rb_dev[0] = 0;
				snap_all[cur_card].rb_done[0] = 0;
			}
		}
		
		
		for(i = 0; i < snap_all[cur_card].safte.no_bp; i++){
			get_backplane_info(DEVICES, &snap_all[cur_card].safte, cur_card, i);
			get_backplane_info(TEMPERATURE, &snap_all[cur_card].safte, cur_card, i);
		}

	}
	uname(&OS);
}

/*
--------------------------------------------------------------------------------
This function counts the number of cards in the system and sets the global
value "no_pages", it can be called to either count the number of cards or
to set global paths to all the cards in the SNAPSHOT array.
I am using recursion here because there is not a lot of processing
done in this function.
*/
void count_cards(DIR *meet_p){
	int no_cards = 0;
	char *offset, line[90];
	static char count = 2;	/*Did we call our selves twice?*/
	struct dirent *entry;
	char reverse;

/*	If our work here is done*/	
	if(!count) return;

/*	Rewind that dir*/	
	rewinddir(meet_p);

	while((entry = readdir(meet_p))){
		if(!(strcmp(CARD0, entry->d_name)) || !(strcmp(CARD1, entry->d_name)) || !(strcmp(CARD2, entry->d_name)) ||
		!(strcmp(CARD3, entry->d_name)) || !(strcmp(CARD4, entry->d_name)) || !(strcmp(CARD5, entry->d_name)) ||
		!(strcmp(CARD6, entry->d_name)) || !(strcmp(CARD7, entry->d_name))){

			/*Fill in the paths for the SNAPSHOT array*/
			if(count == 1){
				reverse = entry->d_name[1];
				reverse -= '0';
				/*no_cards*/
				strcpy(snap_all[(int)reverse].card_path, MEET_POINT);
				strcat(snap_all[(int)reverse].card_path, entry->d_name);
				strcat(snap_all[(int)reverse].card_path, "/current_status");
			}

			no_cards++;
		}
			
	}


/*	Tell the size of an SNAPSHOT array needed for all
	the cards in the system, If we entered this function
 	for counting afcourse*/
	if(count == 2){
			int i;
	       	no_pages = no_cards;

		if(!(snap_all =  calloc(no_pages, sizeof(SNAPSHOT)))){
			printf("\nSnap_all: Not enough memory.\n\n");
			exit(3);
		};

		/*Make the pointers in SNAPSHOT point to null*/
		for(no_cards = 0; no_cards < no_pages; no_cards++){
			snap_all[no_cards].ph_dev = 0;
			snap_all[no_cards].lg_drv = 0;
			snap_all[no_cards].no_ph_dev = 0;
			snap_all[no_cards].no_lg_drv = 0;
		}
		
		/*Fill in the command structure*/
		for(i = 0; i < 6; i++){
			if(!i) cmd[i].focus = '0';
			else cmd[i].focus = 0;
		}
		i = 0;
		strcpy(cmd[i++].name, "Kill");
		strcpy(cmd[i++].name, "Online");
		strcpy(cmd[i++].name, "Standby");
		strcpy(cmd[i++].name, "Rebuild");
		strcpy(cmd[i++].name, "Consistency");
		strcpy(cmd[i++].name, "Cancel");

	}
	
/*	After the SNAPSHOT array is initialized fill it in.
 	do not move this upwards to the upper (if count == 1)
 	because that is in the while loop*/
	if(count == 1){

		/*Count Physical && Logical devices*/	
		for(no_cards = 0; no_cards < no_pages; no_cards++){
			/*Count Physica && Logical devices per SNAPSHOT*/
			while(get_line(line, snap_all[no_cards].card_path, 1)){
				
				/*Get Physical Devices per card
				be compatible acros driver versions*/
				if((offset = strstr(line, "Disk:")) || (offset = strstr(line, "Vendor:"))){
					snap_all[no_cards].no_ph_dev++;
				}
				/*Get Logical Devices per card*/
				if((offset = strstr(line, "RAID-"))){
					snap_all[no_cards].no_lg_drv++;
				}

			}
			
			/*Allocate memory for the counted physical devices*/
			if(!(snap_all[no_cards].ph_dev =  calloc(snap_all[no_cards].no_ph_dev, sizeof(PHY_DEV)))){
				printf("\nPhysical Devices: Not enough memory.\n\n");
				exit(3);
			}
			

			/*Allocate memory for the counted logical devices*/
			if(!(snap_all[no_cards].lg_drv =  calloc(snap_all[no_cards].no_lg_drv, sizeof(LOG_DRIV)))){
				printf("\nLogical Devices: Not enough memory.\n\n");
				exit(3);
			}
			
		}

		get_snap();
	}

	count--;

	count_cards(meet_p);
}

void init_path(CARD * card_pool, int no_cards){
	int dummy = 0;
	for(;dummy < no_cards; dummy++){
		strcpy(card_pool[dummy].path, MEET_POINT);
		card_pool[dummy].path[(sizeof(MEET_POINT)-1)] = 'c';
		card_pool[dummy].path[(sizeof(MEET_POINT))] = (dummy+'0');
		card_pool[dummy].path[(sizeof(MEET_POINT)+1)] = '\0';
	}
}

/*
--------------------------------------------------------------------------------
	Let there be varmon*/
int main(int argc, char **argv){
		
	SWINDOWS all_win;
  	int key_press;
	DIR *meet_p;
	CARD *card_pool;
	TAB *tab_pool;

	if(getuid()){
		printf("\nMust be root to run varmon.\n\n");
		exit(1);
	}
	
	if(argc > 1)
		if(!strcmp(argv[1], "-b")){
			printf("\n\tVarmon sends an invalid command to the DAC driver,\n"
					"\tcausing the driver to reset it's command buffer.\n"
					"\tThis is nothing to worry about.\n\n");
			exit(1);
		}
	
	if(!(meet_p = opendir(MEET_POINT))){
		printf("\nDAC driver not loaded. Exiting.\n\n");
		exit(1);
	}
	
	count_cards(meet_p);	/*Count the number of cards
							 and fill in the SNAPSHOT paths*/
	closedir(meet_p);
	
	printf("\nScanning for VA safety backplane.\n"
			"Please wait a few moments...");
	detect_backplane();
	printf("\tDone.\n");
	
	
	if(!(card_pool =  calloc(no_pages, sizeof(CARD)))){
		printf("\nCard_pool: Not enough memory.\n\n");
		exit(2);
	};
	if(!(tab_pool =  calloc(NO_TABS, sizeof(TAB)))){
		printf("\nTab_pool: Not enough memory.\n\n");
		exit(2);
	}
	init_path(card_pool, no_pages);

	if(!(build_UI(&all_win, card_pool, tab_pool, no_pages))) goto fall_back;
	curs_set(0);
	keypad(all_win.root,TRUE);
	halfdelay(10);
	while ((key_press = wgetch(all_win.root))){
		if((key_press == KEY_ESCPE) && (lock == NO_LOCK)) break;
		else if((key_press == KEY_ESCPE) && (lock == LOCK_CARDS))
			lock = NO_LOCK;
			
		if(key_press == KEY_r || key_press == KEY_R){
			key_press = KEY_INIT;
			clearok(all_win.root, TRUE);
			get_snap();
		}
		if(key_press == ERR){
			key_press = KEY_INIT;
			get_snap();
		}

		mv_fc(&all_win, card_pool, tab_pool, key_press, no_pages);
		refresh();
		clearok(all_win.root, FALSE);
	}
	trash_UI(&all_win,TRASH_ALL);
	fall_back:
	free(card_pool);
	free(tab_pool);
return 0;
}

