I'm working on a system that communicates with child processes using pipes to stdin and stdout. The child processes use a api library to facilitate this communication and I need to write unit tests for the library. The only way that I could figure out how to properly test these functions is to replace stdin/stdout with pipes so that the tests can pretend to be the parent system when calling the functions.
/* replace stdin and stdout with pipes */
void setup(void) {
pipe(in_sub);
pipe(out_sub);
dup2(out_sub[1], fileno(stdout));
dup2( in_sub[0], fileno(stdin));
read_from = fdopen(out_sub[0], "rb");
write_to = fdopen( in_sub[1], "wb");
stdout_t = fopen("/dev/tty", "wb");
stdin_t = fopen("/dev/tty", "rb");
}
/* reopen stdin and stdout for future test suites */
void teardown(void) {
fclose(read_from);
fclose(write_to);
stdout = stdout_t;
stdin = stdin_t;
close(in_sub[0]);
close(in_sub[1]);
close(out_sub[0]);
close(out_sub[1]);
}
I have tried just saving stdin and stdout in temps and using fdopen() on them (should work because they are FILE*) but this doesn't result in things being correctly written to the pipe. This code does work perfectly when being run directly from the host's shell. The problem occurs when running over ssh. The unit tests execute perfectly, but when I go to write anything to stdout after this test suite, I receive a broken pipe error.
What can I do that avoids using the dup2 so that stdin and stdout never get closed, or how can I reopen stdin and stdout such that they will correctly work in the shell and over ssh?
The stdin, stdout is just FILE* pointing to a struct (object) which internally have their fd set to 0 (and 1). Hence when you do the dup2, the file 0 and 1 no longer work. What you need to do is to create a new file object from scratch before doing the dup2, so this may be all the modification you need;
void setup(void) {
int dupin, dupout;
dupin = dup(0); // Create an extra fd to stdin
dupout = dup(1); // create an extra fd to stdout
pipe(in_sub);
pipe(out_sub);
dup2(out_sub[1], fileno(stdout));
dup2( in_sub[0], fileno(stdin));
read_from = fdopen(out_sub[0], "rb");
write_to = fdopen( in_sub[1], "wb");
stdout_t = fdopen(dupout, "wb");
stdin_t = fdopen(dupin, "rb");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With