Reputation: 953
I'm trying to implement multiple piping using a tutorial I got from this website. I seem to get a bad file descriptor error after executing the function that takes care of multiple piping. When I'm duping for the first time it sends me this error. Here's the code:
void runPipedCommands(cmdLine* command, char* userInput) {
int numPipes = countPipes(userInput);
int status = 0;
int i = 0, j = 0;
pid_t pid;
int pipefds[2*numPipes];
for(i = 0; i < (numPipes); i++){
if(pipe(pipefds + i*2) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
}
j = 0;
while(command) {
pid = fork();
if(pid == 0) {
//if not first command
if(j != 0){
if(dup2(pipefds[j-2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
}
if(command->next){
printf(
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
for(i = 0; i < 2*numPipes; i++){
close(pipefds[i]);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
} else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
command = command->next;
j++;
}
for(i = 0; i < 2 * numPipes; i++){
close(pipefds[i]);
printf("in parent: closed pipe[%d]\n", i);
}
wait(0);
}
}
Maybe there's a leakage somewhere or it can't find the descriptor. I don't seem to know where the problem is. What have I done wrong? Thanks.
Edited code:
void runPipedCommands(cmdLine* command, char* userInput) {
int numPipes = countPipes(userInput);
int status = 0;
int i = 0, j = 0;
pid_t pid;
int pipefds[2*numPipes];
for(i = 0; i < (numPipes); i++){
if(pipe(pipefds + i*2) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
}
j = 0;
while(command) {
pid = fork();
if(pid == 0) {
//if not first command
if(j != 0 && j!= 2*numPipes){
if(dup2(pipefds[j-2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
}
}
//if not last command
if(command->next){
printf("command exists: dup(pipefd[%d], 1])\n", j+1);
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
for(i = 0; i < 2*numPipes; i++){
close(pipefds[i]);
printf("in child: closed pipe[%d]\n", i);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
} else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
command = command->next;
j+=2;
}
for(i = 0; i < 2 * numPipes; i++){
close(pipefds[i]);
printf("in parent: closed pipe[%d]\n", i);
}
wait(0);
}
Upvotes: 1
Views: 4419
Reputation: 953
Here's the answer to the problem. Hopes it helps someone out there. I finally decided to increment j
by 2 (j+=2)
. Function countPipes(char*)
is just a simple function to count the number of pipes(|)
from a char*
void runPipedCommands(cmdLine* command, char* userInput) {
int numPipes = countPipes(userInput);
int status;
int i = 0;
pid_t pid;
int pipefds[2*numPipes];//declare pipes
/**Set up pipes*/
for(i = 0; i < (numPipes); i++){
if(pipe(pipefds + i*2) < 0) {
perror("couldn't pipe");
exit(EXIT_FAILURE);
}
}
int j = 0;
while(command) {
pid = fork();
if(pid == 0) {
//if not last command
if(command->next){
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command
if(j != 0 ){
if(dup2(pipefds[j-2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
}
}
//close pipes in child
for(i = 0; i < 2*numPipes; i++){
close(pipefds[i]);
}
//execute commands
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
} else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
command = command->next;//go to the next command in the linked list
j+=2;//increment j
}
/**Parent closes the pipes and waits for all of its children*/
for(i = 0; i < 2 * numPipes; i++){
close(pipefds[i]);
}
for(i = 0; i < numPipes + 1; i++) //parent waits for all of its children
wait(&status);
}
Upvotes: 0
Reputation: 104020
Ok, first, something that's a little odd -- your nesting does not line up with your braces. if (j != 0)
and if(command->next)
look like the same "level" but the actual braces tell a different story:
Copy-and-paste:
if(j != 0){
if(dup2(pipefds[j-2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
}
if(command->next){
printf(
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
Re-indented to reflect the braces:
if (j != 0) {
if (dup2(pipefds[j - 2], 0) < 0) {
perror(" dup2"); ///j-2 0 j+1 1
exit(EXIT_FAILURE);
}
if (command->next) {
printf(); /* fixed this */
if (dup2(pipefds[j + 1], 1) < 0) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
}
Please ask your IDE, editor, or indent(1)
to re-indent your code to reflect the actual syntax of your code, so that you're not confused by misleading whitespace.
Second, I think you changed the j+=2
from a j++
in an earlier iteration but didn't do so completely -- in the first call, you're using pipefds[j-2]
and in the next call you're using pipefds[j+1]
. Whatever happened to j-1
on the first iteration? It is ignored. Is this intentional? j
is only referenced on the next iteration (via the j+=2 .. [j-2]
). Will anything ever reference the next-to-last entry in pipefds[]
? Is that intentional too?
Upvotes: 2