1616
1717CHILD = 0
1818
19+ def openpty ():
20+ """openpty() -> (master_fd, slave_fd)
21+ Open a pty master/slave pair, using os.openpty() if possible."""
22+
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
30+
1931def 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."""
35+
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
44+
45+ return _open_terminal ()
46+
47+ def _open_terminal ():
2048 """Open pty master and return (master_fd, tty_name).
21- SGI and Linux/ BSD version."""
49+ SGI and generic BSD version, for when openpty() fails ."""
2250 try :
2351 import sgi
2452 except ImportError :
@@ -40,22 +68,35 @@ def master_open():
4068 raise os .error , 'out of pty devices'
4169
4270def slave_open (tty_name ):
43- """Open the pty slave and acquire the controlling terminal.
44- Return the file descriptor. Linux version."""
45- # (Should be universal? --Guido)
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."""
75+
4676 return os .open (tty_name , FCNTL .O_RDWR )
4777
4878def fork ():
49- """Fork and make the child a session leader with a controlling terminal.
50- Return (pid, master_fd)."""
51- master_fd , tty_name = master_open ()
79+ """fork() -> (pid, master_fd)
80+ Fork and make the child a session leader with a controlling terminal."""
81+
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
94+
95+ master_fd , slave_fd = openpty ()
5296 pid = os .fork ()
5397 if pid == CHILD :
5498 # Establish a new session.
5599 os .setsid ()
56-
57- # Acquire controlling terminal.
58- slave_fd = slave_open (tty_name )
59100 os .close (master_fd )
60101
61102 # Slave becomes stdin/stdout/stderr of child.
@@ -68,17 +109,17 @@ def fork():
68109 # Parent and child process.
69110 return pid , master_fd
70111
71- def writen (fd , data ):
112+ def _writen (fd , data ):
72113 """Write all the data to a descriptor."""
73114 while data != '' :
74115 n = os .write (fd , data )
75116 data = data [n :]
76117
77- def read (fd ):
118+ def _read (fd ):
78119 """Default read function."""
79120 return os .read (fd , 1024 )
80121
81- def copy (master_fd , master_read = read , stdin_read = read ):
122+ def _copy (master_fd , master_read = _read , stdin_read = _read ):
82123 """Parent copy loop.
83124 Copies
84125 pty master -> standard output (master_read)
@@ -91,9 +132,9 @@ def copy(master_fd, master_read=read, stdin_read=read):
91132 os .write (STDOUT_FILENO , data )
92133 if STDIN_FILENO in rfds :
93134 data = stdin_read (STDIN_FILENO )
94- writen (master_fd , data )
135+ _writen (master_fd , data )
95136
96- def spawn (argv , master_read = read , stdin_read = read ):
137+ def spawn (argv , master_read = _read , stdin_read = _read ):
97138 """Create a spawned process."""
98139 if type (argv ) == type ('' ):
99140 argv = (argv ,)
@@ -103,6 +144,6 @@ def spawn(argv, master_read=read, stdin_read=read):
103144 mode = tty .tcgetattr (STDIN_FILENO )
104145 tty .setraw (STDIN_FILENO )
105146 try :
106- copy (master_fd , master_read , stdin_read )
147+ _copy (master_fd , master_read , stdin_read )
107148 except :
108149 tty .tcsetattr (STDIN_FILENO , tty .TCSAFLUSH , mode )
0 commit comments