Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h> // for open flags
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
//#define DEVICE_SIZE (1024*1024*256) assume all devices identical in size TODO
#define DEVICE_SIZE (5120)
//TODO set parameters as asked
#define SECTOR_SIZE 512
#define SECTORS_PER_BLOCK 2
#define BLOCK_SIZE (SECTOR_SIZE * SECTORS_PER_BLOCK)
#define BLOCKS_PER_DEVICE (DEVICE_SIZE/BLOCK_SIZE)
#define BUFFER_SIZE (BLOCK_SIZE * 100)//todo , check how many devices are allowed, for read and write buffer in consecutive sectors.
char buf_Read[BUFFER_SIZE];
char buf_Write[BUFFER_SIZE];
int kills;
int num_dev;
int *dev_fd;
int first_kill;
int kill(int device_index)
{
int i,j,check;
int diagonal;
char tmp_buf[BUFFER_SIZE];
if (dev_fd[device_index]==-1)
{
printf("THE_DEVICE_KILLED_BEFORE");
return 0;
}
//no need for restructure
else if(kills>0)
{
check=close(dev_fd[device_index]);
if(check==-1)
{
printf("ERROR_CLOSE_KILL\n");
return -1;
}
kills++;
dev_fd[device_index]=-1;
}
//need to restructure.
else
{
for(i=0;i<BLOCKS_PER_DEVICE;i++)
{
//calculate sec diagonal, knowing where the empty block index.
diagonal=num_dev-1-(i%num_dev);
printf("diagonal for row %d at %d\n", i,diagonal);
if(diagonal>device_index)
{
for(j=diagonal;j>device_index;j--) //for each row
{
//set to the start of the block
if(lseek(dev_fd[j-1],i*BLOCK_SIZE,SEEK_SET)!=i*BLOCK_SIZE)
{
printf("ERROR_LSEEK_KILL\n");
return -1;
}
if(lseek(dev_fd[j],i*BLOCK_SIZE,SEEK_SET)!=i*BLOCK_SIZE)
{
printf("ERROR_LSEEK_KILL2\n");
return -1;
}
//shift right from killed disk to diagonal
if(read(dev_fd[j-1],tmp_buf,BLOCK_SIZE)!=BLOCK_SIZE)
{
printf("ERROR_READ_KILL\n");
return -1;
}
if(write(dev_fd[j],tmp_buf,BLOCK_SIZE)!=BLOCK_SIZE)
{
printf("ERROR_WRITE_KILL\n");
return -1;
}
printf("copy %d from %d to %d\n",tmp_buf[0],j-1,j);
}
}
else if(diagonal<device_index)
{
for(j=diagonal;j<device_index;j++)
{
//set to the start of the blocks
if(lseek(dev_fd[j+1],i*BLOCK_SIZE,SEEK_SET)!=i*BLOCK_SIZE)
{
printf("ERROR_LSEEK_KILL3\n");
return -1;
}
if(lseek(dev_fd[j],i*BLOCK_SIZE,SEEK_SET)!=i*BLOCK_SIZE)
{
printf("ERROR_LSEEK_RAIDKILL4\n");
return -1;
}
//shift left from killed disk to empty block
if(read(dev_fd[j+1],tmp_buf,BLOCK_SIZE)!=BLOCK_SIZE)
{
printf("ERROR_READ_RAID5ee2\n");
return -1;
}
if(write(dev_fd[j],tmp_buf,BLOCK_SIZE)!=BLOCK_SIZE)
{
printf("ERROR_WRITE_RAID5ee2\n");
return -1;
}
}
}
}
//close fd && change to -1 && add kill
if(close(dev_fd[device_index]==-1))
{
printf("ERROR_CLOSE_KILL2\n");
return -1;
}
printf("device_index %d\n",device_index);
first_kill=device_index;
kills++;
dev_fd[device_index]=-1;
}
printf("first_kill : %d\n",first_kill);
printf("kills : %d\n",kills);
return 0;
}
int main(int argc, char** argv)
{
kills=0;
if(argc <= 3)
{
printf("ERROR_CMD_PARAMETERS\n");
return 0;
}
printf("you have %d disks in the system:\n",(argc-1));
int i,check;
char* line = (char *)malloc(1024);
// number of devices == number of arguments (ignore 1st)
num_dev = argc-1;
printf("num_dev %d\n", num_dev);
dev_fd = (int *)malloc(num_dev * sizeof(int));
//intialize buffs (read/write)
memset(buf_Read,0,BUFFER_SIZE);
memset(buf_Write,0,BUFFER_SIZE);
// open all devices
for (i = 0; i < num_dev; ++i)
{
printf("Opening device %d: %s\n", i, argv[i+1]);
dev_fd[i] = open(argv[i+1], O_RDWR);
if(dev_fd[i] < 0)
{
printf("ERROR_OPEN_DEVICE\n");
return 0; //todo (treat it like a kill)
}
}
// vars for parsing input line
char operation[20];
int sector;
char count[20];
printf("States: \n");
printf("BLOCK_SIZE : %d\n",BLOCK_SIZE);
printf("BLOCKS_PER_DEVICE : %d\n",BLOCKS_PER_DEVICE);
// read input lines to get command of type "OP <SECTOR> <COUNT>"
printf("Enter CMD: \n");
while ((fgets(line, 1024, stdin)!=NULL)) {
if((check=sscanf(line, "%s %d %s", operation, §or, count)) != 3)
{
printf("ERROR_CMD_ARGS1\n");
printf("line: %s\n",line);
printf("error: %s\n",strerror(errno));
printf("check : %d\n",check);
printf("operation: %s, sector: %d, count: %s\n",operation, sector, count);
do_raid5ee_rw("READ",0,6);
return 0;
}
//KILL specified device
else if (!strcmp(operation, "KILL"))
{
check = kill(sector);
printf("check: %d\n",check);
if (check==-1) //sector == device index need to be killed.
{
printf("ERROR_KILL_MAIN\n");
return 0;
}
}
// setbuf operation
else if(strcmp(operation, "SETBUF")==0)
{
printf("setting write buffer to: %d\n",sector);
memset(buf_Write,sector,BUFFER_SIZE);//sector == byte value (0-255);
}
//read || write
else if(strcmp(operation, "READ")==0 || strcmp(operation, "WRITE")==0)
{
if (do_raid5ee_rw(operation,sector,atoi(count))==-1)
{
printf("ERROR_RAIDE5ee_RW_MAIN\n"); // if == -1 that means that we have error after trying to kill, that's why we exit.
return 0;
}
}
else if(strcmp(operation, "REPAIR")==0)
{
if (kills==0 || dev_fd[sector]!=-1)
printf("NO_NEED_TO_REPAIR\n");
else if (kills==1)
{
if(repair_raid5ee(sector,count)==-1) //sector == device_index && count == filename.
{
printf("ERROR_REPAIR1_MAIN\n");
return 0;
}
}
else if (kills==2)
{
if(repair_raid5(sector,count)==-1) //sector == device_index && count == filename.
{
printf("ERROR_REPAIR2_MAIN\n");
return 0;
}
}
else
{
if(open(count, O_RDWR) == -1)
{
printf("ERROR_REPAIR_DEVICE_MAIN\n");
return 0;
}
}
}
else
printf("ERROR_CMD_ARGS2\n");
printf("Enter CMD: \n");
}
for(i=0; i < argc-1; i++)
{
if (dev_fd[i] >= 0)
assert(!close(dev_fd[i]));
}
free(dev_fd);
free(line);
return 0;
}