Reputation: 601
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
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
Reputation: 1
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
Reputation: 15121
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.
will the API such as open(...), socket(...) not return 0 1 2 since these value are already be taken.
Yes.
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