+++ /dev/null
-"""Pseudo terminal utilities."""\r
-\r
-# Bugs: No signal handling. Doesn't set slave termios and window size.\r
-# Only tested on Linux.\r
-# See: W. Richard Stevens. 1992. Advanced Programming in the\r
-# UNIX Environment. Chapter 19.\r
-# Author: Steen Lumholt -- with additions by Guido.\r
-\r
-from select import select, error\r
-import os\r
-\r
-# Absurd: import termios and then delete it. This is to force an attempt\r
-# to import pty to raise an ImportError on platforms that lack termios.\r
-# Without this explicit import of termios here, some other module may\r
-# import tty first, which in turn imports termios and dies with an\r
-# ImportError then. But since tty *does* exist across platforms, that\r
-# leaves a damaged module object for tty in sys.modules, and the import\r
-# of tty here then appears to work despite that the tty imported is junk.\r
-import termios\r
-del termios\r
-\r
-import tty\r
-\r
-__all__ = ["openpty","fork","spawn","th_spawn","popen2"]\r
-\r
-STDIN_FILENO = 0\r
-STDOUT_FILENO = 1\r
-STDERR_FILENO = 2\r
-\r
-CHILD = 0\r
-\r
-def openpty():\r
- """openpty() -> (master_fd, slave_fd)\r
- Open a pty master/slave pair, using os.openpty() if possible."""\r
-\r
- try:\r
- return os.openpty()\r
- except (AttributeError, OSError):\r
- pass\r
- master_fd, slave_name = _open_terminal()\r
- slave_fd = slave_open(slave_name)\r
- return master_fd, slave_fd\r
-\r
-def master_open():\r
- """master_open() -> (master_fd, slave_name)\r
- Open a pty master and return the fd, and the filename of the slave end.\r
- Deprecated, use openpty() instead."""\r
-\r
- try:\r
- master_fd, slave_fd = os.openpty()\r
- except (AttributeError, OSError):\r
- pass\r
- else:\r
- slave_name = os.ttyname(slave_fd)\r
- os.close(slave_fd)\r
- return master_fd, slave_name\r
-\r
- return _open_terminal()\r
-\r
-def _open_terminal():\r
- """Open pty master and return (master_fd, tty_name).\r
- SGI and generic BSD version, for when openpty() fails."""\r
- try:\r
- import sgi\r
- except ImportError:\r
- pass\r
- else:\r
- try:\r
- tty_name, master_fd = sgi._getpty(os.O_RDWR, 0666, 0)\r
- except IOError, msg:\r
- raise os.error, msg\r
- return master_fd, tty_name\r
- for x in 'pqrstuvwxyzPQRST':\r
- for y in '0123456789abcdef':\r
- pty_name = '/dev/pty' + x + y\r
- try:\r
- fd = os.open(pty_name, os.O_RDWR)\r
- except os.error:\r
- continue\r
- return (fd, '/dev/tty' + x + y)\r
- raise os.error, 'out of pty devices'\r
-\r
-def slave_open(tty_name):\r
- """slave_open(tty_name) -> slave_fd\r
- Open the pty slave and acquire the controlling terminal, returning\r
- opened filedescriptor.\r
- Deprecated, use openpty() instead."""\r
-\r
- return os.open(tty_name, os.O_RDWR)\r
-\r
-def fork():\r
- """fork() -> (pid, master_fd)\r
- Fork and make the child a session leader with a controlling terminal."""\r
-\r
- try:\r
- pid, fd = os.forkpty()\r
- except (AttributeError, OSError):\r
- pass\r
- else:\r
- if pid == CHILD:\r
- try:\r
- os.setsid()\r
- except OSError:\r
- # os.forkpty() already set us session leader\r
- pass\r
- return pid, fd\r
-\r
- master_fd, slave_fd = openpty()\r
- pid = os.fork()\r
- if pid == CHILD:\r
- # Establish a new session.\r
- os.setsid()\r
- os.close(master_fd)\r
-\r
- # Slave becomes stdin/stdout/stderr of child.\r
- os.dup2(slave_fd, STDIN_FILENO)\r
- os.dup2(slave_fd, STDOUT_FILENO)\r
- os.dup2(slave_fd, STDERR_FILENO)\r
- if (slave_fd > STDERR_FILENO):\r
- os.close (slave_fd)\r
-\r
- # Parent and child process.\r
- return pid, master_fd\r
-\r
-def _writen(fd, data):\r
- """Write all the data to a descriptor."""\r
- while data != '':\r
- n = os.write(fd, data)\r
- data = data[n:]\r
-\r
-def _read(fd):\r
- """Default read function."""\r
- return os.read(fd, 1024)\r
-\r
-def _copy(master_fd, master_read=_read, stdin_read=_read, stdin_fd=STDIN_FILENO,\r
- stdout_fd=STDOUT_FILENO):\r
- """Parent copy loop.\r
- Copies\r
- pty master -> stdout_fd (master_read)\r
- stdin_fd -> pty master (stdin_read)"""\r
- try:\r
- mode = tty.tcgetattr(stdin_fd)\r
- tty.setraw(stdin_fd)\r
- restore = 1\r
- except tty.error: # This is the same as termios.error\r
- restore = 0\r
- try:\r
- while 1:\r
- rfds, wfds, xfds = select(\r
- [master_fd, stdin_fd], [], [])\r
- if master_fd in rfds:\r
- data = master_read(master_fd)\r
- os.write(stdout_fd, data)\r
- if stdin_fd in rfds:\r
- data = stdin_read(stdin_fd)\r
- _writen(master_fd, data)\r
- except (IOError, OSError, error): # The last entry is select.error\r
- if restore:\r
- tty.tcsetattr(stdin_fd, tty.TCSAFLUSH, mode)\r
- if stdin_fd > STDERR_FILENO:\r
- os.close(stdin_fd)\r
- if stdout_fd > STDERR_FILENO:\r
- os.close(stdout_fd)\r
-\r
-def spawn(argv, master_read=_read, stdin_read=_read, stdin_fd=STDIN_FILENO,\r
- stdout_fd=STDOUT_FILENO):\r
- """Create a spawned process. The controlling terminal reads and\r
- writes its data to stdin_fd and stdout_fd respectively.\r
- \r
- NOTE: This function does not return until one of the input or output file\r
- descriptors are closed, or the child process exits."""\r
- if type(argv) == type(''):\r
- argv = (argv,)\r
- pid, master_fd = fork()\r
- if pid == CHILD:\r
- apply(os.execlp, (argv[0],) + argv)\r
- _copy(master_fd, master_read, stdin_read, stdin_fd, stdout_fd)\r
-\r
-def th_spawn(argv, master_read=_read, stdin_read=_read, stdin_fd=STDIN_FILENO,\r
- stdout_fd=STDOUT_FILENO):\r
- """Create a spawned process. The controlling terminal reads and\r
- writes its data to stdin_fd and stdout_fd respectively. The function\r
- returns the pid of the spawned process. (It returns immediately.)"""\r
- import thread\r
- if type(argv) == type(''):\r
- argv = (argv,)\r
- pid, master_fd = fork()\r
- if pid == CHILD:\r
- apply(os.execlp, (argv[0],) + argv)\r
- thread.start_new_thread(_copy, (master_fd, master_read, stdin_read, \\r
- stdin_fd, stdout_fd))\r
- return pid\r
-\r
-def popen2(cmd, bufsize=1024, master_read=_read, stdin_read=_read):\r
- """Execute the shell command 'cmd' in a sub-process.\r
- \r
- If 'bufsize' is specified, it sets the buffer size for the I/O pipes.\r
- The function returns (child_stdin, child_stdout, child_pid), where the\r
- file objects are pipes connected to the spawned process's controling\r
- terminal, and the child_pid is the pid of the child process.\r
- """\r
- argv = ('/bin/sh', '-c', cmd)\r
- child_stdin_rfd, child_stdin_wfd = os.pipe()\r
- child_stdout_rfd, child_stdout_wfd = os.pipe()\r
- child_pid = th_spawn(argv, master_read, stdin_read, child_stdin_rfd, \\r
- child_stdout_wfd)\r
- child_stdin = os.fdopen(child_stdin_wfd, 'w', bufsize)\r
- child_stdout = os.fdopen(child_stdout_rfd, 'r', bufsize)\r
- return child_stdin, child_stdout, child_pid\r