pipe, fork and shell commands in C
I am trying to reproduce the pipes in a shell. for example ls | sort At first I am trying the pipes but I can't get the parent to read the result of what the child has executed:
//pipes essai
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <assert.h>
# include <string.h>
# include <sys/stat.h>
# include <fcntl.h>
enum {
MaxLigne = 1024, // longueur max d'une ligne de commandes
MaxMot = MaxLigne / 2, // nbre max de mot dans la ligne
MaxDirs = 100, // nbre max de repertoire dans PATH
MaxPathLength = 512,
// longueur max d'un nom de fichier
};
void decouper(char *, char *, char **, int);
int spawn(char * pathname, char * mot[]);
# define PROMPT "? "
int main(int argc, char * argv[]) {
char ligne[MaxLigne];
char pathname[MaxPathLength];
char * mot[MaxMot];
char * dirs[MaxDirs];
int i, tmp, x;
int fd[2];
int t, res = 0;
char buf[1024];
char * mot2[10];
/* Decouper PATH en repertoires */
decouper(getenv("PATH"), ":", dirs, MaxDirs);
/* read the command lines and try to execute them */
for (printf(PROMPT); fgets(ligne, sizeof ligne, stdin) != 0; printf(PROMPT)) {
decouper(ligne, " \t\n", mot, MaxMot);
if (mot[0] == 0) // empty line
continue;
//launch the pipe
int p=pipe(fd);
assert(p>=0);
tmp = fork(); // launch the pipe process
if (tmp < 0) {
perror("fork");
continue;
}
开发者_JAVA技巧 if (tmp != 0) { // parent wait for end of child
//close this side of the pipe
close(fd[1]);
//waiting
while (wait(0) != tmp)
;
//when finish waiting read what the child has written in the pipe
read(fd[0], buf, sizeof(buf));
//print the result
printf("read %s\n", buf);
//get back the hand to the user
continue;
}else if (tmp==0){
// child
//close this side of the pipe
close(fd[0]);
//close stdout
t=close(1);
//make sur stdout is closed
assert(t>=0);
//open the pipe for writing in it instead of in the stdout
FILE * sortie=fdopen(fd[1], O_WRONLY);
//make sure it is ok
assert(sortie!=NULL);
//try to execute the command
for (i = 0; dirs[i] != 0; i++) {
snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot[0]);
execv(pathname, mot);
}
}
// if exec was unsuccessful
fprintf(stderr, "%s: not found\n", mot[0]);
exit(1);
}
printf("Bye\n");
return 0;
}
void decouper(char * ligne, char * separ, char * mot[], int maxmot){
int i;
mot[0] = strtok(ligne, separ);
for(i = 1; mot[i - 1] != 0; i++){
if (i == maxmot){
fprintf(stderr, "Erreur dans la fonction decouper: trop de mots\n");
mot[i - 1] = 0;
}
mot[i] = strtok(NULL, separ);
}
}
there is a problem with this line FILE * sortie=fdopen(fd[1], O_WRONLY);
pipe1.c: In function ‘main’: pipe1.c:81:4: warning: passing argument 2 of ‘fdopen’ makes pointer from integer without a cast /usr/include/stdio.h:303:14: note: expected ‘const char *’ but argument is of type ‘int’
but how can I make the child to output in the pipe??? freopen doesn't work either
the result I get: ? ls read
which means of course nothing is read. What can I do I am really out of ideas now??? thank you very much in advance
A separate problem...
If the child writes a lot of output to the pipe, it'll block until the parent reads some. Pipes have limited capacity (laziness prevents me from looking up typical limit).
Your parent code doesn't do any reading until the child exits. But if the child blocks on pipe output, it'll never exit. Deadlock!
You are confusing the signature of fdopen
with that of open
.
fdopen
takes a const char*
as its second parameter. Try
FILE * sortie=fdopen(fd[1], "w");
Reference:
- http://linux.die.net/man/3/fdopen
EDIT: It appears that you are using
fdopen
for no valid reason. Specifically, I don't see any use of sortie
after it is initialized.
I presume that you are trying to set up standard out for the exec'd program. If that is the case, you should use dup
or dup2
:
close(fd[0]);
close(1);
dup(fd[1]);
close(fd[1]);
//try to execute the command
... as before
Reference:
- http://linux.die.net/man/2/dup
精彩评论