c fork pipe popen dup2

¿Puede el popen() hacer tuberías bidireccionales como pipe()+fork()?



dup2 (5)

En uno de los backends de netresolve estoy hablando con un script y por lo tanto necesito escribir en su stdin y leer desde su stdout . La siguiente función ejecuta un comando con stdin y stdout redirigido a una tubería. Puedes usarlo y adaptarlo a tu gusto.

static bool start_subprocess(char *const command[], int *pid, int *infd, int *outfd) { int p1[2], p2[2]; if (!pid || !infd || !outfd) return false; if (pipe(p1) == -1) goto err_pipe1; if (pipe(p2) == -1) goto err_pipe2; if ((*pid = fork()) == -1) goto err_fork; if (*pid) { /* Parent process. */ *infd = p1[1]; *outfd = p2[0]; close(p1[0]); close(p2[1]); return true; } else { /* Child process. */ dup2(p1[0], 0); dup2(p2[1], 1); close(p1[0]); close(p1[1]); close(p2[0]); close(p2[1]); execvp(*command, command); /* Error occured. */ fprintf(stderr, "error running %s: %s", *command, strerror(errno)); abort(); } err_fork: close(p2[1]); close(p2[0]); err_pipe2: close(p1[1]); close(p1[0]); err_pipe1: return false; }

https://github.com/crossdistro/netresolve/blob/master/backends/exec.c#L46

(Utilicé el mismo código en popen lectura y escritura simultáneas )

Estoy implementando la canalización en un sistema de archivos simulado en C ++ (en su mayoría con C). Debe ejecutar comandos en el shell del host pero realizar la canalización en el sistema de archivos simulado.

Podría lograr esto con las llamadas al sistema pipe() , fork() y system() , pero prefiero usar popen() (que maneja la creación de una tubería, forking un proceso y pasar un comando al shell) . Esto puede no ser posible porque (creo) necesito poder escribir desde el proceso principal de la canalización, leer el final del proceso secundario, escribir la salida desde el secundario y finalmente leer esa salida del primario. La página de popen() de popen() en mi sistema dice que es posible una canalización bidireccional, pero mi código debe ejecutarse en un sistema con una versión anterior que solo admita tuberías unidireccionales.

Con las llamadas separadas arriba, puedo abrir / cerrar tuberías para lograr esto. ¿Es eso posible con popen() ?

Para un ejemplo trivial, ejecutar ls -l | grep .txt | grep cmds ls -l | grep .txt | grep cmds ls -l | grep .txt | grep cmds necesito:

  • Abra una tubería y el proceso para ejecutar ls -l en el host; leer su salida de vuelta
  • Canaliza la salida de ls -l a mi simulador
  • Abra una tubería y el proceso para ejecutar grep .txt en el host en la salida canalizada de ls -l
  • Conecte la salida de esto de vuelta al simulador (atascado aquí)
  • Abra una tubería y procese para ejecutar grep cmds en el host en la salida canalizada de grep .txt
  • Conecte la salida de esto de vuelta al simulador e imprímala.

hombre popen

Desde Mac OS X:

La función popen() ''abre'' un proceso al crear un conducto bidireccional, forking e invocando el shell. Todas las secuencias abiertas por llamadas popen() anteriores en el proceso principal se cierran en el nuevo proceso secundario. Históricamente, popen() se implementó con una tubería unidireccional; por lo tanto, muchas implementaciones de popen() solo permiten que el argumento de modo especifique lectura o escritura, no ambos. Debido a que popen() ahora se implementa mediante una canalización bidireccional, el argumento de modo puede solicitar un flujo de datos bidireccional. El argumento de modo es un puntero a una cadena terminada en nulo que debe ser ''r'' para leer, ''w'' para escribir o ''r +'' para leer y escribir.


No es necesario crear dos tuberías y desperdiciar un filedescriptor en cada proceso. Sólo tiene que utilizar un zócalo en su lugar. https://.com/a/25177958/894520


POSIX estipula que la llamada popen() no está diseñada para proporcionar comunicación bidireccional:

El argumento de modo a popen () es una cadena que especifica el modo de E / S:

  1. Si el modo es r, cuando se inicia el proceso hijo, su descriptor de archivo STDOUT_FILENO será el final grabable del conducto y el descriptor de archivo fileno (flujo) en el proceso de llamada, donde el flujo es el puntero de flujo devuelto por popen (), Será el extremo legible de la tubería.
  2. Si el modo es w, cuando el proceso hijo se inicia, su descriptor de archivo STDIN_FILENO será el final legible de la tubería, y el descriptor de archivo fileno (flujo) en el proceso de llamada, donde la secuencia es el puntero de flujo devuelto por popen (), Ser el extremo escribible de la tubería.
  3. Si el modo es cualquier otro valor, el resultado no está especificado.

Cualquier código portátil no hará suposiciones más allá de eso. El BSD popen() es similar a lo que describe su pregunta.

Además, las tuberías son diferentes de los sockets y cada descriptor de archivo de tuberías es unidireccional. Tendrías que crear dos tuberías, una configurada para cada dirección.


Parece que has contestado tu propia pregunta. Si su código necesita funcionar en un sistema anterior que no admite la apertura de tuberías bidireccionales de popen , entonces no podrá usar popen (al menos no el que se suministra).

La verdadera pregunta sería acerca de las capacidades exactas de los sistemas anteriores en cuestión. En particular, ¿su pipe soporta la creación de tuberías bidireccionales? Si tienen un pipe que puede crear un conducto bidireccional, pero popen que no lo hace, entonces escribiría la secuencia principal del código para usar popen con un conducto bidireccional, y suministrar una implementación de popen que pueda usar un conducto bidireccional que se compila en un usado donde sea necesario.

Si necesita soportar sistemas lo suficientemente antiguos como para que la pipe solo admita tuberías unidireccionales, entonces está prácticamente estancado con el uso de pipe , fork , dup2 , etc., por su cuenta. Probablemente todavía lo incluya en una función que funcione casi como una versión moderna de popen , pero en lugar de devolver un identificador de archivo, rellena una pequeña estructura con dos identificadores de archivo, uno para la stdin del niño y el otro para stdout


Yo sugeriría escribir su propia función para hacer la tubería / bifurcación / sistema para usted. Puede hacer que la función genere un proceso y devuelva los descriptores de archivo de lectura / escritura, como en ...

typedef void pfunc_t (int rfd, int wfd); pid_t pcreate(int fds[2], pfunc_t pfunc) { /* Spawn a process from pfunc, returning it''s pid. The fds array passed will * be filled with two descriptors: fds[0] will read from the child process, * and fds[1] will write to it. * Similarly, the child process will receive a reading/writing fd set (in * that same order) as arguments. */ pid_t pid; int pipes[4]; /* Warning: I''m not handling possible errors in pipe/fork */ pipe(&pipes[0]); /* Parent read/child write pipe */ pipe(&pipes[2]); /* Child read/parent write pipe */ if ((pid = fork()) > 0) { /* Parent process */ fds[0] = pipes[0]; fds[1] = pipes[3]; close(pipes[1]); close(pipes[2]); return pid; } else { close(pipes[0]); close(pipes[3]); pfunc(pipes[2], pipes[1]); exit(0); } return -1; /* ? */ }

Puedes agregar cualquier funcionalidad que necesites allí.