]> arthur.barton.de Git - bup.git/commitdiff
log(): handle situations where stderr gets set to nonblocking.
authorAvery Pennarun <apenwarr@gmail.com>
Wed, 3 Mar 2010 04:18:49 +0000 (23:18 -0500)
committerAvery Pennarun <apenwarr@gmail.com>
Wed, 3 Mar 2010 04:19:59 +0000 (23:19 -0500)
It's probably ssh doing this, and in obscure situations, it means log() ends
up throwing an exception and aborting the program.

Fix it so that we handle EAGAIN correctly if we get it when writing to
stderr, even though this is only really necessary due to stupidity on
(I think/hope) someone else's part.

lib/bup/helpers.py

index 75cf09cb240a4f8aa9d12b629855a3ed87d92b0e..0aa69458cd074247698b098b7f403b3551fdc081 100644 (file)
@@ -1,8 +1,25 @@
 import sys, os, pwd, subprocess, errno, socket, select, mmap, stat, re
 
 
+# Write (blockingly) to sockets that may or may not be in blocking mode.
+# We need this because our stderr is sometimes eaten by subprocesses
+# (probably ssh) that sometimes make it nonblocking, if only temporarily,
+# leading to race conditions.  Ick.  We'll do it the hard way.
+def _hard_write(fd, buf):
+    while buf:
+        (r,w,x) = select.select([], [fd], [], None)
+        if not w:
+            raise IOError('select(fd) returned without being writable')
+        try:
+            sz = os.write(fd, buf)
+        except OSError, e:
+            if e.errno != errno.EAGAIN:
+                raise
+        assert(sz >= 0)
+        buf = buf[sz:]
+
 def log(s):
-    sys.stderr.write(s)
+    _hard_write(sys.stderr.fileno(), s)
 
 
 def mkdirp(d):