vendredi 27 février 2015

I/O redirection, printing to the wrong file descriptor


I'm working with piping along with other file descriptors, and I ran into a pickle.


Some Context


For some clairty, the function below makes repeated execvp calls using file descriptors based on context. This is so (Ideally) the calls can be easily strung together for i/o redirection.


For example, one possible input might look like:



cat < input.txt | tr a-z A-Z


Which a parser outside of this function turns into:



argvv.at(0).first = "cat", NULL
argvv.at(0).second.at(0) = "1" //this lets us easily see what fd this 'chunk' is using. In my code, 1 stands for "<"
argvv.at(0).second.at(1) = "input.txt" // the file to be read from

argvv.at(1).first = "tr", "a-z", "A-Z", NULL;
argvv.at(1).second.at(0) = "4" // in my code, 4 stands for |


In a way, it's kind of like this:



(cat < input.txt) (| tr a-z A-Z)
argvv[0] ^ argvv[1] ^


This is all fed to fcall() to execute.


The way the parser works isn't set in stone. It may not be the best way of doing things, but I'd prefer to solve the problem at hand for now.


The issue


For results where calls print to standard out, the calls print to standard in. This remains true for cases that don't involve piping either. This should not be the case, something must be wrong but I can't figure out what.


I'm still new to i/o, and I'm failing to see what file descriptor I miss-handled.


Or perhaps it isn't that, and there's an even bigger misunderstanding. Really, I'm just hoping it turns not not to be a typo so I can learn something new.


What changes to the code need to be made in order to function as intended, and why?


The code



int fcall(std::vector < std::pair<char**, std::vector <std::string> > > argvv ){

const int pipew = 1;
const int piper = 0;
//gotta say, fully understanding pipe I really appriciate how much sense this saves me.


int status;
if (strlen(argvv.at(0).first[0]) == 0){

return -1;
}
if (!strcmp(argvv.at(0).first[0], "exit")){

return 1;
}

//counter of weights


unsigned int waitcount = 0;

int n = 0;

std::vector<int*> fdv;

for (unsigned int k = 0; k < argvv.size(); k++){
if (!argvv.at(k).second.at(0).compare("4") ){ //figures out how many pipes we'll need
int fd[2];
if(pipe(fd) == -1)
perror("pipe");
fdv.push_back(fd);
}
else
{
fdv.push_back(NULL);
}

if(argvv.at(k).second.at(0).compare("2") && argvv.at(k).second.at(0).compare("3")){ //determines how long we should be waiting
waitcount++;
}

}


int stdins;
int stdouts;

if (-1 == (stdins = dup(0)))
perror("dup");
if (-1 == (stdouts = dup(1)))
perror("dup");

for (unsigned int i = 0; i < argvv.size(); i++ ){

int pid = fork();
if(pid == -1)//fork’s return value for an error is -1
{
//perror("There was an error with fork(). ");
perror("fork"); //although you certainly can use the above, it is good
//practice not to write more information than necessary
exit(1);//there was an error with fork so exit the program and go back and fix it
}

else if(pid == 0)//when pid is 0 you are in the child process
{
int fdx;
int fdy;

//(I) ==============
int y = ((int)argvv.at(i).second.at(0).at(0)-48);

std::cerr << y << std::endl;
switch (y){
case 0:
break;

case 1:
if (-1 == (fdy = open(argvv.at(i).second.at(1).c_str(), O_RDONLY))){
perror("open");
}
if (-1 == dup2(fdy, 0)){
perror("dup");
}
break;

case 2:
break;

case 3:
break;

case 4:
if(-1 == dup2(fdv.at(i)[piper],0 ))
perror("dup");
break;

}

//(I +1) ==============
if (i+1 < argvv.size()){
int z = ((int)argvv.at(i+1).second.at(0).at(0)-48);
std::cerr << std::endl;
switch (z){
case 0:
break;

case 1:
break;

case 2:
if (-1 == (fdx = open(argvv.at(i+1).second.at(1).c_str(), O_RDWR | O_CREAT,S_IRWXU ))){
perror("open");
}
if (-1 == dup2(fdx,1 ))
perror("dup");
break;

case 3:
if (-1 == (fdx = open(argvv.at(i+1).second.at(1).c_str(), (O_RDWR | O_APPEND) | O_CREAT,S_IRWXU ))){
perror("open");
}
if (-1 == dup2(fdx,1 ))
perror("dup");
break;

case 4:
if(-1 == dup2(fdv.at(i+1)[pipew],1 ))
perror("dup");
break;
}
}
for(unsigned int kg; kg < fdv.size(); kg++){
if (fdv.at(kg) != NULL){
if (-1 == close(fdv.at(kg)[0]))
perror("close");
if (-1 == close(fdv.at(kg)[1]))
perror("close");
}
}

if (y != 2 && y!= 3){
if (0 < execvp(argvv.at(i).first[0],argvv.at(i).first )){
n = -1;
perror("execvp");
}
}

exit(1); //when the child process finishes doing what we want it to, cout,
//we want to kill the child process so it doesn’t go on in the program so we exit

}

}

for (unsigned int f = 0; f < waitcount; f++){
if (-1 == wait(&status))
perror("wait");
}

if (-1 == dup2(stdins, 0))
perror("dup");
if (-1 == dup2(stdouts, 1))
perror("dup");


if (-1 == close(stdins))
perror("close");
if (-1 == close(stdouts))
perror("close");

return n;
}


Thanks a whole bunch!




Aucun commentaire:

Enregistrer un commentaire