DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Simple Popen2 Implementation

01.10.2006
| 16083 views |
  • submit to reddit
        I needed a simple popen2 implementation. This is similar to popen, but allows for bidirectional communication with the application being executed. Based on some other examples, I put this together. It makes for a good base.

#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define READ 0
#define WRITE 1

pid_t
popen2(const char *command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execl("/bin/sh", "sh", "-c", command, NULL);
        perror("execl");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

Simple usage would be:

int
main(int argc, char **argv)
{
    int infp, outfp;
    char buf[128];

    if (popen2("sort", &infp, &outfp) <= 0)
    {
        printf("Unable to exec sort\n");
        exit(1);
    }

    write(infp, "Z\n", 2);
    write(infp, "D\n", 2);
    write(infp, "A\n", 2);
    write(infp, "C\n", 2);
    close(infp);

    *buf = '\0';
    read(outfp, buf, 128);

    printf("buf = '%s'\n", buf);

    return 0;
}
    

Comments

Peter Cooper replied on Thu, 2006/08/03 - 10:23pm

I just got a mail from someone who submitted new code that fixes some problems in the above. I'm not a C programmer so cannot vouch for it, but supposedly it cleans up some memory leaks of some sort: #include #include #include #include #include #define READ 0 #define WRITE 1 pid_t popen2(const char *command, int *infp, int *outfp) { int p_stdin[2], p_stdout[2]; pid_t pid; if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) return -1; pid = fork(); if (pid < 0) return pid; else if (pid == 0) { close(p_stdin[WRITE]); dup2(p_stdin[READ], READ); close(p_stdout[READ]); dup2(p_stdout[WRITE], WRITE); execl("/bin/sh", "sh", "-c", command, NULL); perror("execl"); exit(1); } if (infp == NULL) close(p_stdin[WRITE]); else *infp = p_stdin[WRITE]; // The way it was p_stdin[read] in this program is still open if (outfp == NULL) close(p_stdout[READ]); else *outfp = p_stdout[READ]; // as well as p_stdout[write], they're closed in the fork, but not in the original program //fix is ez: close(p_stdin[READ]); // We only write to the forks input anyway close(p_stdout[WRITE]); // and we only read from its output return pid; }

Snippets Manager replied on Sat, 2006/07/08 - 8:43pm

Thanks for this code snippet. It was a lifesaver. When I tried using the code, I found I had to add several close statements. After close(p_stdin[WRITE]); dup2(p_stdin[READ], READ); close(p_stdout[READ]); dup2(p_stdout[WRITE], WRITE); I added close(p_stdout[READ]); close(p_stdin[WRITE]); since dup2 creates an extra copy of the file descriptors. Just before return pid; I added close(p_stdin[READ]); close(p_stdout[WRITE]); since the parent process has no business reading from the child's stdin our writing to its stdout.