tags:

views:

53

answers:

3

I want to open a process from C code, and be able to read its standard output and standard error, while being able to write to its standard input.

The closest I get to achieving this is using popen(), but this does not allow you to read the standard error stream. You could add "2>&1" to the command, but this will not make it possible to distinguish between the standard output and error data. Being able to seperate both streams is required for my application.

Python has popen3 and Ruby has Open3 to do these kind of things, but I can't seem to find a way to do it in C. Any help?

+1  A: 

If you're forking the child process, you can duplicate the handle of stderr and use it in the child.

Michael Goldshteyn
+2  A: 

You may want to consider using execl(). This is what is used internally by popen().

mouviciel
+2  A: 
#include <unistd.h>
#include <stdio.h>

...


int pipe_err[2], pipe_out[2], pipe_in[2];

if (pipe(pipe_err) || pipe(pipe_out) || pipe(pipe_in)) { // abbreviated error detection
     perror("pipe");
     scream_and_run_around_frantically();
     exit(BAD);
}
pid_t pid = fork();
if (!pid) { // in child
    dup2(pipe_err[1], 2);
    dup2(pipe_out[1], 1);
    dup2(pipe_in[0], 0);
    close(pipe_err[0]);
    close(pipe_err[1]);
    close(pipe_out[0]);
    close(pipe_out[1]);
    close(pipe_in[0]);
    close(pipe_in[1]);

    // close any other files that you don't want the new program
    // to get access to here unless you know that they have the
    // O_CLOEXE bit set

    execl(program_path, program_name, arg1, arg2, arg3);
    /* only gets here if there is an error executing the program */
 } else { // in the parent
     if (pid < 0) {
           perror("fork");
           error_death_plague_stubbed_toe();
           exit(BAD);
     }
     child_err = pipe_err[0];
     close(pipe_err[1]);
     child_out = pipe_out[0];
     close(pipe_out[1]);
     child_in = pipe_in[1];
     close(pipe_in[0]);

     ...

You will probably want to have a look at

man 3 exec

This has lots of functions that turn the current program into a new program. They all have different interfaces, but use execve under the hood.

man 2 execve

Also:

man 2 fork

and

man 2 pipe
nategoose
We wants to send stuff to stdin too.
JeremyP
@JeremyP: see edits
nategoose