1205fd03aSDavide Italianoimport codecs
2205fd03aSDavide Italianoimport errno
3205fd03aSDavide Italianoimport fcntl
4205fd03aSDavide Italianoimport io
5205fd03aSDavide Italianoimport os
6205fd03aSDavide Italianoimport pty
7205fd03aSDavide Italianoimport resource
8205fd03aSDavide Italianoimport signal
9205fd03aSDavide Italianoimport struct
10205fd03aSDavide Italianoimport sys
11205fd03aSDavide Italianoimport termios
12205fd03aSDavide Italianoimport time
13205fd03aSDavide Italiano
14205fd03aSDavide Italianotry:
15205fd03aSDavide Italiano    import builtins  # Python 3
16205fd03aSDavide Italianoexcept ImportError:
17205fd03aSDavide Italiano    import __builtin__ as builtins  # Python 2
18205fd03aSDavide Italiano
19205fd03aSDavide Italiano# Constants
20205fd03aSDavide Italianofrom pty import (STDIN_FILENO, CHILD)
21205fd03aSDavide Italiano
22205fd03aSDavide Italianofrom .util import which, PtyProcessError
23205fd03aSDavide Italiano
24205fd03aSDavide Italiano_platform = sys.platform.lower()
25205fd03aSDavide Italiano
26205fd03aSDavide Italiano# Solaris uses internal __fork_pty(). All others use pty.fork().
27205fd03aSDavide Italiano_is_solaris = (
28205fd03aSDavide Italiano    _platform.startswith('solaris') or
29205fd03aSDavide Italiano    _platform.startswith('sunos'))
30205fd03aSDavide Italiano
31205fd03aSDavide Italianoif _is_solaris:
32205fd03aSDavide Italiano    use_native_pty_fork = False
33205fd03aSDavide Italiano    from . import _fork_pty
34205fd03aSDavide Italianoelse:
35205fd03aSDavide Italiano    use_native_pty_fork = True
36205fd03aSDavide Italiano
37205fd03aSDavide ItalianoPY3 = sys.version_info[0] >= 3
38205fd03aSDavide Italiano
39205fd03aSDavide Italianoif PY3:
40205fd03aSDavide Italiano    def _byte(i):
41205fd03aSDavide Italiano        return bytes([i])
42205fd03aSDavide Italianoelse:
43205fd03aSDavide Italiano    def _byte(i):
44205fd03aSDavide Italiano        return chr(i)
45205fd03aSDavide Italiano
46205fd03aSDavide Italiano    class FileNotFoundError(OSError): pass
47205fd03aSDavide Italiano    class TimeoutError(OSError): pass
48205fd03aSDavide Italiano
49205fd03aSDavide Italiano_EOF, _INTR = None, None
50205fd03aSDavide Italiano
51205fd03aSDavide Italianodef _make_eof_intr():
52205fd03aSDavide Italiano    """Set constants _EOF and _INTR.
53205fd03aSDavide Italiano
54205fd03aSDavide Italiano    This avoids doing potentially costly operations on module load.
55205fd03aSDavide Italiano    """
56205fd03aSDavide Italiano    global _EOF, _INTR
57205fd03aSDavide Italiano    if (_EOF is not None) and (_INTR is not None):
58205fd03aSDavide Italiano        return
59205fd03aSDavide Italiano
60205fd03aSDavide Italiano    # inherit EOF and INTR definitions from controlling process.
61205fd03aSDavide Italiano    try:
62205fd03aSDavide Italiano        from termios import VEOF, VINTR
63205fd03aSDavide Italiano        fd = None
64205fd03aSDavide Italiano        for name in 'stdin', 'stdout':
65205fd03aSDavide Italiano            stream = getattr(sys, '__%s__' % name, None)
66205fd03aSDavide Italiano            if stream is None or not hasattr(stream, 'fileno'):
67205fd03aSDavide Italiano                continue
68205fd03aSDavide Italiano            try:
69205fd03aSDavide Italiano                fd = stream.fileno()
70205fd03aSDavide Italiano            except ValueError:
71205fd03aSDavide Italiano                continue
72205fd03aSDavide Italiano        if fd is None:
73205fd03aSDavide Italiano            # no fd, raise ValueError to fallback on CEOF, CINTR
74205fd03aSDavide Italiano            raise ValueError("No stream has a fileno")
75205fd03aSDavide Italiano        intr = ord(termios.tcgetattr(fd)[6][VINTR])
76205fd03aSDavide Italiano        eof = ord(termios.tcgetattr(fd)[6][VEOF])
77205fd03aSDavide Italiano    except (ImportError, OSError, IOError, ValueError, termios.error):
78205fd03aSDavide Italiano        # unless the controlling process is also not a terminal,
79205fd03aSDavide Italiano        # such as cron(1), or when stdin and stdout are both closed.
80205fd03aSDavide Italiano        # Fall-back to using CEOF and CINTR. There
81205fd03aSDavide Italiano        try:
82205fd03aSDavide Italiano            from termios import CEOF, CINTR
83205fd03aSDavide Italiano            (intr, eof) = (CINTR, CEOF)
84205fd03aSDavide Italiano        except ImportError:
85205fd03aSDavide Italiano            #                         ^C, ^D
86205fd03aSDavide Italiano            (intr, eof) = (3, 4)
87205fd03aSDavide Italiano
88205fd03aSDavide Italiano    _INTR = _byte(intr)
89205fd03aSDavide Italiano    _EOF = _byte(eof)
90205fd03aSDavide Italiano
91205fd03aSDavide Italiano# setecho and setwinsize are pulled out here because on some platforms, we need
92205fd03aSDavide Italiano# to do this from the child before we exec()
93205fd03aSDavide Italiano
94205fd03aSDavide Italianodef _setecho(fd, state):
95205fd03aSDavide Italiano    errmsg = 'setecho() may not be called on this platform (it may still be possible to enable/disable echo when spawning the child process)'
96205fd03aSDavide Italiano
97205fd03aSDavide Italiano    try:
98205fd03aSDavide Italiano        attr = termios.tcgetattr(fd)
99205fd03aSDavide Italiano    except termios.error as err:
100205fd03aSDavide Italiano        if err.args[0] == errno.EINVAL:
101205fd03aSDavide Italiano            raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg))
102205fd03aSDavide Italiano        raise
103205fd03aSDavide Italiano
104205fd03aSDavide Italiano    if state:
105205fd03aSDavide Italiano        attr[3] = attr[3] | termios.ECHO
106205fd03aSDavide Italiano    else:
107205fd03aSDavide Italiano        attr[3] = attr[3] & ~termios.ECHO
108205fd03aSDavide Italiano
109205fd03aSDavide Italiano    try:
110205fd03aSDavide Italiano        # I tried TCSADRAIN and TCSAFLUSH, but these were inconsistent and
111205fd03aSDavide Italiano        # blocked on some platforms. TCSADRAIN would probably be ideal.
112205fd03aSDavide Italiano        termios.tcsetattr(fd, termios.TCSANOW, attr)
113205fd03aSDavide Italiano    except IOError as err:
114205fd03aSDavide Italiano        if err.args[0] == errno.EINVAL:
115205fd03aSDavide Italiano            raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg))
116205fd03aSDavide Italiano        raise
117205fd03aSDavide Italiano
118205fd03aSDavide Italianodef _setwinsize(fd, rows, cols):
119205fd03aSDavide Italiano    # Some very old platforms have a bug that causes the value for
120205fd03aSDavide Italiano    # termios.TIOCSWINSZ to be truncated. There was a hack here to work
121205fd03aSDavide Italiano    # around this, but it caused problems with newer platforms so has been
122205fd03aSDavide Italiano    # removed. For details see https://github.com/pexpect/pexpect/issues/39
123205fd03aSDavide Italiano    TIOCSWINSZ = getattr(termios, 'TIOCSWINSZ', -2146929561)
124205fd03aSDavide Italiano    # Note, assume ws_xpixel and ws_ypixel are zero.
125205fd03aSDavide Italiano    s = struct.pack('HHHH', rows, cols, 0, 0)
126205fd03aSDavide Italiano    fcntl.ioctl(fd, TIOCSWINSZ, s)
127205fd03aSDavide Italiano
128205fd03aSDavide Italianoclass PtyProcess(object):
129205fd03aSDavide Italiano    '''This class represents a process running in a pseudoterminal.
130205fd03aSDavide Italiano
131205fd03aSDavide Italiano    The main constructor is the :meth:`spawn` classmethod.
132205fd03aSDavide Italiano    '''
133205fd03aSDavide Italiano    string_type = bytes
134205fd03aSDavide Italiano    if PY3:
135205fd03aSDavide Italiano        linesep = os.linesep.encode('ascii')
136205fd03aSDavide Italiano        crlf = '\r\n'.encode('ascii')
137205fd03aSDavide Italiano
138205fd03aSDavide Italiano        @staticmethod
139205fd03aSDavide Italiano        def write_to_stdout(b):
140205fd03aSDavide Italiano            try:
141205fd03aSDavide Italiano                return sys.stdout.buffer.write(b)
142205fd03aSDavide Italiano            except AttributeError:
143205fd03aSDavide Italiano                # If stdout has been replaced, it may not have .buffer
144205fd03aSDavide Italiano                return sys.stdout.write(b.decode('ascii', 'replace'))
145205fd03aSDavide Italiano    else:
146205fd03aSDavide Italiano        linesep = os.linesep
147205fd03aSDavide Italiano        crlf = '\r\n'
148205fd03aSDavide Italiano        write_to_stdout = sys.stdout.write
149205fd03aSDavide Italiano
150205fd03aSDavide Italiano    encoding = None
151205fd03aSDavide Italiano
152205fd03aSDavide Italiano    argv = None
153205fd03aSDavide Italiano    env = None
154205fd03aSDavide Italiano    launch_dir = None
155205fd03aSDavide Italiano
156205fd03aSDavide Italiano    def __init__(self, pid, fd):
157205fd03aSDavide Italiano        _make_eof_intr()  # Ensure _EOF and _INTR are calculated
158205fd03aSDavide Italiano        self.pid = pid
159205fd03aSDavide Italiano        self.fd = fd
160205fd03aSDavide Italiano        readf = io.open(fd, 'rb', buffering=0)
161205fd03aSDavide Italiano        writef = io.open(fd, 'wb', buffering=0, closefd=False)
162205fd03aSDavide Italiano        self.fileobj = io.BufferedRWPair(readf, writef)
163205fd03aSDavide Italiano
164205fd03aSDavide Italiano        self.terminated = False
165205fd03aSDavide Italiano        self.closed = False
166205fd03aSDavide Italiano        self.exitstatus = None
167205fd03aSDavide Italiano        self.signalstatus = None
168205fd03aSDavide Italiano        # status returned by os.waitpid
169205fd03aSDavide Italiano        self.status = None
170205fd03aSDavide Italiano        self.flag_eof = False
171205fd03aSDavide Italiano        # Used by close() to give kernel time to update process status.
172205fd03aSDavide Italiano        # Time in seconds.
173205fd03aSDavide Italiano        self.delayafterclose = 0.1
174205fd03aSDavide Italiano        # Used by terminate() to give kernel time to update process status.
175205fd03aSDavide Italiano        # Time in seconds.
176205fd03aSDavide Italiano        self.delayafterterminate = 0.1
177205fd03aSDavide Italiano
178205fd03aSDavide Italiano    @classmethod
179205fd03aSDavide Italiano    def spawn(
180205fd03aSDavide Italiano            cls, argv, cwd=None, env=None, echo=True, preexec_fn=None,
181205fd03aSDavide Italiano            dimensions=(24, 80)):
182205fd03aSDavide Italiano        '''Start the given command in a child process in a pseudo terminal.
183205fd03aSDavide Italiano
184205fd03aSDavide Italiano        This does all the fork/exec type of stuff for a pty, and returns an
185205fd03aSDavide Italiano        instance of PtyProcess.
186205fd03aSDavide Italiano
187205fd03aSDavide Italiano        If preexec_fn is supplied, it will be called with no arguments in the
188205fd03aSDavide Italiano        child process before exec-ing the specified command.
189205fd03aSDavide Italiano        It may, for instance, set signal handlers to SIG_DFL or SIG_IGN.
190205fd03aSDavide Italiano
191205fd03aSDavide Italiano        Dimensions of the psuedoterminal used for the subprocess can be
192205fd03aSDavide Italiano        specified as a tuple (rows, cols), or the default (24, 80) will be used.
193205fd03aSDavide Italiano        '''
194205fd03aSDavide Italiano        # Note that it is difficult for this method to fail.
195205fd03aSDavide Italiano        # You cannot detect if the child process cannot start.
196205fd03aSDavide Italiano        # So the only way you can tell if the child process started
197205fd03aSDavide Italiano        # or not is to try to read from the file descriptor. If you get
198205fd03aSDavide Italiano        # EOF immediately then it means that the child is already dead.
199205fd03aSDavide Italiano        # That may not necessarily be bad because you may have spawned a child
200205fd03aSDavide Italiano        # that performs some task; creates no stdout output; and then dies.
201205fd03aSDavide Italiano
202205fd03aSDavide Italiano        if not isinstance(argv, (list, tuple)):
203205fd03aSDavide Italiano            raise TypeError("Expected a list or tuple for argv, got %r" % argv)
204205fd03aSDavide Italiano
205205fd03aSDavide Italiano        # Shallow copy of argv so we can modify it
206205fd03aSDavide Italiano        argv = argv[:]
207205fd03aSDavide Italiano        command = argv[0]
208205fd03aSDavide Italiano
209205fd03aSDavide Italiano        command_with_path = which(command)
210205fd03aSDavide Italiano        if command_with_path is None:
211205fd03aSDavide Italiano            raise FileNotFoundError('The command was not found or was not ' +
212205fd03aSDavide Italiano                                    'executable: %s.' % command)
213205fd03aSDavide Italiano        command = command_with_path
214205fd03aSDavide Italiano        argv[0] = command
215205fd03aSDavide Italiano
216205fd03aSDavide Italiano        # [issue #119] To prevent the case where exec fails and the user is
217205fd03aSDavide Italiano        # stuck interacting with a python child process instead of whatever
218205fd03aSDavide Italiano        # was expected, we implement the solution from
219205fd03aSDavide Italiano        # http://stackoverflow.com/a/3703179 to pass the exception to the
220205fd03aSDavide Italiano        # parent process
221205fd03aSDavide Italiano
222205fd03aSDavide Italiano        # [issue #119] 1. Before forking, open a pipe in the parent process.
223205fd03aSDavide Italiano        exec_err_pipe_read, exec_err_pipe_write = os.pipe()
224205fd03aSDavide Italiano
225205fd03aSDavide Italiano        if use_native_pty_fork:
226205fd03aSDavide Italiano            pid, fd = pty.fork()
227205fd03aSDavide Italiano        else:
228205fd03aSDavide Italiano            # Use internal fork_pty, for Solaris
229205fd03aSDavide Italiano            pid, fd = _fork_pty.fork_pty()
230205fd03aSDavide Italiano
231205fd03aSDavide Italiano        # Some platforms must call setwinsize() and setecho() from the
232*52a3ed5bSQuinn Pham        # child process, and others from the primary process. We do both,
233205fd03aSDavide Italiano        # allowing IOError for either.
234205fd03aSDavide Italiano
235205fd03aSDavide Italiano        if pid == CHILD:
236205fd03aSDavide Italiano            # set window size
237205fd03aSDavide Italiano            try:
238205fd03aSDavide Italiano                _setwinsize(STDIN_FILENO, *dimensions)
239205fd03aSDavide Italiano            except IOError as err:
240205fd03aSDavide Italiano                if err.args[0] not in (errno.EINVAL, errno.ENOTTY):
241205fd03aSDavide Italiano                    raise
242205fd03aSDavide Italiano
243205fd03aSDavide Italiano            # disable echo if spawn argument echo was unset
244205fd03aSDavide Italiano            if not echo:
245205fd03aSDavide Italiano                try:
246205fd03aSDavide Italiano                    _setecho(STDIN_FILENO, False)
247205fd03aSDavide Italiano                except (IOError, termios.error) as err:
248205fd03aSDavide Italiano                    if err.args[0] not in (errno.EINVAL, errno.ENOTTY):
249205fd03aSDavide Italiano                        raise
250205fd03aSDavide Italiano
251205fd03aSDavide Italiano            # [issue #119] 3. The child closes the reading end and sets the
252205fd03aSDavide Italiano            # close-on-exec flag for the writing end.
253205fd03aSDavide Italiano            os.close(exec_err_pipe_read)
254205fd03aSDavide Italiano            fcntl.fcntl(exec_err_pipe_write, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
255205fd03aSDavide Italiano
256205fd03aSDavide Italiano            # Do not allow child to inherit open file descriptors from parent,
257205fd03aSDavide Italiano            # with the exception of the exec_err_pipe_write of the pipe
258205fd03aSDavide Italiano            # Impose ceiling on max_fd: AIX bugfix for users with unlimited
259205fd03aSDavide Italiano            # nofiles where resource.RLIMIT_NOFILE is 2^63-1 and os.closerange()
260205fd03aSDavide Italiano            # occasionally raises out of range error
261205fd03aSDavide Italiano            max_fd = min(1048576, resource.getrlimit(resource.RLIMIT_NOFILE)[0])
262205fd03aSDavide Italiano            os.closerange(3, exec_err_pipe_write)
263205fd03aSDavide Italiano            os.closerange(exec_err_pipe_write+1, max_fd)
264205fd03aSDavide Italiano
265205fd03aSDavide Italiano            if cwd is not None:
266205fd03aSDavide Italiano                os.chdir(cwd)
267205fd03aSDavide Italiano
268205fd03aSDavide Italiano            if preexec_fn is not None:
269205fd03aSDavide Italiano                try:
270205fd03aSDavide Italiano                    preexec_fn()
271205fd03aSDavide Italiano                except Exception as e:
272205fd03aSDavide Italiano                    ename = type(e).__name__
273205fd03aSDavide Italiano                    tosend = '{}:0:{}'.format(ename, str(e))
274205fd03aSDavide Italiano                    if PY3:
275205fd03aSDavide Italiano                        tosend = tosend.encode('utf-8')
276205fd03aSDavide Italiano
277205fd03aSDavide Italiano                    os.write(exec_err_pipe_write, tosend)
278205fd03aSDavide Italiano                    os.close(exec_err_pipe_write)
279205fd03aSDavide Italiano                    os._exit(1)
280205fd03aSDavide Italiano
281205fd03aSDavide Italiano            try:
282205fd03aSDavide Italiano                if env is None:
283205fd03aSDavide Italiano                    os.execv(command, argv)
284205fd03aSDavide Italiano                else:
285205fd03aSDavide Italiano                    os.execvpe(command, argv, env)
286205fd03aSDavide Italiano            except OSError as err:
287205fd03aSDavide Italiano                # [issue #119] 5. If exec fails, the child writes the error
288205fd03aSDavide Italiano                # code back to the parent using the pipe, then exits.
289205fd03aSDavide Italiano                tosend = 'OSError:{}:{}'.format(err.errno, str(err))
290205fd03aSDavide Italiano                if PY3:
291205fd03aSDavide Italiano                    tosend = tosend.encode('utf-8')
292205fd03aSDavide Italiano                os.write(exec_err_pipe_write, tosend)
293205fd03aSDavide Italiano                os.close(exec_err_pipe_write)
294205fd03aSDavide Italiano                os._exit(os.EX_OSERR)
295205fd03aSDavide Italiano
296205fd03aSDavide Italiano        # Parent
297205fd03aSDavide Italiano        inst = cls(pid, fd)
298205fd03aSDavide Italiano
299205fd03aSDavide Italiano        # Set some informational attributes
300205fd03aSDavide Italiano        inst.argv = argv
301205fd03aSDavide Italiano        if env is not None:
302205fd03aSDavide Italiano            inst.env = env
303205fd03aSDavide Italiano        if cwd is not None:
304205fd03aSDavide Italiano            inst.launch_dir = cwd
305205fd03aSDavide Italiano
306205fd03aSDavide Italiano        # [issue #119] 2. After forking, the parent closes the writing end
307205fd03aSDavide Italiano        # of the pipe and reads from the reading end.
308205fd03aSDavide Italiano        os.close(exec_err_pipe_write)
309205fd03aSDavide Italiano        exec_err_data = os.read(exec_err_pipe_read, 4096)
310205fd03aSDavide Italiano        os.close(exec_err_pipe_read)
311205fd03aSDavide Italiano
312205fd03aSDavide Italiano        # [issue #119] 6. The parent reads eof (a zero-length read) if the
313205fd03aSDavide Italiano        # child successfully performed exec, since close-on-exec made
314205fd03aSDavide Italiano        # successful exec close the writing end of the pipe. Or, if exec
315205fd03aSDavide Italiano        # failed, the parent reads the error code and can proceed
316205fd03aSDavide Italiano        # accordingly. Either way, the parent blocks until the child calls
317205fd03aSDavide Italiano        # exec.
318205fd03aSDavide Italiano        if len(exec_err_data) != 0:
319205fd03aSDavide Italiano            try:
320205fd03aSDavide Italiano                errclass, errno_s, errmsg = exec_err_data.split(b':', 2)
321205fd03aSDavide Italiano                exctype = getattr(builtins, errclass.decode('ascii'), Exception)
322205fd03aSDavide Italiano
323205fd03aSDavide Italiano                exception = exctype(errmsg.decode('utf-8', 'replace'))
324205fd03aSDavide Italiano                if exctype is OSError:
325205fd03aSDavide Italiano                    exception.errno = int(errno_s)
326205fd03aSDavide Italiano            except:
327205fd03aSDavide Italiano                raise Exception('Subprocess failed, got bad error data: %r'
328205fd03aSDavide Italiano                                    % exec_err_data)
329205fd03aSDavide Italiano            else:
330205fd03aSDavide Italiano                raise exception
331205fd03aSDavide Italiano
332205fd03aSDavide Italiano        try:
333205fd03aSDavide Italiano            inst.setwinsize(*dimensions)
334205fd03aSDavide Italiano        except IOError as err:
335205fd03aSDavide Italiano            if err.args[0] not in (errno.EINVAL, errno.ENOTTY, errno.ENXIO):
336205fd03aSDavide Italiano                raise
337205fd03aSDavide Italiano
338205fd03aSDavide Italiano        return inst
339205fd03aSDavide Italiano
340205fd03aSDavide Italiano    def __repr__(self):
341205fd03aSDavide Italiano        clsname = type(self).__name__
342205fd03aSDavide Italiano        if self.argv is not None:
343205fd03aSDavide Italiano            args = [repr(self.argv)]
344205fd03aSDavide Italiano            if self.env is not None:
345205fd03aSDavide Italiano                args.append("env=%r" % self.env)
346205fd03aSDavide Italiano            if self.launch_dir is not None:
347205fd03aSDavide Italiano                args.append("cwd=%r" % self.launch_dir)
348205fd03aSDavide Italiano
349205fd03aSDavide Italiano            return "{}.spawn({})".format(clsname, ", ".join(args))
350205fd03aSDavide Italiano
351205fd03aSDavide Italiano        else:
352205fd03aSDavide Italiano            return "{}(pid={}, fd={})".format(clsname, self.pid, self.fd)
353205fd03aSDavide Italiano
354205fd03aSDavide Italiano    @staticmethod
355205fd03aSDavide Italiano    def _coerce_send_string(s):
356205fd03aSDavide Italiano        if not isinstance(s, bytes):
357205fd03aSDavide Italiano            return s.encode('utf-8')
358205fd03aSDavide Italiano        return s
359205fd03aSDavide Italiano
360205fd03aSDavide Italiano    @staticmethod
361205fd03aSDavide Italiano    def _coerce_read_string(s):
362205fd03aSDavide Italiano        return s
363205fd03aSDavide Italiano
364205fd03aSDavide Italiano    def __del__(self):
365205fd03aSDavide Italiano        '''This makes sure that no system resources are left open. Python only
366205fd03aSDavide Italiano        garbage collects Python objects. OS file descriptors are not Python
367205fd03aSDavide Italiano        objects, so they must be handled explicitly. If the child file
368205fd03aSDavide Italiano        descriptor was opened outside of this class (passed to the constructor)
369205fd03aSDavide Italiano        then this does not close it. '''
370205fd03aSDavide Italiano
371205fd03aSDavide Italiano        if not self.closed:
372205fd03aSDavide Italiano            # It is possible for __del__ methods to execute during the
373205fd03aSDavide Italiano            # teardown of the Python VM itself. Thus self.close() may
374205fd03aSDavide Italiano            # trigger an exception because os.close may be None.
375205fd03aSDavide Italiano            try:
376205fd03aSDavide Italiano                self.close()
377205fd03aSDavide Italiano            # which exception, shouldn't we catch explicitly .. ?
378205fd03aSDavide Italiano            except:
379205fd03aSDavide Italiano                pass
380205fd03aSDavide Italiano
381205fd03aSDavide Italiano
382205fd03aSDavide Italiano    def fileno(self):
383205fd03aSDavide Italiano        '''This returns the file descriptor of the pty for the child.
384205fd03aSDavide Italiano        '''
385205fd03aSDavide Italiano        return self.fd
386205fd03aSDavide Italiano
387205fd03aSDavide Italiano    def close(self, force=True):
388205fd03aSDavide Italiano        '''This closes the connection with the child application. Note that
389205fd03aSDavide Italiano        calling close() more than once is valid. This emulates standard Python
390205fd03aSDavide Italiano        behavior with files. Set force to True if you want to make sure that
391205fd03aSDavide Italiano        the child is terminated (SIGKILL is sent if the child ignores SIGHUP
392205fd03aSDavide Italiano        and SIGINT). '''
393205fd03aSDavide Italiano        if not self.closed:
394205fd03aSDavide Italiano            self.flush()
395205fd03aSDavide Italiano            self.fileobj.close() # Closes the file descriptor
396205fd03aSDavide Italiano            # Give kernel time to update process status.
397205fd03aSDavide Italiano            time.sleep(self.delayafterclose)
398205fd03aSDavide Italiano            if self.isalive():
399205fd03aSDavide Italiano                if not self.terminate(force):
400205fd03aSDavide Italiano                    raise PtyProcessError('Could not terminate the child.')
401205fd03aSDavide Italiano            self.fd = -1
402205fd03aSDavide Italiano            self.closed = True
403205fd03aSDavide Italiano            #self.pid = None
404205fd03aSDavide Italiano
405205fd03aSDavide Italiano    def flush(self):
406205fd03aSDavide Italiano        '''This does nothing. It is here to support the interface for a
407205fd03aSDavide Italiano        File-like object. '''
408205fd03aSDavide Italiano
409205fd03aSDavide Italiano        pass
410205fd03aSDavide Italiano
411205fd03aSDavide Italiano    def isatty(self):
412205fd03aSDavide Italiano        '''This returns True if the file descriptor is open and connected to a
413205fd03aSDavide Italiano        tty(-like) device, else False.
414205fd03aSDavide Italiano
415205fd03aSDavide Italiano        On SVR4-style platforms implementing streams, such as SunOS and HP-UX,
416205fd03aSDavide Italiano        the child pty may not appear as a terminal device.  This means
417205fd03aSDavide Italiano        methods such as setecho(), setwinsize(), getwinsize() may raise an
418205fd03aSDavide Italiano        IOError. '''
419205fd03aSDavide Italiano
420205fd03aSDavide Italiano        return os.isatty(self.fd)
421205fd03aSDavide Italiano
422205fd03aSDavide Italiano    def waitnoecho(self, timeout=None):
423205fd03aSDavide Italiano        '''This waits until the terminal ECHO flag is set False. This returns
424205fd03aSDavide Italiano        True if the echo mode is off. This returns False if the ECHO flag was
425205fd03aSDavide Italiano        not set False before the timeout. This can be used to detect when the
426205fd03aSDavide Italiano        child is waiting for a password. Usually a child application will turn
427205fd03aSDavide Italiano        off echo mode when it is waiting for the user to enter a password. For
428205fd03aSDavide Italiano        example, instead of expecting the "password:" prompt you can wait for
429205fd03aSDavide Italiano        the child to set ECHO off::
430205fd03aSDavide Italiano
431205fd03aSDavide Italiano            p = pexpect.spawn('ssh [email protected]')
432205fd03aSDavide Italiano            p.waitnoecho()
433205fd03aSDavide Italiano            p.sendline(mypassword)
434205fd03aSDavide Italiano
435205fd03aSDavide Italiano        If timeout==None then this method to block until ECHO flag is False.
436205fd03aSDavide Italiano        '''
437205fd03aSDavide Italiano
438205fd03aSDavide Italiano        if timeout is not None:
439205fd03aSDavide Italiano            end_time = time.time() + timeout
440205fd03aSDavide Italiano        while True:
441205fd03aSDavide Italiano            if not self.getecho():
442205fd03aSDavide Italiano                return True
443205fd03aSDavide Italiano            if timeout < 0 and timeout is not None:
444205fd03aSDavide Italiano                return False
445205fd03aSDavide Italiano            if timeout is not None:
446205fd03aSDavide Italiano                timeout = end_time - time.time()
447205fd03aSDavide Italiano            time.sleep(0.1)
448205fd03aSDavide Italiano
449205fd03aSDavide Italiano    def getecho(self):
450205fd03aSDavide Italiano        '''This returns the terminal echo mode. This returns True if echo is
451205fd03aSDavide Italiano        on or False if echo is off. Child applications that are expecting you
452205fd03aSDavide Italiano        to enter a password often set ECHO False. See waitnoecho().
453205fd03aSDavide Italiano
454205fd03aSDavide Italiano        Not supported on platforms where ``isatty()`` returns False.  '''
455205fd03aSDavide Italiano
456205fd03aSDavide Italiano        try:
457205fd03aSDavide Italiano            attr = termios.tcgetattr(self.fd)
458205fd03aSDavide Italiano        except termios.error as err:
459205fd03aSDavide Italiano            errmsg = 'getecho() may not be called on this platform'
460205fd03aSDavide Italiano            if err.args[0] == errno.EINVAL:
461205fd03aSDavide Italiano                raise IOError(err.args[0], '%s: %s.' % (err.args[1], errmsg))
462205fd03aSDavide Italiano            raise
463205fd03aSDavide Italiano
464205fd03aSDavide Italiano        self.echo = bool(attr[3] & termios.ECHO)
465205fd03aSDavide Italiano        return self.echo
466205fd03aSDavide Italiano
467205fd03aSDavide Italiano    def setecho(self, state):
468205fd03aSDavide Italiano        '''This sets the terminal echo mode on or off. Note that anything the
469205fd03aSDavide Italiano        child sent before the echo will be lost, so you should be sure that
470205fd03aSDavide Italiano        your input buffer is empty before you call setecho(). For example, the
471205fd03aSDavide Italiano        following will work as expected::
472205fd03aSDavide Italiano
473205fd03aSDavide Italiano            p = pexpect.spawn('cat') # Echo is on by default.
474205fd03aSDavide Italiano            p.sendline('1234') # We expect see this twice from the child...
475205fd03aSDavide Italiano            p.expect(['1234']) # ... once from the tty echo...
476205fd03aSDavide Italiano            p.expect(['1234']) # ... and again from cat itself.
477205fd03aSDavide Italiano            p.setecho(False) # Turn off tty echo
478205fd03aSDavide Italiano            p.sendline('abcd') # We will set this only once (echoed by cat).
479205fd03aSDavide Italiano            p.sendline('wxyz') # We will set this only once (echoed by cat)
480205fd03aSDavide Italiano            p.expect(['abcd'])
481205fd03aSDavide Italiano            p.expect(['wxyz'])
482205fd03aSDavide Italiano
483205fd03aSDavide Italiano        The following WILL NOT WORK because the lines sent before the setecho
484205fd03aSDavide Italiano        will be lost::
485205fd03aSDavide Italiano
486205fd03aSDavide Italiano            p = pexpect.spawn('cat')
487205fd03aSDavide Italiano            p.sendline('1234')
488205fd03aSDavide Italiano            p.setecho(False) # Turn off tty echo
489205fd03aSDavide Italiano            p.sendline('abcd') # We will set this only once (echoed by cat).
490205fd03aSDavide Italiano            p.sendline('wxyz') # We will set this only once (echoed by cat)
491205fd03aSDavide Italiano            p.expect(['1234'])
492205fd03aSDavide Italiano            p.expect(['1234'])
493205fd03aSDavide Italiano            p.expect(['abcd'])
494205fd03aSDavide Italiano            p.expect(['wxyz'])
495205fd03aSDavide Italiano
496205fd03aSDavide Italiano
497205fd03aSDavide Italiano        Not supported on platforms where ``isatty()`` returns False.
498205fd03aSDavide Italiano        '''
499205fd03aSDavide Italiano        _setecho(self.fd, state)
500205fd03aSDavide Italiano
501205fd03aSDavide Italiano        self.echo = state
502205fd03aSDavide Italiano
503205fd03aSDavide Italiano    def read(self, size=1024):
504205fd03aSDavide Italiano        """Read and return at most ``size`` bytes from the pty.
505205fd03aSDavide Italiano
506205fd03aSDavide Italiano        Can block if there is nothing to read. Raises :exc:`EOFError` if the
507205fd03aSDavide Italiano        terminal was closed.
508205fd03aSDavide Italiano
509205fd03aSDavide Italiano        Unlike Pexpect's ``read_nonblocking`` method, this doesn't try to deal
510205fd03aSDavide Italiano        with the vagaries of EOF on platforms that do strange things, like IRIX
511205fd03aSDavide Italiano        or older Solaris systems. It handles the errno=EIO pattern used on
512205fd03aSDavide Italiano        Linux, and the empty-string return used on BSD platforms and (seemingly)
513205fd03aSDavide Italiano        on recent Solaris.
514205fd03aSDavide Italiano        """
515205fd03aSDavide Italiano        try:
516205fd03aSDavide Italiano            s = self.fileobj.read1(size)
517205fd03aSDavide Italiano        except (OSError, IOError) as err:
518205fd03aSDavide Italiano            if err.args[0] == errno.EIO:
519205fd03aSDavide Italiano                # Linux-style EOF
520205fd03aSDavide Italiano                self.flag_eof = True
521205fd03aSDavide Italiano                raise EOFError('End Of File (EOF). Exception style platform.')
522205fd03aSDavide Italiano            raise
523205fd03aSDavide Italiano        if s == b'':
524205fd03aSDavide Italiano            # BSD-style EOF (also appears to work on recent Solaris (OpenIndiana))
525205fd03aSDavide Italiano            self.flag_eof = True
526205fd03aSDavide Italiano            raise EOFError('End Of File (EOF). Empty string style platform.')
527205fd03aSDavide Italiano
528205fd03aSDavide Italiano        return s
529205fd03aSDavide Italiano
530205fd03aSDavide Italiano    def readline(self):
531205fd03aSDavide Italiano        """Read one line from the pseudoterminal, and return it as unicode.
532205fd03aSDavide Italiano
533205fd03aSDavide Italiano        Can block if there is nothing to read. Raises :exc:`EOFError` if the
534205fd03aSDavide Italiano        terminal was closed.
535205fd03aSDavide Italiano        """
536205fd03aSDavide Italiano        try:
537205fd03aSDavide Italiano            s = self.fileobj.readline()
538205fd03aSDavide Italiano        except (OSError, IOError) as err:
539205fd03aSDavide Italiano            if err.args[0] == errno.EIO:
540205fd03aSDavide Italiano                # Linux-style EOF
541205fd03aSDavide Italiano                self.flag_eof = True
542205fd03aSDavide Italiano                raise EOFError('End Of File (EOF). Exception style platform.')
543205fd03aSDavide Italiano            raise
544205fd03aSDavide Italiano        if s == b'':
545205fd03aSDavide Italiano            # BSD-style EOF (also appears to work on recent Solaris (OpenIndiana))
546205fd03aSDavide Italiano            self.flag_eof = True
547205fd03aSDavide Italiano            raise EOFError('End Of File (EOF). Empty string style platform.')
548205fd03aSDavide Italiano
549205fd03aSDavide Italiano        return s
550205fd03aSDavide Italiano
551205fd03aSDavide Italiano    def _writeb(self, b, flush=True):
552205fd03aSDavide Italiano        n = self.fileobj.write(b)
553205fd03aSDavide Italiano        if flush:
554205fd03aSDavide Italiano            self.fileobj.flush()
555205fd03aSDavide Italiano        return n
556205fd03aSDavide Italiano
557205fd03aSDavide Italiano    def write(self, s, flush=True):
558205fd03aSDavide Italiano        """Write bytes to the pseudoterminal.
559205fd03aSDavide Italiano
560205fd03aSDavide Italiano        Returns the number of bytes written.
561205fd03aSDavide Italiano        """
562205fd03aSDavide Italiano        return self._writeb(s, flush=flush)
563205fd03aSDavide Italiano
564205fd03aSDavide Italiano    def sendcontrol(self, char):
565205fd03aSDavide Italiano        '''Helper method that wraps send() with mnemonic access for sending control
566205fd03aSDavide Italiano        character to the child (such as Ctrl-C or Ctrl-D).  For example, to send
567205fd03aSDavide Italiano        Ctrl-G (ASCII 7, bell, '\a')::
568205fd03aSDavide Italiano
569205fd03aSDavide Italiano            child.sendcontrol('g')
570205fd03aSDavide Italiano
571205fd03aSDavide Italiano        See also, sendintr() and sendeof().
572205fd03aSDavide Italiano        '''
573205fd03aSDavide Italiano        char = char.lower()
574205fd03aSDavide Italiano        a = ord(char)
575205fd03aSDavide Italiano        if 97 <= a <= 122:
576205fd03aSDavide Italiano            a = a - ord('a') + 1
577205fd03aSDavide Italiano            byte = _byte(a)
578205fd03aSDavide Italiano            return self._writeb(byte), byte
579205fd03aSDavide Italiano        d = {'@': 0, '`': 0,
580205fd03aSDavide Italiano            '[': 27, '{': 27,
581205fd03aSDavide Italiano            '\\': 28, '|': 28,
582205fd03aSDavide Italiano            ']': 29, '}': 29,
583205fd03aSDavide Italiano            '^': 30, '~': 30,
584205fd03aSDavide Italiano            '_': 31,
585205fd03aSDavide Italiano            '?': 127}
586205fd03aSDavide Italiano        if char not in d:
587205fd03aSDavide Italiano            return 0, b''
588205fd03aSDavide Italiano
589205fd03aSDavide Italiano        byte = _byte(d[char])
590205fd03aSDavide Italiano        return self._writeb(byte), byte
591205fd03aSDavide Italiano
592205fd03aSDavide Italiano    def sendeof(self):
593205fd03aSDavide Italiano        '''This sends an EOF to the child. This sends a character which causes
594205fd03aSDavide Italiano        the pending parent output buffer to be sent to the waiting child
595205fd03aSDavide Italiano        program without waiting for end-of-line. If it is the first character
596205fd03aSDavide Italiano        of the line, the read() in the user program returns 0, which signifies
597205fd03aSDavide Italiano        end-of-file. This means to work as expected a sendeof() has to be
598205fd03aSDavide Italiano        called at the beginning of a line. This method does not send a newline.
599205fd03aSDavide Italiano        It is the responsibility of the caller to ensure the eof is sent at the
600205fd03aSDavide Italiano        beginning of a line. '''
601205fd03aSDavide Italiano
602205fd03aSDavide Italiano        return self._writeb(_EOF), _EOF
603205fd03aSDavide Italiano
604205fd03aSDavide Italiano    def sendintr(self):
605205fd03aSDavide Italiano        '''This sends a SIGINT to the child. It does not require
606205fd03aSDavide Italiano        the SIGINT to be the first character on a line. '''
607205fd03aSDavide Italiano
608205fd03aSDavide Italiano        return self._writeb(_INTR), _INTR
609205fd03aSDavide Italiano
610205fd03aSDavide Italiano    def eof(self):
611205fd03aSDavide Italiano        '''This returns True if the EOF exception was ever raised.
612205fd03aSDavide Italiano        '''
613205fd03aSDavide Italiano
614205fd03aSDavide Italiano        return self.flag_eof
615205fd03aSDavide Italiano
616205fd03aSDavide Italiano    def terminate(self, force=False):
617205fd03aSDavide Italiano        '''This forces a child process to terminate. It starts nicely with
618205fd03aSDavide Italiano        SIGHUP and SIGINT. If "force" is True then moves onto SIGKILL. This
619205fd03aSDavide Italiano        returns True if the child was terminated. This returns False if the
620205fd03aSDavide Italiano        child could not be terminated. '''
621205fd03aSDavide Italiano
622205fd03aSDavide Italiano        if not self.isalive():
623205fd03aSDavide Italiano            return True
624205fd03aSDavide Italiano        try:
625205fd03aSDavide Italiano            self.kill(signal.SIGHUP)
626205fd03aSDavide Italiano            time.sleep(self.delayafterterminate)
627205fd03aSDavide Italiano            if not self.isalive():
628205fd03aSDavide Italiano                return True
629205fd03aSDavide Italiano            self.kill(signal.SIGCONT)
630205fd03aSDavide Italiano            time.sleep(self.delayafterterminate)
631205fd03aSDavide Italiano            if not self.isalive():
632205fd03aSDavide Italiano                return True
633205fd03aSDavide Italiano            self.kill(signal.SIGINT)
634205fd03aSDavide Italiano            time.sleep(self.delayafterterminate)
635205fd03aSDavide Italiano            if not self.isalive():
636205fd03aSDavide Italiano                return True
637205fd03aSDavide Italiano            if force:
638205fd03aSDavide Italiano                self.kill(signal.SIGKILL)
639205fd03aSDavide Italiano                time.sleep(self.delayafterterminate)
640205fd03aSDavide Italiano                if not self.isalive():
641205fd03aSDavide Italiano                    return True
642205fd03aSDavide Italiano                else:
643205fd03aSDavide Italiano                    return False
644205fd03aSDavide Italiano            return False
645205fd03aSDavide Italiano        except OSError:
646205fd03aSDavide Italiano            # I think there are kernel timing issues that sometimes cause
647205fd03aSDavide Italiano            # this to happen. I think isalive() reports True, but the
648205fd03aSDavide Italiano            # process is dead to the kernel.
649205fd03aSDavide Italiano            # Make one last attempt to see if the kernel is up to date.
650205fd03aSDavide Italiano            time.sleep(self.delayafterterminate)
651205fd03aSDavide Italiano            if not self.isalive():
652205fd03aSDavide Italiano                return True
653205fd03aSDavide Italiano            else:
654205fd03aSDavide Italiano                return False
655205fd03aSDavide Italiano
656205fd03aSDavide Italiano    def wait(self):
657205fd03aSDavide Italiano        '''This waits until the child exits. This is a blocking call. This will
658205fd03aSDavide Italiano        not read any data from the child, so this will block forever if the
659205fd03aSDavide Italiano        child has unread output and has terminated. In other words, the child
660205fd03aSDavide Italiano        may have printed output then called exit(), but, the child is
661205fd03aSDavide Italiano        technically still alive until its output is read by the parent. '''
662205fd03aSDavide Italiano
663205fd03aSDavide Italiano        if self.isalive():
664205fd03aSDavide Italiano            pid, status = os.waitpid(self.pid, 0)
665205fd03aSDavide Italiano        else:
666205fd03aSDavide Italiano            return self.exitstatus
667205fd03aSDavide Italiano        self.exitstatus = os.WEXITSTATUS(status)
668205fd03aSDavide Italiano        if os.WIFEXITED(status):
669205fd03aSDavide Italiano            self.status = status
670205fd03aSDavide Italiano            self.exitstatus = os.WEXITSTATUS(status)
671205fd03aSDavide Italiano            self.signalstatus = None
672205fd03aSDavide Italiano            self.terminated = True
673205fd03aSDavide Italiano        elif os.WIFSIGNALED(status):
674205fd03aSDavide Italiano            self.status = status
675205fd03aSDavide Italiano            self.exitstatus = None
676205fd03aSDavide Italiano            self.signalstatus = os.WTERMSIG(status)
677205fd03aSDavide Italiano            self.terminated = True
678205fd03aSDavide Italiano        elif os.WIFSTOPPED(status):  # pragma: no cover
679205fd03aSDavide Italiano            # You can't call wait() on a child process in the stopped state.
680205fd03aSDavide Italiano            raise PtyProcessError('Called wait() on a stopped child ' +
681205fd03aSDavide Italiano                    'process. This is not supported. Is some other ' +
682205fd03aSDavide Italiano                    'process attempting job control with our child pid?')
683205fd03aSDavide Italiano        return self.exitstatus
684205fd03aSDavide Italiano
685205fd03aSDavide Italiano    def isalive(self):
686205fd03aSDavide Italiano        '''This tests if the child process is running or not. This is
687205fd03aSDavide Italiano        non-blocking. If the child was terminated then this will read the
688205fd03aSDavide Italiano        exitstatus or signalstatus of the child. This returns True if the child
689205fd03aSDavide Italiano        process appears to be running or False if not. It can take literally
690205fd03aSDavide Italiano        SECONDS for Solaris to return the right status. '''
691205fd03aSDavide Italiano
692205fd03aSDavide Italiano        if self.terminated:
693205fd03aSDavide Italiano            return False
694205fd03aSDavide Italiano
695205fd03aSDavide Italiano        if self.flag_eof:
696205fd03aSDavide Italiano            # This is for Linux, which requires the blocking form
697205fd03aSDavide Italiano            # of waitpid to get the status of a defunct process.
698205fd03aSDavide Italiano            # This is super-lame. The flag_eof would have been set
699205fd03aSDavide Italiano            # in read_nonblocking(), so this should be safe.
700205fd03aSDavide Italiano            waitpid_options = 0
701205fd03aSDavide Italiano        else:
702205fd03aSDavide Italiano            waitpid_options = os.WNOHANG
703205fd03aSDavide Italiano
704205fd03aSDavide Italiano        try:
705205fd03aSDavide Italiano            pid, status = os.waitpid(self.pid, waitpid_options)
706205fd03aSDavide Italiano        except OSError as e:
707205fd03aSDavide Italiano            # No child processes
708205fd03aSDavide Italiano            if e.errno == errno.ECHILD:
709205fd03aSDavide Italiano                raise PtyProcessError('isalive() encountered condition ' +
710205fd03aSDavide Italiano                        'where "terminated" is 0, but there was no child ' +
711205fd03aSDavide Italiano                        'process. Did someone else call waitpid() ' +
712205fd03aSDavide Italiano                        'on our process?')
713205fd03aSDavide Italiano            else:
714205fd03aSDavide Italiano                raise
715205fd03aSDavide Italiano
716205fd03aSDavide Italiano        # I have to do this twice for Solaris.
717205fd03aSDavide Italiano        # I can't even believe that I figured this out...
718205fd03aSDavide Italiano        # If waitpid() returns 0 it means that no child process
719205fd03aSDavide Italiano        # wishes to report, and the value of status is undefined.
720205fd03aSDavide Italiano        if pid == 0:
721205fd03aSDavide Italiano            try:
722205fd03aSDavide Italiano                ### os.WNOHANG) # Solaris!
723205fd03aSDavide Italiano                pid, status = os.waitpid(self.pid, waitpid_options)
724205fd03aSDavide Italiano            except OSError as e:  # pragma: no cover
725205fd03aSDavide Italiano                # This should never happen...
726205fd03aSDavide Italiano                if e.errno == errno.ECHILD:
727205fd03aSDavide Italiano                    raise PtyProcessError('isalive() encountered condition ' +
728205fd03aSDavide Italiano                            'that should never happen. There was no child ' +
729205fd03aSDavide Italiano                            'process. Did someone else call waitpid() ' +
730205fd03aSDavide Italiano                            'on our process?')
731205fd03aSDavide Italiano                else:
732205fd03aSDavide Italiano                    raise
733205fd03aSDavide Italiano
734205fd03aSDavide Italiano            # If pid is still 0 after two calls to waitpid() then the process
735205fd03aSDavide Italiano            # really is alive. This seems to work on all platforms, except for
736205fd03aSDavide Italiano            # Irix which seems to require a blocking call on waitpid or select,
737205fd03aSDavide Italiano            # so I let read_nonblocking take care of this situation
738205fd03aSDavide Italiano            # (unfortunately, this requires waiting through the timeout).
739205fd03aSDavide Italiano            if pid == 0:
740205fd03aSDavide Italiano                return True
741205fd03aSDavide Italiano
742205fd03aSDavide Italiano        if pid == 0:
743205fd03aSDavide Italiano            return True
744205fd03aSDavide Italiano
745205fd03aSDavide Italiano        if os.WIFEXITED(status):
746205fd03aSDavide Italiano            self.status = status
747205fd03aSDavide Italiano            self.exitstatus = os.WEXITSTATUS(status)
748205fd03aSDavide Italiano            self.signalstatus = None
749205fd03aSDavide Italiano            self.terminated = True
750205fd03aSDavide Italiano        elif os.WIFSIGNALED(status):
751205fd03aSDavide Italiano            self.status = status
752205fd03aSDavide Italiano            self.exitstatus = None
753205fd03aSDavide Italiano            self.signalstatus = os.WTERMSIG(status)
754205fd03aSDavide Italiano            self.terminated = True
755205fd03aSDavide Italiano        elif os.WIFSTOPPED(status):
756205fd03aSDavide Italiano            raise PtyProcessError('isalive() encountered condition ' +
757205fd03aSDavide Italiano                    'where child process is stopped. This is not ' +
758205fd03aSDavide Italiano                    'supported. Is some other process attempting ' +
759205fd03aSDavide Italiano                    'job control with our child pid?')
760205fd03aSDavide Italiano        return False
761205fd03aSDavide Italiano
762205fd03aSDavide Italiano    def kill(self, sig):
763205fd03aSDavide Italiano        """Send the given signal to the child application.
764205fd03aSDavide Italiano
765205fd03aSDavide Italiano        In keeping with UNIX tradition it has a misleading name. It does not
766205fd03aSDavide Italiano        necessarily kill the child unless you send the right signal. See the
767205fd03aSDavide Italiano        :mod:`signal` module for constants representing signal numbers.
768205fd03aSDavide Italiano        """
769205fd03aSDavide Italiano
770205fd03aSDavide Italiano        # Same as os.kill, but the pid is given for you.
771205fd03aSDavide Italiano        if self.isalive():
772205fd03aSDavide Italiano            os.kill(self.pid, sig)
773205fd03aSDavide Italiano
774205fd03aSDavide Italiano    def getwinsize(self):
775205fd03aSDavide Italiano        """Return the window size of the pseudoterminal as a tuple (rows, cols).
776205fd03aSDavide Italiano        """
777205fd03aSDavide Italiano        TIOCGWINSZ = getattr(termios, 'TIOCGWINSZ', 1074295912)
778205fd03aSDavide Italiano        s = struct.pack('HHHH', 0, 0, 0, 0)
779205fd03aSDavide Italiano        x = fcntl.ioctl(self.fd, TIOCGWINSZ, s)
780205fd03aSDavide Italiano        return struct.unpack('HHHH', x)[0:2]
781205fd03aSDavide Italiano
782205fd03aSDavide Italiano    def setwinsize(self, rows, cols):
783205fd03aSDavide Italiano        """Set the terminal window size of the child tty.
784205fd03aSDavide Italiano
785205fd03aSDavide Italiano        This will cause a SIGWINCH signal to be sent to the child. This does not
786205fd03aSDavide Italiano        change the physical window size. It changes the size reported to
787205fd03aSDavide Italiano        TTY-aware applications like vi or curses -- applications that respond to
788205fd03aSDavide Italiano        the SIGWINCH signal.
789205fd03aSDavide Italiano        """
790205fd03aSDavide Italiano        return _setwinsize(self.fd, rows, cols)
791205fd03aSDavide Italiano
792205fd03aSDavide Italiano
793205fd03aSDavide Italianoclass PtyProcessUnicode(PtyProcess):
794205fd03aSDavide Italiano    """Unicode wrapper around a process running in a pseudoterminal.
795205fd03aSDavide Italiano
796205fd03aSDavide Italiano    This class exposes a similar interface to :class:`PtyProcess`, but its read
797205fd03aSDavide Italiano    methods return unicode, and its :meth:`write` accepts unicode.
798205fd03aSDavide Italiano    """
799205fd03aSDavide Italiano    if PY3:
800205fd03aSDavide Italiano        string_type = str
801205fd03aSDavide Italiano    else:
802205fd03aSDavide Italiano        string_type = unicode   # analysis:ignore
803205fd03aSDavide Italiano
804205fd03aSDavide Italiano    def __init__(self, pid, fd, encoding='utf-8', codec_errors='strict'):
805205fd03aSDavide Italiano        super(PtyProcessUnicode, self).__init__(pid, fd)
806205fd03aSDavide Italiano        self.encoding = encoding
807205fd03aSDavide Italiano        self.codec_errors = codec_errors
808205fd03aSDavide Italiano        self.decoder = codecs.getincrementaldecoder(encoding)(errors=codec_errors)
809205fd03aSDavide Italiano
810205fd03aSDavide Italiano    def read(self, size=1024):
811205fd03aSDavide Italiano        """Read at most ``size`` bytes from the pty, return them as unicode.
812205fd03aSDavide Italiano
813205fd03aSDavide Italiano        Can block if there is nothing to read. Raises :exc:`EOFError` if the
814205fd03aSDavide Italiano        terminal was closed.
815205fd03aSDavide Italiano
816205fd03aSDavide Italiano        The size argument still refers to bytes, not unicode code points.
817205fd03aSDavide Italiano        """
818205fd03aSDavide Italiano        b = super(PtyProcessUnicode, self).read(size)
819205fd03aSDavide Italiano        return self.decoder.decode(b, final=False)
820205fd03aSDavide Italiano
821205fd03aSDavide Italiano    def readline(self):
822205fd03aSDavide Italiano        """Read one line from the pseudoterminal, and return it as unicode.
823205fd03aSDavide Italiano
824205fd03aSDavide Italiano        Can block if there is nothing to read. Raises :exc:`EOFError` if the
825205fd03aSDavide Italiano        terminal was closed.
826205fd03aSDavide Italiano        """
827205fd03aSDavide Italiano        b = super(PtyProcessUnicode, self).readline()
828205fd03aSDavide Italiano        return self.decoder.decode(b, final=False)
829205fd03aSDavide Italiano
830205fd03aSDavide Italiano    def write(self, s):
831205fd03aSDavide Italiano        """Write the unicode string ``s`` to the pseudoterminal.
832205fd03aSDavide Italiano
833205fd03aSDavide Italiano        Returns the number of bytes written.
834205fd03aSDavide Italiano        """
835205fd03aSDavide Italiano        b = s.encode(self.encoding)
836205fd03aSDavide Italiano        return super(PtyProcessUnicode, self).write(b)
837