strstr expects a zero-byte terminator. The input string "\0" looks like an empty string and will always return a pointer to the beginning of the other string (it matches the empty string at the beginning, I guess). So if you're testing it logically, it will always be true.
memchr doesn't assume a null-byte terminator but instead takes a maximum length of memory to search. It occurs to me now that you'd have to initialize the memory to a non-zero value in case there were already some stray zeros in there. You could use memset(msg, A_NON_ZERO_VALUE, MSG_SIZE).
But maybe get rid of the idea of searching for a zero byte and instead accumulate the number of bytes read:
Code:
#define BYTES_TO_READ 3
if((pid2=fork())==0){ // Process C
close(bc[1]);
while(1){
int nbytes = 0;
do {
int nb;
if ((nb = read(bc[0], &msg, BYTES_TO_READ - nbytes)) < 0)
goto break_outer_while; // hit EOF (or error) on pipe
nbytes += nb
}while (nbytes < BYTES_TO_READ);
sleep(1);
printf("C received %s from B\n", msg);
}
break_outer_while:
exit(1);
}
Also, you don't have to define all your pipes in the parent. Only log needs to be there. Process A could create ab and process B could create bc and bd. That way there won't be quite so many pipes floating about.
You should also post your code directly if you want more people to read it.