As @Barmar said in the comments, there is no built-in property to check if the child process is about to read from the pipe. Even standard terminals allow input during process execution. So when I run the following code, I can enter text that is as not being processed by the child process, the shell tries to execute after process termination.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[2], b[2], child_read, child_write;
char output[4] = {0};
pipe(a);
pipe(b);
child_write = a[1];
child_read = b[0];
FILE *parent_write = fdopen(b[1], "w");
FILE *parent_read = fdopen(a[0], "r");
if (fork() == 0) {
close(b[1]);
close(a[0]);
fclose(parent_read);
fclose(parent_write);
dup2(child_read, STDIN_FILENO);
dup2(child_write, STDOUT_FILENO);
sleep(3);
printf("ok\n");
close(child_read);
close(child_write);
exit(0);
}
close(child_read);
close(child_write);
if (fread(output, 1, 3, parent_read) > 0) {
printf("%s\n", output);
}
fclose(parent_read);
fclose(parent_write);
close(b[1]);
close(a[0]);
}
$ gcc -o test test.c ; ./test
ls
ok
$ ls
test test.c