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