1

I would like to write a program that will eventually replicate the functionality of this

program1 | program | programX

So I would like to redirect programX's output into programX+1's input.

For the sake of simplicity, I would like to start off with only two programs and a single pipe.

In pseudocode, my approach looks like this:

1. create a pipe for communication between child1 and child2
2. fork parent to create child1 and fork parent again to create child2
3. close unneeded pipe ends in children
4. redirect the output of execvp() from child 1 into the write-end of the pipe via dup2, so that child2 receives whatever that program puts out
5. child2 reads the pipe and receives output from program of child1
6. execute execvp() with the received data

So far so good, here is what I currently have:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define READ  0
#define WRITE 1

int main(int argc, const char * argv[])
{

    //create a unidirectional pipe
    int aPipe[2];

    if(pipe(aPipe)){

        perror("pipe call");
        exit(EXIT_FAILURE);

    }

    //create child 1 ("sender")
    pid_t child_pid = fork();

    if(child_pid < (pid_t)0)
    {
        perror("fork call failed");
        exit(EXIT_FAILURE);
    }
    else if(child_pid == (pid_t) 0){

        //in child1
        close(aPipe[READ]);

        //get actual arguments from argv array
        const char **realArgs = malloc(sizeof(char *) * (argc-1));

        for(int i=1;i<argc;i++){

            realArgs[i-1] = argv[i];

        }

        //redirect standard output into write-end of the pipe
        dup2(aPipe[WRITE], STDOUT_FILENO);
        close(aPipe[WRITE]);
        execvp(argv[0], realArgs);

        //exec call failed
        exit(EXIT_FAILURE);



    }


    //parent
    //create second child ("receiver")
    pid_t child2_pid = fork();

    if(child2_pid == (pid_t)0){

        //close unneeded pipe end
        close(aPipe[WRITE]);

        char buffer[1024];
        char **argv2 = malloc(sizeof(char *));

        while (read(aPipe[READ], buffer, sizeof(buffer)) != 0)
        {

            argv2[0] = buffer;
            printf("buffer = %s", buffer);
            //execvp("sort", argv2);

        }

        close(aPipe[READ]);
        exit(EXIT_SUCCESS);

    }

    //close unneeded pipe ends, parent does not need the pipe
    close(aPipe[WRITE]);
    close(aPipe[READ]);

    exit(EXIT_SUCCESS);

    return 0;
}

That achieves almost what I am trying to do, but the output in child2 seems to write into the pipe again and that results in writing into its own pipe. I think, and I may be completely wrong here, that (despite closing the write end in child2) via printf it writes into its own pipe (as I redirected STDOUT into the write end of the pipe) and reads that again. So the output looks like this

When I run the program with parameters who and sort

myProg who sort

I get the following output:

buffer = buffer = martine****** console Apr 24 12:59

EDIT:

How do I set the input for the sort command in execvp("sort", argsArr); ? sort usually takes in a filename, so how do I go about that ?

the_critic
  • 12,720
  • 19
  • 67
  • 115
  • Your while loop seems to go 2 iterations. The first iteration, buffer is empty, so the program writes `buffer=`. The second iteration it gets data and writes `buffer = martine****** console Apr 24 12:59`. – Klas Lindbäck Apr 24 '14 at 14:52
  • this is a common homework question and a common question on so. If you do a search you should find many questions and answers about this task. – Hogan Apr 24 '14 at 14:58
  • @KlasLindbäck Well, actually, if I delimit the output with ticks, I get something like buffer = "buffer = "martine****** console Apr 24 12:59"". So it seems like it does get the stdout into the pipe, which is very strange. – the_critic Apr 24 '14 at 14:59
  • @Hogan I have seen 3 questions on here, none of which actually helped me. For example, the sort command (see edited question) takes a filename as input, how do I execvp("sort", ?fileDescriptor? ) ? – the_critic Apr 24 '14 at 15:00
  • With no FILE, or when FILE is `-`, `sort` reads from standard input. – Klas Lindbäck Apr 24 '14 at 15:02
  • "... I think, and I may be completely wrong here,..." You are completely wrong. Using pipes has nothing to do with writing to a file even if you are using `fprintf`. This is how unix works input and output look like files to the program but aren't – Hogan Apr 24 '14 at 15:03
  • @Hogan I think you have misunderstood what I was trying to say. I thought I would need a filename for the sort command, but as KlasLindbäck pointed out, if no file is given, sort reads from stdin... So that was helpful to start with. What I meant is, that I used dup2 to redirect stdout into the write end of the pipe. In child2, via printf, I write into stdout right ? If my assumption is correct, then I had assumed before that it would redirect that output into the pipe again. Again maybe I am the one who misunderstands all of this. – the_critic Apr 24 '14 at 15:19
  • @MartinE. - Your description is confusing. The process is simple. You take the standard out of one process and feed it to the standard in of the **next process**. If you feed a single processes standard out to it's own standard in then you won't have a pipe. In order to do this your control program (shell) must keep track of all the processes it forks and wire them up. – Hogan Apr 24 '14 at 15:26
  • @Hogan Alright, so that is exactly what **I think** I am doing in my code. And I do get the output of child1, however I hoped somebody could point out what exactly is wrong. True, I still have difficulties understanding all of this, but I wrote this code and I do try hard. It just doesn't 'click' yet for me. So I hoped I could get some help here. – the_critic Apr 24 '14 at 15:34
  • Sure, take a look at this question >> http://stackoverflow.com/questions/8555900/fork-exec-pipe-redirection-issue?rq=1 Does that clear it up. If not look at the related questions on the right. – Hogan Apr 24 '14 at 15:42
  • @Hogan Thanks for your help. Appreciate your time. I still don't get it... – the_critic Apr 24 '14 at 16:00
  • One problem you have is that `read` reads raw data (with no NULL termaintor) into a buffer, while `printf` expects a NULL terminated string. You need to manually add a NULL terminator to the buffer after the data read before trying to `printf` it to avoid problems. – Chris Dodd Apr 24 '14 at 17:26

0 Answers0