[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Bug with svn+ssh (plus workaround)

From: Alan Barrett <apb_at_cequrux.com>
Date: 2006-03-21 16:24:13 CET

I found a horrible interaction between subversion and ssh.

This works:

        svn log svn+ssh://host/repo/trunk | less

This doesn't work:

        svn log svn+ssh://host/repo/trunk 2>&1 | less

The symptom is that the output is truncated after the first few
kilobytes.

The underlying cause is this sequence of events:

1. The shell runs "svn" in such a way that both fd 1 (stdout) and fd 2
   (stderr) are connected to a pipe which goes to "less".

2. svn runs ssh, in such a way that ssh's fd 0 (stdin) and fd 1
   (stdout) are connected to pipes controlled by svn, but ssh's fd 2
   (stderr) is still connected to the pipe that goes to "less". In
   other words, all three of svn's fd 1 (stdout), svn's fd 2 (stderr),
   and ssh's fd 2 (stderr) are connected to the same place.

3. ssh puts its stderr into non-blocking mode. Because ssh's stderr
   and svn's stdout and stderr all go to the same place, this
   accidentally puts svn's stdout and stderr into non-blocking mode.

4. After a while, svn starts writing to stdout. The first few writes
   work fine. But after a few kilobytes, a write attempt gets an
   EAGAIN error (a.k.a. EWOULDBLOCK). The pipe is full and the write
   would have to block until "less" drains some data from the other
   end of the pipe; but the file descriptor is in non-blocking mode,
   so the write gets an error instead of blocking.

5. svn gives up. It tries to write an error message to stderr, but
   that also encounters an EAGAIN/EWOULDBLOCK error.

As a workaround, I pointed the SVN_SSH environment variable to this
script, and everything worked correctly:

    #!/bin/sh
    # Run ssh in such a way that a pipe through a "cat" process is
    # interposed between the inner fd 2 (stderr) seen by the ssh
    # command, and the outer fd 2 (stderr) seen by our caller (which
    # is typically "svn"). This insulates the outer fd 2 from ssh's
    # habit of putting the inner fd 2 into non-blocking mode.
    PATH=/bin:/usr/bin
    REAL_SSH=/usr/bin/ssh
    exec 4>&1
    exec "${REAL_SSH}" ${1+"$@"} 1>&4 2>&1 4>&- | cat 1>&2

As a fix, I suggest that svn should connect ssh's stdout to a pipe
that is managed by svn.

--apb (Alan Barrett)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Tue Mar 21 16:27:24 2006

This is an archived mail posted to the Subversion Dev mailing list.