Estoy luchando por implementar un caparazón con tuberías para la clase.Tuberías UNIX en el bloque C en lectura
typedef struct {
char** cmd;
int in[2];
int out[2];
} cmdio;
cmdio cmds[MAX_PIPE + 1];
Comandos en la tubería se leen y se almacenan en cmds
.
cmdio[i].in
es el par de descriptores de archivo del tubo de entrada devuelto por pipe()
. Para el primer comando, que se lee desde la entrada del terminal, es simplemente {fileno (stdin), -1}. cmdin[i].out
es similar para la salida de salida de tubería/terminal. cmdio[i].in
es lo mismo que cmd[i-1].out
. Por ejemplo:
$ ls -l | sort | wc
CMD: ls -l
IN: 0 -1
OUT: 3 4
CMD: sort
IN: 3 4
OUT: 5 6
CMD: wc
IN: 5 6
OUT: -1 1
Pasamos cada comando a process_command, que hace una serie de cosas:
for (cmdi = 0; cmds[cmdi].cmd != NULL; cmdi++) {
process_command(&cmds[cmdi]);
}
Ahora, en el interior process_command:
if (!(pid_fork = fork())) {
dup2(cmd->in[0], fileno(stdin));
dup2(cmd->out[1], fileno(stdout));
if (cmd->in[1] >= 0) {
if (close(cmd->in[1])) {
perror(NULL);
}
}
if (cmd->out[0] >= 0) {
if (close(cmd->out[0])) {
perror(NULL);
}
}
execvp(cmd->cmd[0], cmd->cmd);
exit(-1);
}
El problema es que leyendo desde la bloques de tubería para siempre:
COMMAND $ ls | wc
Created pipe, in: 5 out: 6
Foreground pid: 9042, command: ls, Exited, info: 0
[blocked running read() within wc]
Si, en lugar de intercambiar el proceso con execvp
, acabo de hacer esto:
if (!(pid_fork = fork())) {
dup2(cmd->in[0], fileno(stdin));
dup2(cmd->out[1], fileno(stdout));
if (cmd->in[1] >= 0) {
if (close(cmd->in[1])) {
perror(NULL);
}
}
if (cmd->out[0] >= 0) {
if (close(cmd->out[0])) {
perror(NULL);
}
}
char buf[6];
read(fileno(stdin), buf, 5);
buf[5] = '\0';
printf("%s\n", buf);
exit(0);
}
Le pasa a trabajar:
COMMAND $ cmd1 | cmd2 | cmd3 | cmd4 | cmd5
Pipe creada, in: 11 out: 12
Pipe creada, in: 13 out: 14
Pipe creada, in: 15 out: 16
Pipe creada, in: 17 out: 18
hola!
Foreground pid: 9251, command: cmd1, Exited, info: 0
Foreground pid: 9252, command: cmd2, Exited, info: 0
Foreground pid: 9253, command: cmd3, Exited, info: 0
Foreground pid: 9254, command: cmd4, Exited, info: 0
hola!
Foreground pid: 9255, command: cmd5, Exited, info: 0
Cuál podría ser el problema?
Hum, no funciona: \ Sigue siendo lo mismo, excepto que stdin/stdout se cierra antes de ejecutar el comando, por ejemplo 'cat' falla con' cat: stdin: Bad file descriptor'. Pero incluso si evito cerrar stdin/out, el comportamiento es el mismo que antes. Por lo que entiendo ambos 'cmd -> (in | out) [(0 | 1)]' se refieren a los mismos archivos subyacentes como 'fileno (std (in | out)', ¿no? –
Bien Cada tubo tiene un descriptor de lectura y un descriptor de escritura. Según tengo entendido, tiene dos derivaciones entre el padre y el hijo (o entre los dos hijos).En cada proceso secundario, solo querrá un 'dup2()' del extremo de lectura de una tubería abierta en 'stdin' y solo' dup2() 'del extremo de escritura de la otra tubería abierta en' stdout'; los cuatro extremos originales de la tubería deberían estar cerrados (que es lo que sorprende a las personas). No estoy seguro si tenemos suficiente del código para decir qué más está yendo mal. –
Gracias Jonathan, no estaba cerrando ambos extremos de los tubos del padre como dijiste. ¡Muchas gracias! –