Comme vecchio l'a si bien dit, il faut utiliser pipe ... enfin presque :)
Il faut en fait comprendre ce qui se passe quand on utilise un pipe dans un shell (C'est en fait une fonctionalité du shell). L'utilisation du pipe indique au shell qu'il doit rediriger la sortie du premier programme vers l'entrée du second. Redirection implique une modification des handles standard input et standard output (puisqu'on veut récupérer le résultat en sortie).
Pour ce faire, on utilise donc un pipe (ou un unix socket, rien à voir avec les sockets ip) qui agit comme un buffer entre les deux programmes.
J'ai déjà écrit ce genre de code pour un serveur web lors de l'exécution des cgi et de la récupération des résultats de l'exécution (si tu ne vois pas le lien, ne cherche pas ce n'est pas grave :p).
Je copie la partie du code implémente cette fonctionalité. Je n'ai pas mis toutes les fonctions utilisées mais leurs noms est assez explicite pour que tu puisses les recoder.
Argument de la fonction:
1) tableau de string formant la ligne de commande
2) tableau de string pour les variables d'environnement
3) pointeur vers un entier dans lequel sera stocké le "file descriptor" à utiliser pour lire le stdout et écrire dans le stdin du programme (simplement avec read et write comme s'il s'agissait d'un fichier).
Le principe de la fonction est de créer une paire de socket déjà connecté, de faire un fork (les file descriptors pour le deux bouts du tunnel sont toujours valides), de fermer un des deux bouts selon qu'on est dans le parent où dans le fils. Pour le processus parent le travail s'arrête là. Dans le processus fils, il faut encore dédoubler le bout du "tunnel" en stdin et stdout. Il faut enfin faire un exec pour lancer le programme à exécuter. La fonction exec ne réouvre pas le flux d'entrée et de sortie. De cette façon, nos modifications de stdin et stdout seront conservées. Assez de blabla, maintenant le code :P
int
io_popen(char *argv[], char *envp[], int *srv_child)
{ int sockpair[2];
int child_srv;
if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1)
{ log_error("socketpair failed: %s", strerror(errno)); return -1;
}
*srv_child = sockpair[0];
child_srv = sockpair[1];
int retval = fork();
if(retval < 0)
{ /* parent - fork has failed */
log_error("fork failed: %s", strerror(errno)); io_close(child_srv);
io_close(*srv_child);
return -1;
}
else if(retval > 0)
{ /* parent - close the file descriptor used by the child */
io_close(child_srv);
return 0;
}
/*---------------*
| Child process |
*---------------*/
/* close socket used by parent */
io_close(*srv_child);
/* logs shouldn't be accessed by cgi */
log_close();
/* close stdin and stdout */
io_close(STDIN_FILENO);
io_close(STDOUT_FILENO);
/* duplicate input and output to stdin and stdout */
if (dup2(child_srv, STDIN_FILENO) != STDIN_FILENO ||
dup2(child_srv, STDOUT_FILENO) != STDOUT_FILENO)
{ io_close(child_srv);
debug_msg(ERROR, "dup2 failed: %s", strerror(errno));
_exit(EXIT_FAILURE);
}
execve(argv[0], argv, envp);
/* execve doesn't return on success */
if (errno == ENOEXEC || errno == EACCES)
debug_msg(ERROR, "CGI file not executable");
else
debug_msg(ERROR, "execve failed: %s", strerror(errno));
/* prevent the call to the function registered with atexit */
_exit(EXIT_FAILURE);
}
Si tu as des questions sur le code ou sur mes explications (légèrement foireuse ?), n'hésite j'essayerais de faire mieux.
Belo