Dimitris Delis
Dimitris Delis

Reputation: 55

Using processes to run commands with pipes

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

Answers (1)

Some programmer dude
Some programmer dude

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

Related Questions