[issue11466] getpass.getpass doesn't close tty file

Steffen Daode Nurpmeso report at bugs.python.org
Sat Mar 12 16:34:47 CET 2011


Steffen Daode Nurpmeso <sdaoden at googlemail.com> added the comment:

This patch makes getpass.getpass() comply with the documented 
behaviour and fixes #11466. 
It will require no further adjustments for #11236 (except what 
valhallasw's patch does, of course). 
It applies cleanly to:

16:32 ~/src/cpython $ hg identify
ee259a4f3eee tip

----------
Added file: http://bugs.python.org/file21093/11466.3.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue11466>
_______________________________________
-------------- next part --------------
diff --git a/Lib/getpass.py b/Lib/getpass.py
--- a/Lib/getpass.py
+++ b/Lib/getpass.py
@@ -38,27 +38,28 @@
 
     Always restores terminal settings before returning.
     """
-    fd = None
     tty = None
-    try:
-        # Always try reading and writing directly on the tty first.
-        fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
-        tty = os.fdopen(fd, 'w+', 1)
-        input = tty
-        if not stream:
-            stream = tty
-    except EnvironmentError as e:
-        # If that fails, see if stdin can be controlled.
+    exinst = None
+    passwd = None
+    # Something to break off if an error happens
+    while 1:
         try:
-            fd = sys.stdin.fileno()
-        except (AttributeError, ValueError):
-            passwd = fallback_getpass(prompt, stream)
-        input = sys.stdin
-        if not stream:
-            stream = sys.stderr
+            # Always try reading and writing directly on the tty first.
+            fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
+            input = tty = os.fdopen(fd, 'w+', 1)
+            if not stream:
+                stream = tty
+        except EnvironmentError as e:
+            # If that fails, see if stdin can be controlled.
+            try:
+                fd = sys.stdin.fileno()
+            except:
+                # We need to use the generic fallback implementation
+                break
+            if not stream:
+                stream = sys.stderr
+            input = sys.stdin
 
-    if fd is not None:
-        passwd = None
         try:
             old = termios.tcgetattr(fd)     # a copy to save
             new = old[:]
@@ -69,20 +70,28 @@
             try:
                 termios.tcsetattr(fd, tcsetattr_flags, new)
                 passwd = _raw_input(prompt, stream, input=input)
-            finally:
-                termios.tcsetattr(fd, tcsetattr_flags, old)
-                stream.flush()  # issue7208
+            except Exception as e:
+                exinst = e
+            termios.tcsetattr(fd, tcsetattr_flags, old)
         except termios.error as e:
             if passwd is not None:
                 # _raw_input succeeded.  The final tcsetattr failed.  Reraise
                 # instead of leaving the terminal in an unknown state.
-                raise
-            # We can't control the tty or stdin.  Give up and use normal IO.
-            # fallback_getpass() raises an appropriate warning.
-            del input, tty  # clean up unused file objects before blocking
-            passwd = fallback_getpass(prompt, stream)
+                exinst = e
+        break
 
-    stream.write('\n')
+    if not exinst and passwd is None:
+        # We can't control the tty or stdin. Give up and use normal IO.
+        # fallback_getpass() raises an appropriate warning.
+        passwd = fallback_getpass(prompt, stream)
+
+    if stream:
+        stream.write('\n')
+        stream.flush() # issue7208, 7246
+    if tty:
+        tty.close()
+    if exinst:
+        raise exinst
     return passwd
 
 


More information about the Python-bugs-list mailing list