Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - pipe without using popen

Tags:

c

pipe

popen

how can I transform this:

FILE *f;
char in_buffer[80];
f=popen("command","r");
fgets(in_buffer,sizeof(in_buffer),f)

without using popen(), but only pipe() or other instruction?

like image 830
Rick Owens Avatar asked Oct 29 '13 19:10

Rick Owens


People also ask

What does Popen do in C?

The popen() function executes the command specified by the string command. It creates a pipe between the calling program and the executed command, and returns a pointer to a stream that can be used to either read from or write to the pipe.

What does Popen mean?

popen - initiate pipe streams to or from a process.

What is Popen function?

The popen() function used to open a pipe to the program specified by the user using the command parameter. It returns a file pointer which is identical to that returned by fopen(), but it is unidirectional in nature i.e it can be only used for reading or writing.


1 Answers

Here's my simple implementation, with comments explaining what's being done.

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

FILE *
my_popen (const char *cmd)
{
    int fd[2];
    int read_fd, write_fd;
    int pid;               

    /* First, create a pipe and a pair of file descriptors for its both ends */
    pipe(fd);
    read_fd = fd[0];
    write_fd = fd[1];

    /* Now fork in order to create process from we'll read from */
    pid = fork();
    if (pid == 0) {
        /* Child process */

        /* Close "read" endpoint - child will only use write end */
        close(read_fd);

        /* Now "bind" fd 1 (standard output) to our "write" end of pipe */
        dup2(write_fd,1);

        /* Close original descriptor we got from pipe() */
        close(write_fd);

        /* Execute command via shell - this will replace current process */
        execl("/bin/sh", "sh", "-c", cmd, NULL);

        /* Don't let compiler be angry with us */
        return NULL;
    } else {
        /* Parent */

        /* Close "write" end, not needed in this process */
        close(write_fd);

        /* Parent process is simpler - just create FILE* from file descriptor,
           for compatibility with popen() */
        return fdopen(read_fd, "r");
    }
}

int main ()
{
    FILE *p = my_popen ("ls -l");
    char buffer[1024];
    while (fgets(buffer, 1024, p)) {
        printf (" => %s", buffer);
    }
    fclose(p);
}

Notes:

  1. Thir code supports only "r" mode of popen. Implementing other modes, namely "w" mode is left as an exercise for the reader.
  2. System functions used in this example may fail - error handling is left as an exercise for the reader.
  3. Implementation of pclose is left as an exercise for the reader - see close, waiptid, and fclose.

If you want to look at real impementations, you can look into sources of OSX, GNU glibc and OpenSolaris, among others.

Hope this helps!

like image 101
el.pescado - нет войне Avatar answered Sep 21 '22 23:09

el.pescado - нет войне