Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

popen simultaneous read and write [duplicate]

Tags:

c++

c

Is it possible to read and write to a file descriptor returned by popen. I have an interactive process I'd like to control through C. If this isn't possible with popen, is there any way around it?

like image 780
Lee Avatar asked May 30 '11 01:05

Lee


People also ask

Can the pipe created by popen () be used for writing and reading both at the same time?

You can't use popen to use two-way pipes.

What does Popen mean?

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

Why is Popen returning NULL?

Return Value The popen() function returns NULL if the fork(2) or pipe(2) calls fail, or if it cannot allocate memory. The pclose() function returns -1 if wait4(2) returns an error, or some other error is detected.

How does Popen work in C?

The popen() function uses a program name as its first argument. The second argument is a file mode, such as "r" to read, "w" to write, or "r+" for both. Once opened, the same FILE type pointer is used as a reference. When open for input (as shown below), the spawned program's output is captured.


1 Answers

As already answered, popen works in one direction. If you need to read and write, You can create a pipe with pipe(), span a new process by fork() and exec functions and then redirect its input and outputs with dup2(). Anyway I prefer exec over popen, as it gives you better control over the process (e.g. you know its pid)

EDITED:

As comments suggested, a pipe can be used in one direction only. Therefore you have to create separate pipes for reading and writing. Since the example posted before was wrong, I deleted it and created a new, correct one:

#include<unistd.h> #include<sys/wait.h> #include<sys/prctl.h> #include<signal.h> #include<stdlib.h> #include<string.h> #include<stdio.h>  int main(int argc, char** argv) {   pid_t pid = 0;   int inpipefd[2];   int outpipefd[2];   char buf[256];   char msg[256];   int status;    pipe(inpipefd);   pipe(outpipefd);   pid = fork();   if (pid == 0)   {     // Child     dup2(outpipefd[0], STDIN_FILENO);     dup2(inpipefd[1], STDOUT_FILENO);     dup2(inpipefd[1], STDERR_FILENO);      //ask kernel to deliver SIGTERM in case the parent dies     prctl(PR_SET_PDEATHSIG, SIGTERM);      //replace tee with your process     execl("/usr/bin/tee", "tee", (char*) NULL);     // Nothing below this line should be executed by child process. If so,      // it means that the execl function wasn't successfull, so lets exit:     exit(1);   }   // The code below will be executed only by parent. You can write and read   // from the child using pipefd descriptors, and you can send signals to    // the process using its pid by kill() function. If the child process will   // exit unexpectedly, the parent process will obtain SIGCHLD signal that   // can be handled (e.g. you can respawn the child process).    //close unused pipe ends   close(outpipefd[0]);   close(inpipefd[1]);    // Now, you can write to outpipefd[1] and read from inpipefd[0] :     while(1)   {     printf("Enter message to send\n");     scanf("%s", msg);     if(strcmp(msg, "exit") == 0) break;      write(outpipefd[1], msg, strlen(msg));     read(inpipefd[0], buf, 256);      printf("Received answer: %s\n", buf);   }    kill(pid, SIGKILL); //send SIGKILL signal to the child process   waitpid(pid, &status, 0); } 
like image 124
Patryk Avatar answered Oct 07 '22 22:10

Patryk