Search code examples
ciofork

To which file descriptor execve redirect?


int main (void) {

   int rc=fork();
   if(rc==0){
   close(1); //close stdout BEFORE opening my file
   open("./c.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);


   //execve "wc"
   char *cmd[3];
   cmd[0] = strdup("wc"); //file to execuable
   cmd[1]=strdup("c.c"); //first arg to command 'wc' -> c.c
   cmd[2]=NULL;

   execvp(cmd[0], cmd);
   }

If I close() stdout, then the output of execve ("wc"), will be in file c.txt but ONLY if I close stdout BEFORE open()ing. If I call it AFTER

open("./c.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
   close(1); 

then -> wc: write error: Bad file descriptor.

I have read, that for open() (probably in my case for wc output) is OS reaching file descriptor from 0, and so it first find 1 as stdout to printf() to screen. So I need to close() it, in order to use file descriptor from open("./c.txt") for wc. But If that is correct (I do not know where I have understood it correctly), then it would not matter whether I close stdout before or after open() call, does it? Once it is closed, OS has no other FD to use as output. I maybe does not understand it clearly.

question: why must be fd1 closed first in order to make redirection to c.txt?


Solution

  • A few concepts to establish first.

    1. stdout is one of the streams automatically opened as part of program startup. The program startup code uses file descriptor 1 for stdout).
    2. execve creates a new process with the same open file descriptors as the parent/calling process (there are exceptions and naunces which can be read from the execve man page.
    3. open will look for the lowest available file descriptor to use.

    Ok, so now to your code.

    Case 1 - close, open, execve

    In this case the following sequence of events happens:

    1. Program starts with stdout=>fd 1.
    2. close(1) makes fd 1 available.
    3. open("c.txt") returns 1 which effectively redirects stdout to the file.
    4. execve creates a new process which has 1 open and redirected to the file.
    5. wc writes to fd 1 which now ends up in the file.

    Case 2 - open,close,execve

    In this case the following sequence of events happens:

    1. Program starts with stdout=>fd 1.
    2. open("c.txt")is called but fd 1 is not available so it returns 2.
    3. close(1) means there is now effectively no stdout.
    4. execve creates a new process which has no open stream on fd 1 (ie no stdout).
    5. wc tries to write to fd 1 and gets a bad file descriptor error since fd 1 is not open.