delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2008/02/16/08:18:40

X-Recipient: archive-cygwin AT delorie DOT com
X-Spam-Check-By: sourceware.org
X-Authority-Analysis: v=1.0 c=1 a=NgUlfERH4W8A:10 a=xe8BsctaAAAA:8 a=Z9aqXrEEam2A-1Q7ltMA:9 a=bZMz-rKxGhunYayeStYA:7 a=p6I22-JYcwO820mK8YksdkGsZ6QA:4 a=eDFNAWYWrCwA:10 a=rPt6xJ-oxjAA:10 a=tKd_e3Mjn0G4LscsO_gA:9 a=0th8VvegpUzhaCNGlgxjfEaHroMA:4 a=Hh7NdPsCZosA:10
Message-ID: <47B6E2B3.9010701@byu.net>
Date: Sat, 16 Feb 2008 06:18:43 -0700
From: Eric Blake <ebb9 AT byu DOT net>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.666
MIME-Version: 1.0
To: cygwin AT cygwin DOT com
Subject: Re: AW: 1.5.25-7 piping directed output to /dev/stdout will not work
References: <4971562D0CDBAE4A86212E08861E9C4F038D779E AT si-mail46 DOT de DOT bosch DOT com> <47B59B10 DOT 5090105 AT byu DOT net> <4971562D0CDBAE4A86212E08861E9C4F038D77A3 AT si-mail46 DOT de DOT bosch DOT com> <47B66A3F DOT 4030804 AT byu DOT net> <20080216095212 DOT GA9304 AT calimero DOT vinschen DOT de>
In-Reply-To: <20080216095212.GA9304@calimero.vinschen.de>
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

--------------060803070502000906050105
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

-----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             ebb9 AT byu DOT 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

iD8DBQFHtuKz84KuGfSFAYARAuiBAJ9OvbQkE8eTElLBMqFVbZ1VCijgxwCfWLOi
rlUWQX5B+WxYXogMj2JqnD4=
=nbpE
-----END PGP SIGNATURE-----

--------------060803070502000906050105
Content-Type: text/plain;
 name="foo.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="foo.c"

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


--------------060803070502000906050105
Content-Type: text/plain; charset=us-ascii

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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019