Search code examples
cunixprocesspipepopen

How do I have control over the pipe created by popen()?


Note: I know I can achieve what I am describing by using fork and maybe wait but I want to understand how popen works and how I can use it to communicate between processes.

I want to use popen to create a child process, then in the child process I write to the pipe created by popen and then, in the parent process, I read from the pipe and output the message.

This is what I have tried:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

#define BUFFER_SIZE 105

int main(int argc, const char * argv[])
{
    FILE* fp;
    int status;
    char buffer[BUFFER_SIZE];

    fp = popen("date", "r"); // returns `FILE *` object (the same as a "stream", I think)
    if(fp == NULL) { printf("Eroare la deschidere cu `popen()`\n");} return -1; // or `EXIT_FAILURE`

    fgets(buffer, BUFFER_SIZE, fp); // ????? is this where I am reading from the pipe? 
                                    // `popen` returns a pointer to a stream, thus is it a `FILE *` object?
                                    // As such, is `fp` also the pipe? "pipe" == "stream" == `FILE *` object ?
    printf("I have read: %s", buffer); 

    status = pclose(fp);
    if(status == -1) { printf("`Eroare la inchiderea cu popen()`\n"); return -1;} // or `EXIT_FAILURE`

return 0; // or `EXIT_SUCCESS`?
}

Also, which is the pipe in such a context? Is fp both a FILE * object and "the pipe"? Can I access fp[0] & fp[1] ?

Output:

I have read: Thu Apr 30 16:29:05 EEST 2020

Solution

  • I'm not entirely clear what you're asking here, so let me know if this answer misses the mark.

    man popen confirms that popen returns a FILE *. It's not an array; there is no fp[0] or fp[1].

    A "pipe" is just a pair of connected file descriptors...one is available in the parent process (that's the return value from popen) and one is available in the child process. When you read from your fp variable you are reading from one end of the pipe (and when the child process writes to stdout it is writing to the other end of the pipe).

    is the child reading from the stream or the parent

    When you run fp = popen("date", "r"), you are creating a uni-directional pipe. The parent can read, and the child can write (if you were to specify "w" as the mode instead you'd have the opposite).

    You are explicitly reading from the pip here:

    fgets(buffer, BUFFER_SIZE, fp);
    

    and how do I know what is executed by the sub-process

    The subprocess executes what you told it to (in this case, date).

    Furthermore, how do we know which end is for read and which is for write

    You control with the second argument to the popen command.


    is the whole purpose of popen (in my case, here) to redirect the output of a command to the parent process

    The purpose of popen is to permit communication between a child process and a parent process. It creates a unidirectional pipe, but you control whether that is parent -> child or child -> parent.

    Is this what happens in the program I have provided? 1) popen opens a sub-process 2) The sub-process writes the output of the date command to the writing-end of the pipe 3) The parent process reads the read-end of the pipe(ie what the child has transmitted)?

    That is correct.