I'm trying to capture the stderr from a process which is being called by execv(). Instead, however, it seems to be writing to a descriptor that isn't even opened in this process. The short description of what I'm trying to do is I'm first creating a pipe. Then through clever use of close() and dup() I'm making the write end of the pipe STDERR_FILENO (which is 2, I believe). Then I'm calling fork() and in the child I'm calling execv(). However, the output from this process is going to the original STDERR_FILENO, not the pipe!
A longer explanation follows:
First, in my process I'm changing the stderr descriptor to a file
Code:
close(STDERR_FILENO);
int des = open("stderr.txt", "wt");
assert(des == STDERR_FILENO);//trust me, it works
Then later in my program:
Code:
int fds[2];
pipe(fds);
int desBackupStderr = dup(STDERR_FILENO);//this is now a stderr
close(STDERR_FILENO);
int desPipeWrite = dup(fds[1]);
assert(desPipeWrite == STDERR_FILENO);//trust me
switch(fork()) {
case 0://child
close(desBackupStderr);//this process no longer has ANY descriptor open to the file stderr.txt
CaptureLSOF();//this captures lsof -p getpid() to a file, which proves the above axiom
const char *p = "this should make it to the read-end of the pipe";
write(STDERR_FILENO, p, strlen(p));//this did make it into the pipe!
execv(blah, bLah);
assert(false);//never happens
default://parent
close(STDERR_FILENO);//closing write end of the pipe in the parent
int des = dup(desBackupStderr);
assert(des == STDERR_FILENO);//trust me
}
Of course, I also close unnecessary duplicate descriptors for tidiness, but I left that out of here for simplicity. What I find hard to understand is that the call to execv() has writes to the stderr going to the file stderr.txt, even though the file written by CaptureLSOF() proves that that process does not have anything open to that file. The code also proves that writes to STDERR_FILENO do make it into the pipe. It's as if the program called by execv() gets a hold the descriptor to stderr.txt through the group process id, or the parent process id? I dunno, I'm grasping at straws.
FWIW, the program execv() is calling is sendmail (a la Postfix). I don't know what difference that could make.
Edit - It is also worth pointing out that I have another pipe opened, whose read end is connected to the stdin of the child process. Everything I write to the pipe from the parent does make it to the stdin of the child process.