I need to count how many bytes are being sent to a child process through stdin, and how many bytes a child process is writing to stdout and stderr. The child process calls execvp, so I have no way to monitor those stats from within the process itself. My current tactic involves creating 3 additional child processes, one each to monitor each of the std streams through pipes (or in the case of stdin, just reading from stdin).
This tactic seems really frail at best, and I’m doing something strange which makes it so that the processes monitoring stdout/err cannot read from their respective ends of the pipes (and makes them hang indefinitely). Code below.
This creates the three helper child processes, and should allow them to count the stats:
void controles(struct fds *des)
{
int ex[2];
int err[2];
int n_in = 0;
int c_in;
int n_ex = 0;
int c_ex;
int n_err = 0;
int c_err;
pipe(ex);
pipe(err);
/*has two fields, for the write end of the stdout pipe and the stderr pipe. */
des->err = err[1];
des->ex = ex[1];
switch (fork()) {
case 0: /*stdin */
while (read(0, &c_in, 1) == 1)
n_in++;
if (n_in > 0)
printf("%d bytes to stdin\n", n_in);
exit(n_in);
default:
break;
}
switch (fork()) {
case 0: /*stdout */
close(ex[1]);
/*pretty sure this is wrong */
while (read(ex[0], &c_ex, 1) == 1) {
n_ex++;
write(1, &c_ex, 1);
}
if (n_ex > 0)
printf("%d bytes to stdout\n", n_ex);
close(ex[0]);
exit(n_ex);
default:
close(ex[0]);
}
switch (fork()) {
case 0: /*error */
close(err[1]);
/*also probably have a problem here */
while (read(err[0], &c_err, 1) == 1) {
n_err++;
write(2, &c_err, 1);
}
if (n_err > 0)
printf("%d bytes to stderr\n", n_err);
close(err[0]);
exit(n_err);
default:
close(err[0]);
}
}
and this is a code fragment (within the child process) which sets up the two fd’s from the fds struct so that the child process should write to the pipe instead of stdin/stderr.
dup2(des.ex, 1);
dup2(des.err, 2);
close(des.ex); close(des.err); /*Is this right?*/
execvp(opts->exec, opts->options); /*sure this is working fine*/
I’m lost, any help would be appreciated.
I think your code could be improved by breaking things apart a little; the accounting and copying routines are all basically the same task, and if you choose to continue down the road with multiple processes, can be written simply:
Rather than one-char-at-a-time, which is inefficient for moderate amounts of data, we can handle partial writes with the
writen()function from the Advanced Programming in the Unix Environment source code:With the helper in place, I think the rest can go more easily. Fork a
new child for each stream, and give the
in[0]read-end,out[1]anderr[1]write-ends of the pipes to the child.All those
close()calls in each child are pretty ugly, but trying towrite a little wrapper around an array of all the fds, and exempting the
ones passed in as arguments, also seems like trouble.
It seems to work for toy applications anyway 🙂
I think it is worth pointing out that you could also implement this
program with only one process, and use
select(2)to determine whichfile descriptors need reading and writing.