Reputation: 15
I'm trying to get something like this to work in c using piping and fork : echo "an operation like 10+10" | bc
To be precise, I tried to create 2 pipes, one where the server will write the operation and bc will read and another where the result of the operation (by bc) will go and the server will read it and printf it. For this, I'm changing the output and input of the parent and child process.
Here is my code:
int main(){
int t1, t2;
char resultat[5];
int pipe1[2];
int pipe2[2];
pipe(pipe1);
pipe(pipe2);
int resultat_fork = fork();
if(resultat_fork == -1){
exit(EXIT_FAILURE);
}
if(resultat_fork!=0){
printf("I am the parent\n");
close(pipe1[0]);
close(pipe2[1]);
//We only want to write into pipe1 and read from pipe2, we can close the two other
write(pipe1[1], "20*5\n", 20);
//write on pipe1 the expression
read(pipe2[0], resultat, sizeof(resultat));
//read from pipe2 the answer (written by bc)
printf("resultat : %s\n",resultat);
close(pipe1[1]);
close(pipe2[0]);
}else{
printf("I am the children\n");
close(pipe1[1]);
close(pipe2[0]);
//We only want to write into pipe2 and read from pipe1, we can close the two other
dup2(pipe1[0], 0);
//redirection standard input to pipe1[0]
dup2(pipe2[1], 1);
//redirection standard output to pipe2[1]
execlp("bc", "bc", NULL);
//execute bc, which normaly will read the operation from pipe1 and write the answer into pipe2, but I think it's here the problem come out
close(pipe1[0]);
close(pipe2[1]);
}
return 0;
}
I'm getting the correct answer but with the error : "(standard_in) 2: illegal character : ^@" "(standard_in) 2: illegal character : :" plus I have to CTRL C to quit. I guess it comes from BC but why...
What am I doing wrong? Thank you! I've already seen few exemple but only threw one pipe.
Upvotes: 1
Views: 1573
Reputation: 755026
This works. Note how it specifies the size of the data to be written, and how it checks the writes and reads, and also how it closes file descriptors. (Remember: sizeof("string literal")
counts the null byte, unlike strlen()
. It's also a compile time constant. However, more general purpose code would use strlen()
on the current expression string.)
Rule of Thumb: If you use dup2()
to duplicate a pipe file descriptor to standard input or standard output, close both ends of the pipe.
That also applies if you use dup()
, or fcntl()
with F_DUPFD
or F_DUPFD_CLOEXEC
instead.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
char resultat[5];
int pipe1[2];
int pipe2[2];
pipe(pipe1);
pipe(pipe2);
int resultat_fork = fork();
if (resultat_fork == -1)
{
exit(EXIT_FAILURE);
}
if (resultat_fork != 0)
{
printf("I am the parent\n");
close(pipe1[0]);
close(pipe2[1]);
if (write(pipe1[1], "20*5\n", sizeof("20*5\n") - 1) != sizeof("20*5\n") - 1)
fprintf(stderr, "write to child failed\n");
int nbytes = read(pipe2[0], resultat, sizeof(resultat));
if (nbytes <= 0)
fprintf(stderr, "read from child failed\n");
else
printf("resultat: [%.*s]\n", nbytes, resultat);
close(pipe1[1]);
close(pipe2[0]);
}
else
{
printf("I am the child\n");
close(pipe1[1]);
close(pipe2[0]);
dup2(pipe1[0], 0);
dup2(pipe2[1], 1);
close(pipe1[0]); /* More closes! */
close(pipe2[1]); /* More closes! */
execlp("bc", "bc", NULL);
fprintf(stderr, "Failed to execute bc\n");
exit(EXIT_FAILURE);
}
return 0;
}
There is still room for improving the error handling; the code ploughs on after reporting some of the errors, which is probably not the best behaviour.
Output:
I am the parent
I am the child
resultat: [100
]
(Note: if you pipe the output of the program somewhere, you don't see the I am the child
message. For the reasons why, see printf()
anomaly after fork()
.)
Upvotes: 2