I have to write program in C (Unix) which captures stdin, stdout and stderr of command passed in command line arguments.
For example,
./capture echo Hi
== stdout ===
Hi
== end of stdout ==
./capture bc -q
== stdin ==
1+2
== end of stdin ==
== stdout ==
3
== end of stdout ==
I've already implemented such behaviour for stdout and stderr:
int pipe_out[2];
int pipe_in[2];
int finished = 0;
void sig_handler(int signo)
{
if (signo == SIGCHLD)
{
finished = 1;
wait(NULL);
}
}
void ChildProcess (char * argv[], char * env[])
{
dup2(pipe_out[1], 1);
dup2(pipe_out[1], 2);
dup2(pipe_in[0], 0);
close(pipe_out[0]);
close(pipe_out[1]);
close(pipe_in[0]);
close(pipe_in[1]);
int return_code = execvpe(argv[0], argv, env);
printf("This should not appear: %d\n", return_code);
printf("Error: %s\n\n", strerror(errno));
}
void ParentProcess(pid_t pid)
{
int status;
char buf[10000];
fd_set out_fds;
fd_set in_fds;
signal(SIGCHLD, sig_handler);
do
{
FD_ZERO(&out_fds);
FD_ZERO(&in_fds);
FD_SET(pipe_in[1], &in_fds);
FD_SET(pipe_out[0], &out_fds);
int cnt = select(max(pipe_out[0], pipe_out[0]) + 1, &out_fds, NULL, NULL, NULL);
if (cnt > 0 && FD_ISSET(pipe_out[0], &out_fds))
{
puts("== stdout ==");
read(pipe_out[0], buf, sizeof(buf));
printf("%s", buf);
puts("== end of stdout == ");
continue;
}
if (0 && FD_ISSET(pipe_in[1], &in_fds))
{
puts("== stdin ==");
write(pipe_in[1], "1+2\n", sizeof("1+2\n"));
puts("== end of stdin ==");
continue;
}
} while (!finished);
}
As far as I understand it works in this way: parent process call select() and wait for output of child process. After that parent process prints additional information (== stdout ==) and child's output.
When I try implement same behaviour for stdin I see that in_fds
always ready independent on what child process need. So capture
always reads from stdin. Even when child process need output something.
So my question is how to implement such behaviour?
I think there must be a special signal which indicates when child process needs some input, but I can't find anything.