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: + # If that fails, see if stdin can be controlled, + # otherwise use generic fallback implementation + try: + fd = sys.stdin.fileno() + except: + 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) + except Exception as e: + exinst = e finally: + stream.write('\n') 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) + exinst = e # e == termios.error + 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