blob: 2ba193828d7b6bf4f9e6f39686a6032746b89921 [file] [log] [blame]
Guido van Rossum23cb2a81994-09-12 10:36:35 +00001# pty.py -- Pseudo terminal utilities.
2
3# Bugs: No signal handling. Doesn't set slave termios and window size.
4# Only tested on Linux.
5# See: W. Richard Stevens. 1992. Advanced Programming in the
6# UNIX Environment. Chapter 19.
7# Author: Steen Lumholt -- with additions by Guido.
8
9from select import select
Guido van Rossum96d80f91999-05-03 18:13:51 +000010import os, FCNTL
Guido van Rossum23cb2a81994-09-12 10:36:35 +000011import tty
12
13STDIN_FILENO = 0
14STDOUT_FILENO = 1
15STDERR_FILENO = 2
16
17CHILD = 0
18
19# Open pty master. Returns (master_fd, tty_name). SGI and Linux/BSD version.
20def master_open():
21 try:
22 import sgi
23 except ImportError:
24 pass
25 else:
26 try:
27 tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
28 except IOError, msg:
29 raise os.error, msg
30 return master_fd, tty_name
31 for x in 'pqrstuvwxyzPQRST':
32 for y in '0123456789abcdef':
33 pty_name = '/dev/pty' + x + y
34 try:
35 fd = os.open(pty_name, FCNTL.O_RDWR)
36 except os.error:
37 continue
38 return (fd, '/dev/tty' + x + y)
39 raise os.error, 'out of pty devices'
40
41# Open the pty slave. Acquire the controlling terminal.
42# Returns file descriptor. Linux version. (Should be universal? --Guido)
43def slave_open(tty_name):
44 return os.open(tty_name, FCNTL.O_RDWR)
45
46# Fork and make the child a session leader with a controlling terminal.
47# Returns (pid, master_fd)
48def fork():
49 master_fd, tty_name = master_open()
50 pid = os.fork()
51 if pid == CHILD:
52 # Establish a new session.
53 os.setsid()
54
55 # Acquire controlling terminal.
56 slave_fd = slave_open(tty_name)
57 os.close(master_fd)
58
59 # Slave becomes stdin/stdout/stderr of child.
60 os.dup2(slave_fd, STDIN_FILENO)
61 os.dup2(slave_fd, STDOUT_FILENO)
62 os.dup2(slave_fd, STDERR_FILENO)
63 if (slave_fd > STDERR_FILENO):
64 os.close (slave_fd)
65
66 # Parent and child process.
67 return pid, master_fd
68
69# Write all the data to a descriptor.
70def writen(fd, data):
71 while data != '':
72 n = os.write(fd, data)
73 data = data[n:]
74
75# Default read function.
76def read(fd):
77 return os.read(fd, 1024)
78
79# Parent copy loop.
80# Copies
81# pty master -> standard output (master_read)
82# standard input -> pty master (stdin_read)
83def copy(master_fd, master_read=read, stdin_read=read):
84 while 1:
85 rfds, wfds, xfds = select(
86 [master_fd, STDIN_FILENO], [], [])
87 if master_fd in rfds:
88 data = master_read(master_fd)
89 os.write(STDOUT_FILENO, data)
90 if STDIN_FILENO in rfds:
91 data = stdin_read(STDIN_FILENO)
92 writen(master_fd, data)
93
94# Create a spawned process.
95def spawn(argv, master_read=read, stdin_read=read):
96 if type(argv) == type(''):
97 argv = (argv,)
98 pid, master_fd = fork()
99 if pid == CHILD:
100 apply(os.execlp, (argv[0],) + argv)
101 mode = tty.tcgetattr(STDIN_FILENO)
102 tty.setraw(STDIN_FILENO)
103 try:
104 copy(master_fd, master_read, stdin_read)
105 except:
106 tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)