I am writting a C program formed by a parent and his child (using fork). They comunicate through a pipe. Parent writes into the pipe through the standard output and child reads from the pipe through the standard input. Once they are connected, parent writes "hello world" into the pipe, and son calls exec. My code looks like this:
int main(int argc, char *argv[])
{
int p, a;
char buf[1024];
FILE *file;
size_t nread;
int fd[2];
char argument[PATH_MAX];
if(pipe(fd)<0){
return 1;
}
p = fork();
switch(p){
case -1: perror("Error en el fork()"); return 1;
case 0:
close(fd[1]);
close (0);
dup(fd[0]);
close(fd[0]);
sprintf(argument,"/usr/bin/%s",argv[1]);
execvp(argument,argv);
perror("Error en el execv");
exit(1);
default: break;
}
close(fd[0]);
close(1);
a = dup(fd[1]);
close(fd[1]);
write(1,"Hello World\n",12);
close(a);
wait(NULL);
return 0;
}
exec function executed by the son calls functions rev or wc. If called without arguments, rev and wc should be applied to the standard input ("hello world" in my case). But this is not working and I don't know why. Any help would be really appreciated.
this is not working and I don't know why
Because you are using dup()
. To redirect the standard input of the child process to the pipe, the correct system call to use is dup2()
case 0:
close( fd[1] );
dup2( fd[0], 0 ); // this "dup"s the read-end of the pipe onto STDIN
close( fd[0] );
Note that you don't need the dup()
call at all in the parent code branch. Just write to the write-end of the pipe:
write( fd[1], "Hello World\n", 12 );
However, if you want to use execvp in the parent branch also, to launch another program with its standard output redirected, then you would have to use dup2()
here also:
dup2( fd[1], 1 ); // this "dup"s the write-end of the pipe onto STDOUT
close( fd[1] );
Read the manpage for dup2
for details.
Also, another problem with your code is the use of execvp with argv
as the argument list. This will cause programs like rev
and wc
to receive the entire command line of the parent program and thus find an argument to process rather than read from standard input. You probably want
execvp( argv[1], &argv[1] );
You are using execvp()
wrongly in the following code:
sprintf(argument,"/usr/bin/%s",argv[1]);
execvp(argument,argv);
If you run your program by ./a.out wc
, then in this case the arguments to /usr/bin/wc
would be ./a.out wc
, i.e. the original argument list to ./a.out
, then /usr/bin/wc
will try to open a file named wc
in current working directory instead of reading from standard input.
So change the above code to
sprintf(argument,"/usr/bin/%s",argv[1]);
execvp(argument,NULL);
should fix the problem, this time the argument list to /usr/bin/wc
will be a empty list.