Reputation: 55
I'm still new to processes,pipes and dup2, therefore I'd like someone to help me figure out what's wrong with a program I've created. This program is supposed to run ls | wc
. So far the output I get is :
wc : standard input : Bad file descriptor
0 0 0
ls : write error : Bad file descriptor
After I get this output, the terminal still accepts inputs. It's like wc is still running, although if I put commands like ls first(without any other input before) it runs them and shuts down. I tried running ps before/after and while the program was still running and it didn't show any process being open aside from bash and ps. (I'm running this program in Linux terminal)
Here's my code :
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
#include<errno.h>
int main(int argc, char* argv[]){
pid_t pid;
int fd[2];
char com1[1024] = ("ls");
char com2[1024] = ("wc");
pipe(fd);
pid = fork();
if(pid == 0){
open(fd[1]);
dup2(fd[0],STDOUT_FILENO);
close(fd[0]);
execlp(com1, com1, NULL);
}
else {
pid = fork();
if (pid == 0){
open(fd[0]);
dup2(fd[1],STDIN_FILENO);
close(fd[1]);
execlp(com2, com2, NULL);
}
}
return 0;
}
Bear in mind that I know some if commands for checking are required(like if(pid<0)exit(0);
) but I tried to simplify my code as much as possible in order to see if there's any mistake due to carelessness.
Thank you in advance!
Upvotes: 1
Views: 196
Reputation: 409442
According to the pipe
manual page:
pipefd[0]
refers to the read end of the pipe.pipefd[1]
refers to the write end of the pipe.
Now take this line from the first child, the process that calls the ls
command:
dup2(fd[0],STDOUT_FILENO);
Here you duplicate the read end of the pipe to STDOUT_FILENO
, i.e. where output is written. If you stop and think a little about it, how would you write to a read-only file-descriptor like fd[0]
?
Same with the other child process, where you make the write end of the pipe standard input.
The solution is simple: Swap places of the descriptors you duplicate. Use fd[1]
for the first child process, and fd[0]
for the second child process.
In the first process where you call the ls
command:
dup2(fd[1],STDOUT_FILENO);
close(fd[1]);
execlp(com1, com1, NULL);
And in the second child process where you call the wc
command:
dup2(fd[0],STDIN_FILENO);
close(fd[0]);
execlp(com2, com2, NULL);
Upvotes: 1