APUE says
fd = open("/dev/fd/0", mode);
is equivalent to fd = dup (0);
, and mode
is completely ignored. It seems this is the case in Solaris, but wrong in Linux. (I don’t have access to other Unices at this moment.)A test program:
01 #include <unistd.h> 02 #include <fcntl.h> 03 04 int main () 05 { 06 close (0); 07 printf ("%d\n", open ("a.txt", O_RDONLY)); // Should be 0 08 //int f2 = open ("/dev/fd/0", O_WRONLY); 09 int f2 = dup(0); 10 printf ("%d\n", f2); 11 write (f2, "Hello world\n", 12); 12 return 0; 13 }
Let’s run the program with an empty
a.txt
. Certainly the write
function in Line 11 is going to fail.Now, let’s comment out Line 9 and uncomment line 8 and try it again.
First I ran it in Solaris, the
write
call still failed. The behavior is like what APUE tells us.Try it again in Linux - It was successful!
It seems that in Linux,
/dev/fd/0
is considered by open
as nothing but a normal symlink to a.txt
. So it returns a completely new descriptor instead of a duplicate of the old.Let’s try it again with a shell script:
rm -f a.txt touch a.txt exec 0<a.txt exec 3>/dev/fd/0 echo 'Hello world' >&3 cat a.txt
Run it in Linux (with DASH or BASH): Both outputed ‘Hello world’.
Run it in Solaris (with Bourne shell and BASH): Both failed, outputting nothing (Bourne shell) or failing with ‘Bad file number’ (BASH).
Conclusion:
(1) Solaris handles
/dev/fd/..
specially, as APUE tells us;(2) Linux simply consider
/dev/fd/0
a symlink to the actual file.(I’ll try later how Linux handles
open("/dev/fd/0",mode)
if the descriptor is an anonymous pipe or socket or something else that a normal symlink is unable to link to.Kernels used in the above tests:
Linux:
Linux desktop 2.6.28-gentoo #4 SMP Mon Jan 12 17:39:23 CST 2009 x86_64 Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz GenuineIntel GNU/Linux
Solaris:
SunOS caesar 5.8 Generic_117350-51 sun4u sparc SUNW,Ultra-80 Solaris
try opening /proc/PID/fd/FD
ReplyDelete