When we open /dev/fd/n
, we are not "duplicating" a file descriptor. We are opening a brand new file.
You may be confusing this with using dup
. Since we know the binary value of n
, we could do: int fdn = dup(n);
. That would share things.
But, that is not what we're doing.
/dev/fd
is a symlink to /proc/self/fd
. If we do ls -l /proc/self/fd > /tmp/out
, we'll get something like:
total 0
lrwx------. 1 cae cae 64 Nov 7 00:16 0 -> /dev/pts/2
l-wx------. 1 cae cae 64 Nov 7 00:16 1 -> /tmp/out
lrwx------. 1 cae cae 64 Nov 7 00:16 2 -> /dev/pts/2
lr-x------. 1 cae cae 64 Nov 7 00:16 3 -> /proc/35153/fd
If we do:
fd = open("/proc/self/0",O_WRONLY);
this is identical to doing:
fd2 = open("/dev/pts/2",O_WRONLY);
fd
and fd2
do not share any flags/modes, etc. They are completely separate. Nor do they have any common flags/modes with fd 0.
Note that I deliberately specified /proc/self/0
[which is open for reading] and, yet, we opened it for writing.
It does not care about [nor use] the original descriptors flags, etc. Once again, it is just a "double level" symlink to the full path of the final target file: /dev/pts/2
It is the file permissions of the target file that dictate whether a given open
is allowed (e.g. if the permissions were 0444, and we tried to open with O_WRONLY
, that would return EPERM
).
This would be no different than if we had a directory that looked like:
total 0
-rw-r--r--. 1 cae cae 0 Nov 7 00:29 a
lrwxrwxrwx. 1 cae cae 1 Nov 7 00:29 b -> a
lrwxrwxrwx. 1 cae cae 1 Nov 7 00:29 c -> a
lrwxrwxrwx. 1 cae cae 1 Nov 7 00:29 d -> c
We could do:
int fd1 = open("a",O_RDONLY);
int fd2 = open("b",O_WRONLY);
int fd3 = open("c",O_WRONLY);
int fd4 = open("d",O_WRONLY);
Those four file descriptors don't share anything. But, they are four separate streams to the same file. So, if we write to any of fd2
, fd3
, or fd4
. Then, read from fd1
and we'll see the effect.