-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 According to Corinna Vinschen on 2/16/2008 2:52 AM: | /dev/stdout is nothing special for Cygwin. /dev/stdout is just a | symlink pointing to /proc/self/fd/1. /proc/self is just a symlink to | /proc/<pid>.
This part's just fine (same as on Linux). | /proc/<pid>/fd/1 is just a symlink to the file opened | in this process using fd 1. I think that's where the difference lies. On Linux, open("/proc/<pid>/fd/1",O_WRONLY) behaves like dup(1) - now both fd 1 and fd 3 share the same handle. At which point, calling dup2(3,1) closes one of the copies, but fd 3 is not invalidated, so the handle remains alive. But on cygwin, the open creates a new handle via a symbolic name (or fails outright on some inherited handles); if the underlying handle was a regular file, this is virtually the same, but if the underlying handle was special, such as a pipe, it is acting up. Consider running the attached file, which uses dup(1) if there were no arguments, and open("/dev/stdout",O_WRONLY) if there are: $ gcc -o foo foo.c $ ./foo hi $ ./foo 1 hi $ # ok, so the current pty is correctly duplicated $ rm -f f && ./foo > f && cat f hi $ rm -f f && ./foo 1 > f && cat f hi $ # ok, so a disk file is correctly duplicated $ ./foo | cat hi $ ./foo 1 | cat failed to write to new stdout, 9 $ # hmm, duplicating the pipe had problems $ rm -f f && strace -o f ./foo hi $ rm -f f && strace -o f ./foo 1 failed to write to new stdout, 9 $ # hmm, strace was unable to duplicate the pty, which kind $ # of makes sense, since strace is a pure windows program Snippets of that strace include: ~ 42 27150 [main] foo 3448 fhandler_process::exists: exists (/proc/3448/fd/pipe:[1504]) ... ~ 51 27276 [main] foo 3448 fhandler_base::dup: in fhandler_base dup ... ~ 30 27402 [main] foo 3448 open: 3 = open (/dev/stdout, 0x1) ~ 31 27433 [main] foo 3448 dtable::dup2: dup2 (3, 1) ... ~ 29 27642 [main] foo 3448 fhandler_pipe::dup: res 0 ~ 30 27672 [main] foo 3448 dtable::dup_worker: duped '/proc/3448/fd/pipe:[1504]' old 0x6F4, new 0x6F0 ... ~ 34 27770 [main] foo 3448 fhandler_base::close: closing '' handle 0x5E0 ~ 33 27803 [main] foo 3448 close: 0 = close (1) ~ 30 27833 [main] foo 3448 dtable::dup2: 1 = dup2 (3, 1) ... ~ 56 28343 [main] foo 3448 fhandler_base::write: binary write ~ 58 28401 [main] foo 3448 sig_send: sendsig 0x708, pid 3448, signal - -34, its_me 1 ~ 613 29014 [main] foo 3448 sig_send: wakeup 0x5E0 The symlink was correctly resolved, and discovered the pipe, but fell back to fhandler_base::dup to do the duplication. At any rate, the open succeeded, but fd 3 is now tied to a symbolic name (/proc/3448/fd/pipe:[1504] stands for handle 0x5e0). Then, in the dup2, handle 0x5e0 from fd 1 is closed before overlaying fd 3 onto fd 1. Finally, the write tries to access the pipe via fd 1, and sends a wakeup to the original handle 0x5e0, based on the symbolic name associated with fd 3 (now fd 1) - oops; that was the handle that dup already closed. Also interesting is: $ rm -f f f1 && strace -o f1 ./foo > f && cat f hi $ rm -f f f1 && strace -o f1 ./foo 1 > f && cat f failed to open /dev/stdout, 2 failed to write to new stdout, 9 hi Here, the strace inherits an open handle to f, but does not know which file it came from, so it gives up with ENOENT rather than successfully creating fd 3. But since strace is obviously able to dup open handles to unknown files, it would seem that open(/proc/self/fd/1) to an unknown file handle should work as well. | It's not even clear anymore, that this file is an open file in *this* | very process. | | How is Cygwin supposed to know that it is a symlink with a special | meaning? Do you think that Cygwin should test every file on every open | to be "/dev/stdout"? Not /dev/stdout, per se, but /proc/<pid>/fd/n. But since /proc is already a special device (via fhandler_proc), it seems like such special handling should already be happening. Maybe it's just a matter of writing fhandler_proc::dup, or making fhandler_proc::open go through the dup machinery. - -- Don't work too hard, make some time for fun as well! Eric Blake [EMAIL PROTECTED] -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.5 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFHtuKz84KuGfSFAYARAuiBAJ9OvbQkE8eTElLBMqFVbZ1VCijgxwCfWLOi rlUWQX5B+WxYXogMj2JqnD4= =nbpE -----END PGP SIGNATURE-----
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <fcntl.h> int main (int argc, char* argv[]) { int f; if (argc > 1) { f = open ("/dev/stdout", O_WRONLY); if (f < 0) fprintf (stderr, "failed to open /dev/stdout, %d\n", errno); } else { f = dup (1); if (f < 0) fprintf (stderr, "failed to dup stdout, %d\n", errno); } f = dup2 (f, 1); if (f < 0) fprintf (stderr, "failed to dup2 back to stdout, %d\n", errno); f = write (1, "hi\n", 3); if (f < 3) fprintf (stderr, "failed to write to new stdout, %d\n", errno); return 0; }
-- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/