This commit was manufactured by cvs2svn to create tag 'cnrisync'.
[python/dscho.git] / Lib / pty.py
blob53a4b2d3a9f3a3a2a2b5887fdda921ee2592e3af
1 # pty.py -- 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, sys, FCNTL
11 import tty
13 STDIN_FILENO = 0
14 STDOUT_FILENO = 1
15 STDERR_FILENO = 2
17 CHILD = 0
19 # Open pty master. Returns (master_fd, tty_name). SGI and Linux/BSD version.
20 def 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'
41 # Open the pty slave. Acquire the controlling terminal.
42 # Returns file descriptor. Linux version. (Should be universal? --Guido)
43 def slave_open(tty_name):
44 return os.open(tty_name, FCNTL.O_RDWR)
46 # Fork and make the child a session leader with a controlling terminal.
47 # Returns (pid, master_fd)
48 def fork():
49 master_fd, tty_name = master_open()
50 pid = os.fork()
51 if pid == CHILD:
52 # Establish a new session.
53 os.setsid()
55 # Acquire controlling terminal.
56 slave_fd = slave_open(tty_name)
57 os.close(master_fd)
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)
66 # Parent and child process.
67 return pid, master_fd
69 # Write all the data to a descriptor.
70 def writen(fd, data):
71 while data != '':
72 n = os.write(fd, data)
73 data = data[n:]
75 # Default read function.
76 def read(fd):
77 return os.read(fd, 1024)
79 # Parent copy loop.
80 # Copies
81 # pty master -> standard output (master_read)
82 # standard input -> pty master (stdin_read)
83 def 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)
94 # Create a spawned process.
95 def 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)