Never been to DZone Snippets before?

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

Simple popen2 implementation (See related posts)

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 on this post

dalleyg posts on Jul 08, 2006 at 21:47
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.

jswizard posts on Sep 29, 2006 at 14:35
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 <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];
	// 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;
}

You need to create an account or log in to post comments to this site.


Click here to browse all 5059 code snippets

Related Posts