1.5.25-7 piping directed output to /dev/stdout will not work

Eric Blake ebb9@byu.net
Fri Feb 15 16:17:00 GMT 2008


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Leutwein Tobias (BEG-PG/EES) on 2/14/2008 11:51 PM:
| Since I updated to 1.5.25 piping directed output to /dev/stdout with
| bash 3.2.33-18 will not work.

Updated from what prior version?

|
|> echo "test string" > /dev/stdout | wc -w
| v:\Programme\cygwin\current\bin\bash: echo: write error: Bad file
| descriptor
| 0

Hmm.  The error message does not list a POSIX-style path to bash.  Is this
started directly under cmd.exe?  At any rate, you've told bash to do the
following:

create a pipe, connecting echo's stdout to wc's stdin
within echo, open /dev/stdout at the next available fd (3), as a clone of fd 1
call dup2(3,1), which closes 1 then moves 3 in its place

And it looks like what cygwin is doing is closing the handle owned by fd
1, so that the handle owned by fd 3 is invalid before it is reassociated
with fd 1, explaining the bad fd write error.

True - on some Unix systems, /dev/stdout is a device rather than a
symlink, and as such, the OS goes to great pains to keep the original fd 1
when going through the name /dev/stdout.  And I'm not sure that this
problem is cygwin specific.  At any rate, it does not violate POSIX - you
are in the realm of unportable behavior when you rely on /proc (or on
/dev/stdout).

On the other hand, this behavior is indeed different than what Linux
provides.  I tested the same scenario on Linux, and it appears to special
case dup2 when moving the cloned fd back on top of the original, the
underlying handle is not invalidated.  Which means that the bug might lie
in cygwin1.dll and not in bash.

On the other hand, the following C program behaves correctly when
simulating the same sequence of actions (although it avoids the unportable
use of /proc).  I'll have to investigate further to prove where the blame
lies, but right now, it seems that it is in cygwin, for not treating
open("/proc/self/fd/1") as equivalent to dup(1).

#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 = 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;
}

- --
Don't work too hard, make some time for fun as well!

Eric Blake             ebb9@byu.net
-----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

iD8DBQFHtZsQ84KuGfSFAYARAilqAKDH8L/CB4YgluYp4vEHZpU8Qvc0HACgzf9I
daCIJwWfA7gZjE9ImKwrSRA=
=I6rF
-----END PGP SIGNATURE-----

--
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/



More information about the Cygwin mailing list