[issue11466] getpass.getpass doesn't close tty file
Steffen Daode Nurpmeso
report at bugs.python.org
Sat Mar 19 23:40:58 CET 2011
Steffen Daode Nurpmeso <sdaoden at googlemail.com> added the comment:
On Sat, Mar 19, 2011 at 01:29:28PM +0000, Ãric Araujo wrote:
> Itâs a private function, if that makes the patch smaller letâs change it.
The promised 11466.5.patch. It:
- Fixes #11466 resource warning.
- Fixes bogus newline which would have been written before
in case the fallback implementation needs to be used.
+ _raw_input() has been renamed to _user_input() because that
is what it actually does (wether it's raw depends on caller).
It will now encapsulate the complete user prompting,
thus including the mentioned final newline.
- Allows patch-in of #11236 patch without any further
adjustments (i.e. no additional catch of another resource
warning necessary).
- It cleans up the control flow and the comments a bit which
i think was the reason that the first two items above could
actually become introduced in the code at all.
But - it's even larger than 11466.4.patch!
----------
Added file: http://bugs.python.org/file21297/11466.5.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,25 @@
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.
+ tty, exinst, passwd = None, None, 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:
+ # If that fails, see if stdin can be controlled;
+ # use generic fallback implementation as last resort
+ try:
+ fd = sys.stdin.fileno()
+ except:
+ break
+ if not stream:
+ stream = sys.stderr
- if fd is not None:
- passwd = None
try:
old = termios.tcgetattr(fd) # a copy to save
new = old[:]
@@ -68,21 +66,29 @@
tcsetattr_flags |= termios.TCSASOFT
try:
termios.tcsetattr(fd, tcsetattr_flags, new)
- passwd = _raw_input(prompt, stream, input=input)
+ passwd = _user_input(prompt, stream, input=input, echooff=True)
+ except Exception as e:
+ exinst = e
finally:
termios.tcsetattr(fd, tcsetattr_flags, old)
- stream.flush() # issue7208
- except termios.error as e:
+ stream.flush() # issue7208 (7246)
+ except Exception 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)
+ # _user_input succeeded, but the final tcsetattr failed.
+ # Reraise the termios.error instead of leaving the terminal
+ # in an unknown state.
+ 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 tty:
+ tty.close()
+ if exinst:
+ raise exinst
return passwd
@@ -115,10 +121,10 @@
if not stream:
stream = sys.stderr
print("Warning: Password input may be echoed.", file=stream)
- return _raw_input(prompt, stream)
+ return _user_input(prompt, stream, input=None, echooff=False)
-def _raw_input(prompt="", stream=None, input=None):
+def _user_input(prompt, stream, input=None, echooff=False):
# This doesn't save the string in the GNU readline history.
if not stream:
stream = sys.stderr
@@ -130,6 +136,8 @@
stream.flush()
# NOTE: The Python C API calls flockfile() (and unlock) during readline.
line = input.readline()
+ if echooff:
+ stream.write('\n')
if not line:
raise EOFError
if line[-1] == '\n':
More information about the Python-bugs-list
mailing list