diff --git a/ansible_mitogen/target.py b/ansible_mitogen/target.py index 33bcb107..6e128af4 100644 --- a/ansible_mitogen/target.py +++ b/ansible_mitogen/target.py @@ -42,6 +42,7 @@ import json import logging import operator import os +import pty import pwd import re import signal @@ -120,7 +121,7 @@ def subprocess__Popen__close_fds(self, but): continue fd = int(name, 10) - if fd > 2 and fd != but: + if fd > pty.STDERR_FILENO and fd != but: try: os.close(fd) except OSError: diff --git a/mitogen/core.py b/mitogen/core.py index 49f92cae..057cdbcf 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -74,6 +74,7 @@ import logging import os import pickle as py_pickle import pstats +import pty import signal import socket import struct @@ -544,8 +545,8 @@ def set_cloexec(fd): they must be explicitly closed through some other means, such as :func:`mitogen.fork.on_fork`. """ + assert fd > pty.STDERR_FILENO, 'fd %r <= 2 (STDERR_FILENO)' % (fd,) flags = fcntl.fcntl(fd, fcntl.F_GETFD) - assert fd > 2, 'fd %r <= 2' % (fd,) fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) @@ -4019,7 +4020,9 @@ class ExternalContext(object): in_fp = os.fdopen(os.dup(in_fd), 'rb', 0) os.close(in_fd) - out_fp = os.fdopen(os.dup(self.config.get('out_fd', 1)), 'wb', 0) + out_fd = self.config.get('out_fd', pty.STDOUT_FILENO) + out_fd2 = os.dup(out_fd) + out_fp = os.fdopen(out_fd2, 'wb', 0) self.stream = MitogenProtocol.build_stream( self.router, parent_id, @@ -4103,7 +4106,11 @@ class ExternalContext(object): Open /dev/null to replace stdio temporarily. In case of odd startup, assume we may be allocated a standard handle. """ - for stdfd, mode in ((0, os.O_RDONLY), (1, os.O_RDWR), (2, os.O_RDWR)): + for stdfd, mode in [ + (pty.STDIN_FILENO, os.O_RDONLY), + (pty.STDOUT_FILENO, os.O_RDWR), + (pty.STDERR_FILENO, os.O_RDWR), + ]: fd = os.open('/dev/null', mode) if fd != stdfd: os.dup2(fd, stdfd) @@ -4119,8 +4126,9 @@ class ExternalContext(object): avoid receiving SIGHUP. """ try: - if os.isatty(2): - self.reserve_tty_fp = os.fdopen(os.dup(2), 'r+b', 0) + if os.isatty(pty.STDERR_FILENO): + reserve_tty_fd = os.dup(pty.STDERR_FILENO) + self.reserve_tty_fp = os.fdopen(reserve_tty_fd, 'r+b', 0) set_cloexec(self.reserve_tty_fp.fileno()) except OSError: pass @@ -4140,13 +4148,16 @@ class ExternalContext(object): self._nullify_stdio() self.loggers = [] - for name, fd in (('stdout', 1), ('stderr', 2)): - log = IoLoggerProtocol.build_stream(name, fd) + for stdfd, name in [ + (pty.STDOUT_FILENO, 'stdout'), + (pty.STDERR_FILENO, 'stderr'), + ]: + log = IoLoggerProtocol.build_stream(name, stdfd) self.broker.start_receive(log) self.loggers.append(log) # Reopen with line buffering. - sys.stdout = os.fdopen(1, 'w', 1) + sys.stdout = os.fdopen(pty.STDOUT_FILENO, 'w', 1) def main(self): self._setup_master() diff --git a/mitogen/fakessh.py b/mitogen/fakessh.py index 2d660248..a2a8da15 100644 --- a/mitogen/fakessh.py +++ b/mitogen/fakessh.py @@ -95,6 +95,7 @@ Sequence: import getopt import inspect import os +import pty import shutil import socket import subprocess @@ -354,8 +355,9 @@ def _fakessh_main(dest_context_id, econtext): control_handle, stdin_handle) process = Process(econtext.router, - stdin=os.fdopen(1, 'w+b', 0), - stdout=os.fdopen(0, 'r+b', 0)) + stdin=os.fdopen(pty.STDOUT_FILENO, 'w+b', 0), + stdout=os.fdopen(pty.STDIN_FILENO, 'r+b', 0), + ) process.start_master( stdin=mitogen.core.Sender(dest, stdin_handle), control=mitogen.core.Sender(dest, control_handle), diff --git a/mitogen/parent.py b/mitogen/parent.py index 9f15b657..f9200a2e 100644 --- a/mitogen/parent.py +++ b/mitogen/parent.py @@ -43,6 +43,7 @@ import inspect import logging import os import re +import pty import signal import socket import struct @@ -406,12 +407,14 @@ def _acquire_controlling_tty(): if sys.platform in ('linux', 'linux2'): # On Linux, the controlling tty becomes the first tty opened by a # process lacking any prior tty. - os.close(os.open(os.ttyname(2), os.O_RDWR)) + tty_path = os.ttyname(pty.STDERR_FILENO) + tty_fd = os.open(tty_path, os.O_RDWR) + os.close(tty_fd) if hasattr(termios, 'TIOCSCTTY') and not mitogen.core.IS_WSL and not IS_SOLARIS: # #550: prehistoric WSL does not like TIOCSCTTY. # On BSD an explicit ioctl is required. For some inexplicable reason, # Python 2.6 on Travis also requires it. - fcntl.ioctl(2, termios.TIOCSCTTY) + fcntl.ioctl(pty.STDERR_FILENO, termios.TIOCSCTTY) def _linux_broken_devpts_openpty(): @@ -1415,7 +1418,7 @@ class Connection(object): # w: write side of core_src FD. # C: the decompressed core source. - # Final os.close(2) to avoid --py-debug build from corrupting stream with + # Final os.close(STDOUT_FILENO) to avoid --py-debug build corrupting stream with # "[1234 refs]" during exit. @staticmethod def _first_stage():