Puede popen () hacer las pipas bidireccionales como tubería () + tenedor ()?
Pregunta
estoy poniendo en práctica la tubería en un sistema de archivos simulado en C ++ (con su mayoría C). Que necesita para ejecutar comandos en el shell de acogida, sino realizar la tubería de sí mismo en el sistema de archivos simulado.
Me podría lograr esto con las llamadas pipe()
, fork()
, y del sistema system()
, pero yo prefiero usar popen()
(que se ocupa de la creación de una tubería, un proceso que se bifurcan, y pasando un comando de la cáscara). Esto puede no ser posible debido a que (creo) que necesito para ser capaz de escribir del proceso padre de la tubería, leer en el extremo proceso hijo, escribir la parte posterior salida del niño, y finalmente leer que la producción de los padres. La página del manual para popen()
en mi sistema dice un tubo bidireccional es posible, pero mi código necesita ejecutarse en un sistema con una versión más antigua soportar tuberías solamente unidireccionales.
Con las llamadas separadas anteriores, que pueden abrir / cerrar tuberías para lograr esto. Es que es posible con popen()
?
Para un ejemplo trivial, para ejecutar lo que necesito ls -l | grep .txt | grep cmds
a:
- Abrir un tubo y proceso para ejecución
ls -l
en el host; leer su posterior salida - Tubería de la salida de la espalda
ls -l
a mi simulador - Abrir un tubo y proceso para ejecución
grep .txt
en el host en la salida por tuberías dels -l
- Tubería la salida de esta vuelta al simulador (pegado aquí)
- Abrir un tubo y proceso para ejecución
grep cmds
en el host en la salida por tuberías degrep .txt
- Tubería la salida de este de nuevo al simulador y imprimirlo
hombre popen
A partir de Mac OS X:
'abre' La función de un
popen()
proceso creando un bidireccional tubería, bifurcar, e invocando la cáscara. Cualquier corriente abierta porpopen()
anterior llamadas en el proceso principal están cerrados en el nuevo proceso hijo. Históricamente, se implementópopen()
con un tubo unidireccional; por lo tanto, muchas implementaciones depopen()
solamente permitir que el argumento de modo para especificar leer o escribir, no ambas. Porquepopen()
ahora se implementa utilizando una tubo bidireccional, el argumento de modo puede solicitar un flujo de datos bidireccional. El argumento de modo es un puntero a una terminada en nulo cadena que debe ser 'R' para la lectura, 'w' para escribir, o 'R +' para la lectura y la escritura.
Solución
parece haber respondido a su propia pregunta. Si sus necesidades de código para trabajar en un sistema más antiguo que no admite tuberías bidireccionales de apertura popen
, entonces usted no será capaz de utilizar popen
(al menos no el que está incluido).
La verdadera pregunta sería acerca de las capacidades exactas de los sistemas más antiguos de que se trate. En particular, no su apoyo pipe
crear tuberías bidireccionales? Si tienen un pipe
que puede crear un tubo bidireccional, pero popen
que no, entonces me gustaría escribir la corriente principal del código de uso popen
con un tubo bidireccional, y suministran una implementación de popen
que puede utilizar un tubo bidireccional que se compila en una utilizado cuando sea necesario.
Si necesita para apoyar los sistemas suficientemente mayor que pipe
sólo es compatible con tubos unidireccionales, a continuación, que está bastante atascado con el uso de pipe
, fork
, dup2
, etc., por su cuenta. Yo probablemente todavía terminar con esto en una función que las obras casi como una versión moderna de popen
, pero en lugar de devolver un identificador de archivo, rellenos en una estructura pequeña con dos identificadores de archivos, uno para los niños de stdin
, el otro para stdout
del niño.
Otros consejos
Me gustaría sugerir a escribir su propia función para hacer la tubería / bifurcación / sistema-ción para usted. Usted podría tener la función de generar un proceso de retorno y de lectura / escritura de descriptores de archivo, 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; /* ? */
}
Se puede añadir cualquier funcionalidad que necesita en ese país.
POSIX establece que el href="http://www.opengroup.org/onlinepubs/9699919799/functions/popen.html" rel="noreferrer"> El argumento de modo en popen () es una cadena que especifica el modo I / O: Cualquier código portable hará ninguna suposición más allá de eso. El Además, las tuberías son diferentes de tomas de corriente y cada descriptor de fichero tubería es uni-direccional. Usted tendría que crear dos tubos, uno para cada sentido configuradas. popen()
llamada
popen()
BSD es similar a lo que describe su pregunta.
En una de netresolve backends Estoy hablando con un guión y por lo tanto tengo que escribir a su stdin
y leer desde su stdout
. La siguiente función se ejecuta un comando con entrada y salida estándar redirigido a una tubería. Se puede utilizar y adaptar a su 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
(I utiliza el mismo código en popen simultánea leer y escribir )
No hay necesidad de crear dos tubos y perder un descriptor de fichero en cada proceso. Sólo tiene que utilizar un enchufe en su lugar. https://stackoverflow.com/a/25177958/894520