Last set of CW Pro 5 projects (probably)
[python/dscho.git] / Lib / pty.py
blob12c9093a24ffa1ddd6fb8c5e0c1f7e02a8706426
1 """Pseudo terminal utilities."""
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.
9 from select import select
10 import os, FCNTL
11 import tty
13 STDIN_FILENO = 0
14 STDOUT_FILENO = 1
15 STDERR_FILENO = 2
17 CHILD = 0
19 def openpty():
20 """openpty() -> (master_fd, slave_fd)
21 Open a pty master/slave pair, using os.openpty() if possible."""
23 try:
24 return os.openpty()
25 except (AttributeError, OSError):
26 pass
27 master_fd, slave_name = _open_terminal()
28 slave_fd = slave_open(slave_name)
29 return master_fd, slave_fd
31 def master_open():
32 """master_open() -> (master_fd, slave_name)
33 Open a pty master and return the fd, and the filename of the slave end.
34 Deprecated, use openpty() instead."""
36 try:
37 master_fd, slave_fd = os.openpty()
38 except (AttributeError, OSError):
39 pass
40 else:
41 slave_name = os.ttyname(slave_fd)
42 os.close(slave_fd)
43 return master_fd, slave_name
45 return _open_terminal()
47 def _open_terminal():
48 """Open pty master and return (master_fd, tty_name).
49 SGI and generic BSD version, for when openpty() fails."""
50 try:
51 import sgi
52 except ImportError:
53 pass
54 else:
55 try:
56 tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
57 except IOError, msg:
58 raise os.error, msg
59 return master_fd, tty_name
60 for x in 'pqrstuvwxyzPQRST':
61 for y in '0123456789abcdef':
62 pty_name = '/dev/pty' + x + y
63 try:
64 fd = os.open(pty_name, FCNTL.O_RDWR)
65 except os.error:
66 continue
67 return (fd, '/dev/tty' + x + y)
68 raise os.error, 'out of pty devices'
70 def slave_open(tty_name):
71 """slave_open(tty_name) -> slave_fd
72 Open the pty slave and acquire the controlling terminal, returning
73 opened filedescriptor.
74 Deprecated, use openpty() instead."""
76 return os.open(tty_name, FCNTL.O_RDWR)
78 def fork():
79 """fork() -> (pid, master_fd)
80 Fork and make the child a session leader with a controlling terminal."""
82 try:
83 pid, fd = os.forkpty()
84 except (AttributeError, OSError):
85 pass
86 else:
87 if pid == CHILD:
88 try:
89 os.setsid()
90 except OSError:
91 # os.forkpty() already set us session leader
92 pass
93 return pid, fd
95 master_fd, slave_fd = openpty()
96 pid = os.fork()
97 if pid == CHILD:
98 # Establish a new session.
99 os.setsid()
100 os.close(master_fd)
102 # Slave becomes stdin/stdout/stderr of child.
103 os.dup2(slave_fd, STDIN_FILENO)
104 os.dup2(slave_fd, STDOUT_FILENO)
105 os.dup2(slave_fd, STDERR_FILENO)
106 if (slave_fd > STDERR_FILENO):
107 os.close (slave_fd)
109 # Parent and child process.
110 return pid, master_fd
112 def _writen(fd, data):
113 """Write all the data to a descriptor."""
114 while data != '':
115 n = os.write(fd, data)
116 data = data[n:]
118 def _read(fd):
119 """Default read function."""
120 return os.read(fd, 1024)
122 def _copy(master_fd, master_read=_read, stdin_read=_read):
123 """Parent copy loop.
124 Copies
125 pty master -> standard output (master_read)
126 standard input -> pty master (stdin_read)"""
127 while 1:
128 rfds, wfds, xfds = select(
129 [master_fd, STDIN_FILENO], [], [])
130 if master_fd in rfds:
131 data = master_read(master_fd)
132 os.write(STDOUT_FILENO, data)
133 if STDIN_FILENO in rfds:
134 data = stdin_read(STDIN_FILENO)
135 _writen(master_fd, data)
137 def spawn(argv, master_read=_read, stdin_read=_read):
138 """Create a spawned process."""
139 if type(argv) == type(''):
140 argv = (argv,)
141 pid, master_fd = fork()
142 if pid == CHILD:
143 apply(os.execlp, (argv[0],) + argv)
144 mode = tty.tcgetattr(STDIN_FILENO)
145 tty.setraw(STDIN_FILENO)
146 try:
147 _copy(master_fd, master_read, stdin_read)
148 except:
149 tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)