summaryrefslogtreecommitdiffstats
path: root/Lib/pty.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/pty.py')
-rw-r--r--Lib/pty.py106
1 files changed, 106 insertions, 0 deletions
diff --git a/Lib/pty.py b/Lib/pty.py
new file mode 100644
index 0000000..53a4b2d
--- /dev/null
+++ b/Lib/pty.py
@@ -0,0 +1,106 @@
+# pty.py -- Pseudo terminal utilities.
+
+# Bugs: No signal handling. Doesn't set slave termios and window size.
+# Only tested on Linux.
+# See: W. Richard Stevens. 1992. Advanced Programming in the
+# UNIX Environment. Chapter 19.
+# Author: Steen Lumholt -- with additions by Guido.
+
+from select import select
+import os, sys, FCNTL
+import tty
+
+STDIN_FILENO = 0
+STDOUT_FILENO = 1
+STDERR_FILENO = 2
+
+CHILD = 0
+
+# Open pty master. Returns (master_fd, tty_name). SGI and Linux/BSD version.
+def master_open():
+ try:
+ import sgi
+ except ImportError:
+ pass
+ else:
+ try:
+ tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
+ except IOError, msg:
+ raise os.error, msg
+ return master_fd, tty_name
+ for x in 'pqrstuvwxyzPQRST':
+ for y in '0123456789abcdef':
+ pty_name = '/dev/pty' + x + y
+ try:
+ fd = os.open(pty_name, FCNTL.O_RDWR)
+ except os.error:
+ continue
+ return (fd, '/dev/tty' + x + y)
+ raise os.error, 'out of pty devices'
+
+# Open the pty slave. Acquire the controlling terminal.
+# Returns file descriptor. Linux version. (Should be universal? --Guido)
+def slave_open(tty_name):
+ return os.open(tty_name, FCNTL.O_RDWR)
+
+# Fork and make the child a session leader with a controlling terminal.
+# Returns (pid, master_fd)
+def fork():
+ master_fd, tty_name = master_open()
+ pid = os.fork()
+ if pid == CHILD:
+ # Establish a new session.
+ os.setsid()
+
+ # Acquire controlling terminal.
+ slave_fd = slave_open(tty_name)
+ os.close(master_fd)
+
+ # Slave becomes stdin/stdout/stderr of child.
+ os.dup2(slave_fd, STDIN_FILENO)
+ os.dup2(slave_fd, STDOUT_FILENO)
+ os.dup2(slave_fd, STDERR_FILENO)
+ if (slave_fd > STDERR_FILENO):
+ os.close (slave_fd)
+
+ # Parent and child process.
+ return pid, master_fd
+
+# Write all the data to a descriptor.
+def writen(fd, data):
+ while data != '':
+ n = os.write(fd, data)
+ data = data[n:]
+
+# Default read function.
+def read(fd):
+ return os.read(fd, 1024)
+
+# Parent copy loop.
+# Copies
+# pty master -> standard output (master_read)
+# standard input -> pty master (stdin_read)
+def copy(master_fd, master_read=read, stdin_read=read):
+ while 1:
+ rfds, wfds, xfds = select(
+ [master_fd, STDIN_FILENO], [], [])
+ if master_fd in rfds:
+ data = master_read(master_fd)
+ os.write(STDOUT_FILENO, data)
+ if STDIN_FILENO in rfds:
+ data = stdin_read(STDIN_FILENO)
+ writen(master_fd, data)
+
+# Create a spawned process.
+def spawn(argv, master_read=read, stdin_read=read):
+ if type(argv) == type(''):
+ argv = (argv,)
+ pid, master_fd = fork()
+ if pid == CHILD:
+ apply(os.execlp, (argv[0],) + argv)
+ mode = tty.tcgetattr(STDIN_FILENO)
+ tty.setraw(STDIN_FILENO)
+ try:
+ copy(master_fd, master_read, stdin_read)
+ except:
+ tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)