views:

42

answers:

3

Hi,

On Linux, I have some C++ code where I want to execv another application. That program outputs some data to the stderr. I therefore redirect the stderr by calling freopen() with stderr as the stream parameter. The thing is, I want to redirect the stderr for another process that is run.

Here is the scenario I am working with. I fork() the current process; in the child process, I redirect the stderr; then I execv() to run the separate application.

Firstly, I have a Sentry set up to redirect the stderr output. Here is the code:

class StderrSentry {
public:
  StderrSentry() {
    freopen( "NUL", "wt", stderr );
  }
  ~StderrSentry() {
    fclose( stderr );
  }
};

Then later in the code:

pid_t pid = fork();
int retval=-1;

if( pid < 0 ) {
  success = false;
}
else if( ! pid ) {  // child process
  StderrSentry stdErrSentry;   // REDIRECTING STDERR HERE!
  pid_t chid = setsid();
  if (chid == -1 ) {
    exit(-1);
  }
  else {
    //  HERE IS THE execv() call:
    if( execv(command[0].c_str(), const_cast<char**>(&c_args[0])) < 0 ) {
      exit( -1 );
    }
  }
}
// ... else etc...

Will the stderr redirect actually still technically be valid once the execv() call replaces the current process with the specified one?

This is actually behaving as I desire, but is it a fluke, or is this the way to do it?

I cannot activate the stderr redirect in the application that is run in the execv, since it is not my code.

Thanks for any info on this.

A: 

The redirection is very much valid. The execv call changes the process image, but the file descriptors remain untouched.

Kedar Soparkar
Thanks for all the answers from everyone - they could all be marked as 'the answer'. This helps me to be confident in this code, since it is to be released shortly. Thanks again.
Raymond
+2  A: 

It is generally safer to do this sort of thing with the OS primitives operating on file descriptors (open, close, dup2) than with freopen and friends, but yes, this is supposed to work, and is how shell pipelines are implemented. execve leaves all open files open, unless they have been marked F_CLOEXEC.

Zack
A: 

If the file descriptors don't have the O_CLOEXEC flag (see man 2 open), they should persist across exec. This flag is only available in kernel 2.6.23 and later, so if you're using an older distribution, it won't be available.

Chris
O_CLOEXEC as an open(2) flag is relatively new, but `fcntl(fd, F_SETFD, FD_CLOEXEC)` has been around for aeons.
Zack
I'm pretty sure our distributions are pretty well up to date, but I'm not using the flag anyway, and as I said, it works. I just wanted to be certain that the code made sense.
Raymond