mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-27 14:17:25 -05:00
fix: a refused write also marks a closed window
A window can still answer tcgetattr while refusing writes. The check now tries both, as the audit asked, and takes the terminal itself so a stand-in without a descriptor is never read.
This commit is contained in:
1 parent
19c57b3d68
commit
c53715d7b9
2 files changed
+21
-14
No files matched your search
+12
-10
@@ -12969,7 +12969,7 @@ def run_tui(args: argparse.Namespace) -> int:
|
||||
# The result is printed in the terminal on the way out.
|
||||
state.exit_code = state.code if state.code is not None else 1
|
||||
except Exception as exc: # noqa: BLE001
|
||||
if flags["term"] or _closed_terminal(exc, terminal.fd):
|
||||
if flags["term"] or _closed_terminal(exc, terminal):
|
||||
# The window closed under a screen that was changing, or the
|
||||
# SIGCONT that comes with its SIGHUP put the screen back: the
|
||||
# write failed before the signal was read. That is its exit.
|
||||
@@ -13033,28 +13033,30 @@ def _tui_startup(args: argparse.Namespace) -> tuple[TuiState, list[tuple]] | Non
|
||||
_CLOSED_TERMINAL = frozenset({errno.EIO, errno.EPIPE, errno.ENXIO})
|
||||
|
||||
|
||||
def _closed_terminal(exc: BaseException, fd: int | None = None) -> bool:
|
||||
def _closed_terminal(exc: BaseException, terminal: _TuiTerminal | None = None) -> bool:
|
||||
"""Whether exc is the terminal gone: an OSError, or a termios.error,
|
||||
whose first argument is the errno, answering EIO, EPIPE or ENXIO, and,
|
||||
given the terminal's fd, that terminal no longer answering. A failing
|
||||
SD card answers EIO too, and that read error is kept in a crash log."""
|
||||
given the terminal, that terminal no longer answering. A failing SD
|
||||
card answers EIO too, and that read error is kept in a crash log."""
|
||||
if isinstance(exc, OSError):
|
||||
closed = exc.errno in _CLOSED_TERMINAL
|
||||
elif type(exc).__name__ == "error" and type(exc).__module__ == "termios":
|
||||
closed = bool(exc.args) and exc.args[0] in _CLOSED_TERMINAL
|
||||
else:
|
||||
closed = False
|
||||
return closed and (fd is None or _terminal_gone(fd))
|
||||
return closed and (terminal is None or _terminal_gone(terminal))
|
||||
|
||||
|
||||
def _terminal_gone(fd: int) -> bool:
|
||||
"""Whether the terminal at fd hung up: a closed window answers EIO to
|
||||
tcgetattr, a live one its settings."""
|
||||
def _terminal_gone(terminal: _TuiTerminal) -> bool:
|
||||
"""Whether the terminal hung up: a closed window answers EIO to
|
||||
tcgetattr and to a write, a live one its settings."""
|
||||
import termios # noqa: PLC0415
|
||||
|
||||
try:
|
||||
termios.tcgetattr(fd)
|
||||
except (termios.error, OSError):
|
||||
termios.tcgetattr(terminal.fd)
|
||||
terminal.stdout.write("")
|
||||
terminal.stdout.flush()
|
||||
except (termios.error, OSError, ValueError):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -2576,16 +2576,21 @@ class AReadErrorIsNotAClosedWindow(unittest.TestCase):
|
||||
import pty
|
||||
|
||||
master, slave = pty.openpty()
|
||||
screen = open(os.dup(slave), "w", encoding="utf-8") # noqa: SIM115
|
||||
terminal = mock.Mock(fd=slave, stdout=screen)
|
||||
try:
|
||||
card = OSError(errno.EIO, "Input/output error", "/media/card/bios/x.bin")
|
||||
self.assertFalse(install._closed_terminal(card, slave))
|
||||
self.assertFalse(install._closed_terminal(card, terminal))
|
||||
self.assertFalse(install._closed_terminal(
|
||||
OSError(errno.ENOENT, "No such file"), slave))
|
||||
OSError(errno.ENOENT, "No such file"), terminal))
|
||||
os.close(master)
|
||||
master = -1
|
||||
self.assertTrue(install._closed_terminal(card, slave))
|
||||
self.assertTrue(install._closed_terminal(termios.error(errno.EIO, "gone"), slave))
|
||||
self.assertTrue(install._closed_terminal(card, terminal))
|
||||
self.assertTrue(install._closed_terminal(termios.error(errno.EIO, "gone"),
|
||||
terminal))
|
||||
finally:
|
||||
with contextlib.suppress(OSError):
|
||||
screen.close()
|
||||
os.close(slave)
|
||||
if master >= 0:
|
||||
os.close(master)
|
||||
|
||||
Reference in new issue
Block a user