AllenHu
AllenHu

Reputation: 601

Is it possible that linux file descriptor 0 1 2 not for stdin, stdout and stderr?

When a program begins, does it take file descriptors 0, 1 and 2 for stdin, stdout and stderr by default?. And will API calls such as open(...), socket(...) not return 0, 1 and 2 since these values are already taken?. Is there any case in which open(...) or socket(...) would return 0, 1 or 2. And 0, 1 and 2 are not related with stdin, stdout, and stderr.

Upvotes: 34

Views: 98844

Answers (3)

swayamraina
swayamraina

Reputation: 3158

Though a couple of answers already existed but I didn't find them informative enough that they explained the complete story.

Since I went ahead and researched more, I am adding my findings.

Whenever a process starts, an entry of the running process is added to the /proc/<pid> directory. This is the place where all of the data related to the process is kept. Also, on process start the kernel allocates 3 file-descriptors to the process for communication with the 3 data streams referred to as stdin, stdout and stderr.
the linux kernel uses an algorithm to always create a FD with the lowest possible integer value so these data-streams are mapped to the numbers 0, 1 and 2.

Since these are nothing but references to a stream and we can close a stream. One can easily call close(<fd>), in our case close(1), to close the file descriptor.

on doing ls -l /proc/<pid>/fd/, we see only 2 FDs listed there 0 and 2.
If we now do an open() call the kernel will create a new FD to map this new file reference and since kernel uses lowest integer first algorithm, it will pick up the integer value 1.

So now, the new FD created points to the file we opened (using the open() syscall)
Any of the data transfer that happens now is not via the default data-stream that was earlier linked but the new file that we opened.

So yes, we can map the FD 0, 1 or 2 to any of the file and not necessary stdin, stdout or stderr

Upvotes: 8

At the file descriptor level, stdin is defined to be file descriptor 0, stdout is defined to be file descriptor 1; and stderr is defined to be file descriptor 2. See this.

Even if your program -or the shell- changes (e.g. redirect with dup2(2)) what is file descriptor 0, it always stays stdin (since by definition STDIN_FILENO is 0).

So of course stdin could be a pipe or a socket or a file (not a terminal). You could test with isatty(3) if it is a tty, and/or use fstat(2) to get status information on it.

Syscalls like open(2) or pipe(2) or socket(2) may give e.g. STDIN_FILENO (i.e. 0) if that file descriptor is free (e.g. because it has been close(2)-d before). But when that occurs, it is still stdin by definition.

Of course, in stdio(3), the FILE stream stdin is a bit more complex. Your program could fclose(3), freopen(3), fdopen(3) ...

Probably the kernel sets stdin, stdout, and stderr file descriptors to the console when magically starting /sbin/init as the first process.

Upvotes: 42

Lee Duhem
Lee Duhem

Reputation: 15121

  1. When a program begins, does it take file descriptor 0 1 2 for stdin, stdout and stderr by default .

    If you launch your program in an interactive shell normally, yes.

    By @EJP:

    Inheriting a socket as FD 0 also happens if the program is started by inetd, or anything else that behaves the same way.

  2. will the API such as open(...), socket(...) not return 0 1 2 since these value are already be taken.

    Yes.

  3. Is there any case that open(...) or socket(...) would return 0 1 2.

    Yes, if you do something like

    close(0);
    close(1);
    close(2);
    open(...); /* this open will return 0 if success */
    

Upvotes: 4

Related Questions