Hello. I need to create a process and get its I / O. In libc there is a popen and you can get either input or output. I need to get this and that.

Please share your ideas :)

  • Getting input is like? - Roman
  • not correctly expressed. Get the input file, as if FILE *. - nrdgrauf 4:02 pm
  • popen has limited capabilities, you should use low-level calls, see the redirection example: ru.stackoverflow.com/a/474094/130 To get a low-level descriptor from FILE* stdio, use fileno , on the contrary - fdopen . - sercxjo

2 answers 2

To get both input and output of the child process, you can redirect them using dup2 () (executable pseudo-code):

 #!/usr/bin/env python from os import * STDIN_FILENO, STDOUT_FILENO = 0, 1 r_stdin, w_stdin = pipe() r_stdout, w_stdout = pipe() if not fork(): # child process close(w_stdin) # unused close(r_stdout) # unused dup2(r_stdin, STDIN_FILENO) # redirect stdin close(r_stdin) dup2(w_stdout, STDOUT_FILENO) # redirect stdout close(w_stdout) execlp('cat', 'cat') else: # parent close(r_stdin) # unused close(w_stdout) # unused write(w_stdin, b'hello') # send some input to the child close(w_stdin) output = read(r_stdout, 512) # read it back write(STDOUT_FILENO, b'got [' + output + b']\n') close(r_stdout) wait() # wait for the child to exit 

In essence, this is the implementation of the steps from the @Pink Tux response .

It is worth mentioning that in practice, many programs change their behavior if their standard I / O is redirected to a pipe. In particular, due to internal buffering, I / O can be delayed, for example, without the - --line-buffered option of the grep option, lines that are not immediately found can print if its output is redirected. Perhaps you should use pseudo-tty (pty) instead of pipe. See Q: Why not just use a pipe (popen ())?


For comparison, here is the full C code corresponding to the above pseudo-code:

 /** Redirect both stdin/stdout of a child process. Test it. * * $ gcc *.c && ./a.out */ #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> #define Close(FD) do { \ int Close_fd = (FD); \ if (close(Close_fd) == -1) { \ perror("close"); \ fprintf(stderr, "%s:%d: close(" #FD ") %d\n", \ __FILE__, __LINE__, Close_fd); \ } \ }while(0) static int child = 0; /* whether it is a child process relative to main() */ static void report_error_and_exit(const char* msg) { perror(msg); (child ? _exit : exit)(EXIT_FAILURE); } /** move oldfd to newfd */ static void redirect(int oldfd, int newfd) { if (oldfd != newfd) { if (dup2(oldfd, newfd) != -1) Close(oldfd); /* successfully redirected */ else report_error_and_exit("dup2"); } } int main(void) { int fd_stdin[2], fd_stdout[2]; /* stdin/stdout pipes */ if (pipe(fd_stdin) == -1) report_error_and_exit("stdin pipe"); if (pipe(fd_stdout) == -1) report_error_and_exit("stdout pipe"); switch(fork()) { case -1: /* error */ report_error_and_exit("fork"); case 0: /* child: redirect stdin/stdout and exec */ child = 1; Close(fd_stdin[1]); /* close unused end of the pipe */ Close(fd_stdout[0]); /* unused */ redirect(fd_stdin[0], STDIN_FILENO); /* redirect stdin */ redirect(fd_stdout[1], STDOUT_FILENO); /* redirect stdout */ execlp("cat", "cat", NULL); report_error_and_exit("execlp"); default: /* parent: write some input to the child and read it back */ Close(fd_stdin[0]); /* close unused end of the pipe */ Close(fd_stdout[1]); /* unused */ { /* send some input to the child */ char buf[] = "hello"; if (write(fd_stdin[1], buf, sizeof buf) == -1) report_error_and_exit("write"); Close(fd_stdin[1]); } { /* read it back */ char readbuf[512] = {0}; ssize_t n = read(fd_stdout[0], readbuf, sizeof readbuf); if (n == -1) report_error_and_exit("read"); Close(fd_stdout[0]); printf("got [%.*s]\n", (int)n, readbuf); } { /* wait for the child to exit */ int status = 0; if (wait(&status) == -1) report_error_and_exit("wait"); } } return 0; } 

    Something like this:

    1. Created 2 channels ( man pipe ) - for reading and writing
    2. Stuck
    3. In the descendant, these descriptors are closed on stdin and stdout
    4. Substituted the descendant by the desired process using something from the exec * family