In this function, how do I make it so that the parent stops trying to read from the pipe. I.e. if I run the command ls | grep test grep won't output test and test.c and then wait for user input?
pipe(pipefd);
int pid = fork();
if (pid != 0) {
dup2(pipefd[0], STDIN_FILENO);
int rv2 = execv(get_contain_dir(command_to), args_to);
close(pipefd[0]);
} else {
dup2(pipefd[1], STDOUT_FILENO);
int rv1 = execv(get_contain_dir(command_from), args_from);
close(pipefd[1]);
}
You are not closing the pipes correctly. Each process must close the pipe that it does not use :
int pid = fork();
if (pid != 0) {
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[1]); // not using the left side
int rv2 = execv(get_contain_dir(command_to), args_to);
} else {
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]); // not using the right side
int rv1 = execv(get_contain_dir(command_from), args_from);
}
Related
I want to simulate the pipe command : ls | sort | wc -l by writing some code but I comfront a strange problem ( I can solve it by remove the line but I don't know the reason why it is an error)
When I remove the last wait command it run exactly and finish. But when I add this, it will wait infinity .
int main()
{
int pfds[2];
int pfds1[2];
pipe(pfds); // create a pipe
pid_t pid = fork(); // create child proess
if (pid == 0) // child process
{
dup2(pfds[1],1); // change the stdout to pipe
close(pfds[0]);
execlp("ls", "ls", NULL); // run the ls command
}
else { // main process
wait(0); // wait for the child process
pipe(pfds1); // make a pipe
pid_t npid = fork(); // create child process
if (npid == 0) // child process
{
dup2(pfds[0],0); // change the stdin to pipe
close(pfds[1]);
dup2(pfds1[1], 1); // get data from pipe
close(pfds1[0]);
execlp("sort", "sort", NULL); // run sort command ( combine with above is ls | sort )
}
else { // main process
wait(0); // this line will make infinity wait
dup2(pfds[0], 0);
close(pfds[1]);
execlp("wc", "wc", "-l", NULL); // run wc -l command
}
}
return 0;
}
You aren't closing fds you should be closing. Remember that a file handle is only closed once all file descriptors to it are closed. For example, if you're not careful, it's possible for ls to have completed but sort not realizing this because of a missing close.
Also, your code is susceptible to deadlocks. If ls were to output a large amount, it would write to the first pipe until it's full and block. The parent, rather than emptying the pipe, is waiting for the child to end. Deadlock.
Make sure to close fds you don't need anymore, and start every children before waiting for any to end.
int pfds1[2]; pipe(pfds1);
pid_t pid1 = fork();
if (!pid1) {
close(pfds1[0]);
dup2(pfds1[1], 1); close(pfds1[1]);
execlp("ls", "ls", NULL);
}
close(pfds1[1]);
int pfds2[2]; pipe(pfds2);
pid_t pid2 = fork();
if (!pid2) {
close(pfds2[0]);
dup2(pfds1[0], 0); close(pfds1[0]);
dup2(pfds2[1], 1); close(pfds2[1]);
execlp("sort", "sort", NULL);
}
close(pfds2[1]);
pid_t pid3 = fork();
if (!pid3) {
dup2(pfds2[0], 0); close(pfds2[0]);
execlp("wc", "wc", "-l", NULL);
}
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
waitpid(pid3, NULL, 0);
I am working to make a shell like bash, but i have trouble solving heredoc << so i made a test code as simple as possible for this question.
void pipeline()
{
int i = 0;
int fd[2];
pid_t pid;
int fdd = 0;
while (i < 2)
{
pipe(fd);
pid = fork();
if (pid == 0)
{
//dup2(fd[1],1); if i dup in the first pipe cat dont finalize
if (i == 0)
dup2(fd[0],0);
write(fd[1], "hello\nhow\nare\nyou\n", 17);
close(fd[0]);
close(fd[1]);
dup2(fdd, 0);
if (i == 0)
execlp("cat", "cat", NULL);
else
execlp("grep", "grep", "you" , NULL);
perror("error");
exit(1);
}
else
{
close(fd[1]);
fdd = fd[0];
wait(NULL);
i++;
}
}
}
int main(int *argc, char **argv, char **env)
{
pipeline();
}
I know that cat and grep need an EOF to run; what I'm doing is writing in stdin and running cat, but my question is: how do I save stdout for grep without duping stdout on the first pipe?
If I dup on dup2(fd[1],1) cat does not work in the first pipe, could someone help me out to make this code work? And make it as similar to bash heredoc as well if possible.
how do I save stdout for grep without duping stdout on the first pipe?
I'd rearrange the creation of the child processes from rightmost to leftmost - then grep is created first and can output to the initial output descriptor. A necessary change is to run all child processes before waiting on one as well as before writing, so that there's no deadlock even if the pipe buffer wouldn't suffice for the heredoc.
void pipeline()
{
int i = 2; // create children from last to first
int fd[2];
pid_t pid;
int fdd = 1; // output of last child is STDOUT
while (i--)
{
pipe(fd);
pid = fork();
if (pid == 0)
{
dup2(fdd, 1); // child's output
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
if (i == 0)
execlp("cat", "cat", "-A", NULL);
else
execlp("grep", "grep", "you" , NULL);
perror("error");
exit(1);
}
if (fdd != 1) close(fdd); // close if a pipe write end
fdd = fd[1]; // preceding child's output is pipe write end
close(fd[0]);
}
write(fd[1], "hello\nhow\nare\nyou\n", 17);
close(fd[1]); // signal EOF to child
while (wait(NULL) > 0) ; // wait for all children
}
int main()
{
int pipefd[2];
char buf;
int pid, pid1;
pid = fork();
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
if(pid == 0){ // CHILD 1
close(pipefd[1]);
while(read(pipefd[0],&buf,1) > 0){ // THIS DOESNT WORK
printf("FIRST CHILD WRITES: %s\n",&buf); // THIS DOESNT WORK
} // THIS DOESNT WORK
close(pipefd[0]);
_exit(EXIT_SUCCESS);
}else{
pid1 = fork();
if(pid1 == 0){ // CHILD 2
close(pipefd[1]);
// while(read(pipefd[0],&buf,1) > 0){ // ONLY THIS (WOULD) WORK
// printf("SECOND CHILD WRITES: %s\n",&buf); // ONLY THIS (WOULD) WORK
// } // ONLY THIS (WOULD) WORK
close(pipefd[0]);
_exit(EXIT_SUCCESS);
}else{ // PARENT
close(pipefd[0]);
char* s = "Write To Pipe";
write(pipefd[1],s,strlen(s));
close(pipefd[1]);
wait(NULL); // WAIT FOR CHILD TO TERMINATE
wait(NULL); // WAIT FOR CHILD TO TERMINATE
}
}
return 0;
}
Whenever I try to run the program only the 2ND CHILD can read from the pipe, the 1ST CHILD never. So I tried commenting the second child's pipe reading, however the first child still can't read from the pipe to which the parent wrote into.
Why can't the 1ST CHILD read from the pipe?
Thanks for the help!
The order is wrong. Your code is
pid = fork();
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
You need to create the pipe before you fork. You would probably catch this type of error if you check for errors on the close and/or the read.
If I create a process with fork(), such as grep, how do I pass it data to process? When I use write I get the error $ grep: (standard input): Bad file descriptor;
Command I'm running ps aux | grep notepad
child = fork();
//C1 execute first line of command line
if(child == 0)
{
close(1); //close stdout
dup(pfds[1]); // make stdout pfds[1]
close(pfds[0]);
//execute the args
execvp(args[0], args);
perror("FAILED TO EXECUTE!!!");
exit(-1);
}
//Parent assume execution control
else
{
int in = dup(0); //duplicate in
int out = dup(1); //duplicate out
//Close the parents in and redirect to pipe
close(0);
dup(pfds[0]);
close(pfds[1]);
waitpid(pid, NULL, 0); // wait for child to die
read(pfds[0], pbuff, P_BUFSIZE); //read from pipe
//Close the parents out and redirect to pipe
close(1);
dup(pfds[1]);
close(pfds[0]);
write(pfds[0], pbuff, sizeof(pbuff)-1);
pid = fork();
//C2 process use the data of the old C1 process
if(pid == 0)
{
//Close childs in and redirect to pipe;
close(0);
dup(pfds[0]);
execvp(args2[0], args2);
perror("Execution failure);
exit(-1)
}
Let's say within a program I want to execute two processes, one to execute a ls -al command, then piping the result into the wc command, and displaying the output on the terminal. How can I do this using pipe file descriptors? So far the code I have written:
int main(int argc, char* argv[]) {
int pipefd[2];
int pipefd2[2];
pipe(pipefd2);
if ((fork()) == 0) {
dup2(pipefd2[1], STDOUT_FILENO);
close(pipefd2[0]);
close(pipefd2[1]);
execl("ls", "ls", "-al", NULL);
exit(EXIT_FAILURE);
}
if ((fork()) == 0){
dup2(pipefd2[0], STDIN_FILENO);
close(pipefd2[0]);
close(pipefd2[1]);
execl("/usr/bin/wc", "wc", NULL);
exit(EXIT_FAILURE);
}
close(pipefd[0]);
close(pipefd[1]);
close(pipefd2[0]);
close(pipefd2[1]);
}
An example would be greatly helpful.
Your example code was syntactically and semantically broken (e.g. pipefd2 not decared, confusion between pipefd and pipefd2, etc.) Since this smells like homework, please make sure you understand my annotations below and ask more if you need to. I've omitted error checks on pipe, fork and dup, but they should be there, ideally.
int main(int argc, char *argv[]) {
int pipefd[2];
pid_t ls_pid, wc_pid;
pipe(pipefd);
// this child is generating output to the pipe
//
if ((ls_pid = fork()) == 0) {
// attach stdout to the left side of pipe
// and inherit stdin and stdout from parent
dup2(pipefd[1],STDOUT_FILENO);
close(pipefd[0]); // not using the right side
execl("/bin/ls", "ls","-al", NULL);
perror("exec ls failed");
exit(EXIT_FAILURE);
}
// this child is consuming input from the pipe
//
if ((wc_pid = fork()) == 0) {
// attach stdin to the right side of pipe
// and inherit stdout and stderr from parent
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[1]); // not using the left side
execl("/usr/bin/wc", "wc", NULL);
perror("exec wc failed");
exit(EXIT_FAILURE);
}
// explicitly not waiting for ls_pid here
// wc_pid isn't even my child, it belongs to ls_pid
return EXIT_SUCCESS;
}