blob: a32432041fa1dbe18d0e1f78283559b13e7ca5d1 [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Pseudo terminal utilities."""
Guido van Rossum23cb2a81994-09-12 10:36:35 +00002
3# Bugs: No signal handling. Doesn't set slave termios and window size.
Tim Peters2344fae2001-01-15 00:50:52 +00004# Only tested on Linux.
5# See: W. Richard Stevens. 1992. Advanced Programming in the
6# UNIX Environment. Chapter 19.
Guido van Rossum23cb2a81994-09-12 10:36:35 +00007# Author: Steen Lumholt -- with additions by Guido.
8
9from select import select
Fred Drake66aaaae2001-05-10 05:17:02 +000010import os
Saiyang Gou95f60012020-02-04 16:15:00 -080011import sys
Guido van Rossum23cb2a81994-09-12 10:36:35 +000012import tty
13
Skip Montanaroc62c81e2001-02-12 02:00:42 +000014__all__ = ["openpty","fork","spawn"]
15
Guido van Rossum23cb2a81994-09-12 10:36:35 +000016STDIN_FILENO = 0
17STDOUT_FILENO = 1
18STDERR_FILENO = 2
19
20CHILD = 0
21
Fred Drake8cef4cf2000-06-28 16:40:38 +000022def openpty():
Tim Peters2344fae2001-01-15 00:50:52 +000023 """openpty() -> (master_fd, slave_fd)
24 Open a pty master/slave pair, using os.openpty() if possible."""
Fred Drake8cef4cf2000-06-28 16:40:38 +000025
Tim Peters2344fae2001-01-15 00:50:52 +000026 try:
27 return os.openpty()
28 except (AttributeError, OSError):
29 pass
30 master_fd, slave_name = _open_terminal()
31 slave_fd = slave_open(slave_name)
32 return master_fd, slave_fd
Fred Drake8cef4cf2000-06-28 16:40:38 +000033
Guido van Rossum23cb2a81994-09-12 10:36:35 +000034def master_open():
Tim Peters2344fae2001-01-15 00:50:52 +000035 """master_open() -> (master_fd, slave_name)
36 Open a pty master and return the fd, and the filename of the slave end.
37 Deprecated, use openpty() instead."""
Fred Drake8cef4cf2000-06-28 16:40:38 +000038
Tim Peters2344fae2001-01-15 00:50:52 +000039 try:
40 master_fd, slave_fd = os.openpty()
41 except (AttributeError, OSError):
42 pass
43 else:
44 slave_name = os.ttyname(slave_fd)
45 os.close(slave_fd)
46 return master_fd, slave_name
Fred Drake8cef4cf2000-06-28 16:40:38 +000047
Tim Peters2344fae2001-01-15 00:50:52 +000048 return _open_terminal()
Fred Drake8cef4cf2000-06-28 16:40:38 +000049
50def _open_terminal():
Andrew Kuchlingedf33c02013-06-01 13:52:30 -040051 """Open pty master and return (master_fd, tty_name)."""
Tim Peters2344fae2001-01-15 00:50:52 +000052 for x in 'pqrstuvwxyzPQRST':
53 for y in '0123456789abcdef':
54 pty_name = '/dev/pty' + x + y
55 try:
Fred Drake66aaaae2001-05-10 05:17:02 +000056 fd = os.open(pty_name, os.O_RDWR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +020057 except OSError:
Tim Peters2344fae2001-01-15 00:50:52 +000058 continue
59 return (fd, '/dev/tty' + x + y)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +020060 raise OSError('out of pty devices')
Guido van Rossum23cb2a81994-09-12 10:36:35 +000061
Guido van Rossum23cb2a81994-09-12 10:36:35 +000062def slave_open(tty_name):
Tim Peters2344fae2001-01-15 00:50:52 +000063 """slave_open(tty_name) -> slave_fd
64 Open the pty slave and acquire the controlling terminal, returning
65 opened filedescriptor.
66 Deprecated, use openpty() instead."""
Fred Drake8cef4cf2000-06-28 16:40:38 +000067
Martin v. Löwis14e73b12003-01-01 09:51:12 +000068 result = os.open(tty_name, os.O_RDWR)
69 try:
70 from fcntl import ioctl, I_PUSH
Brett Cannoncd171c82013-07-04 17:43:24 -040071 except ImportError:
Martin v. Löwis14e73b12003-01-01 09:51:12 +000072 return result
73 try:
Tim Peters2c60f7a2003-01-29 03:49:43 +000074 ioctl(result, I_PUSH, "ptem")
75 ioctl(result, I_PUSH, "ldterm")
Andrew Svetlovf7a17b42012-12-25 16:47:37 +020076 except OSError:
Martin v. Löwis14e73b12003-01-01 09:51:12 +000077 pass
78 return result
Guido van Rossum23cb2a81994-09-12 10:36:35 +000079
Guido van Rossum23cb2a81994-09-12 10:36:35 +000080def fork():
Tim Peters2344fae2001-01-15 00:50:52 +000081 """fork() -> (pid, master_fd)
82 Fork and make the child a session leader with a controlling terminal."""
Fred Drake8cef4cf2000-06-28 16:40:38 +000083
Tim Peters2344fae2001-01-15 00:50:52 +000084 try:
85 pid, fd = os.forkpty()
86 except (AttributeError, OSError):
87 pass
88 else:
89 if pid == CHILD:
90 try:
91 os.setsid()
92 except OSError:
93 # os.forkpty() already set us session leader
94 pass
95 return pid, fd
Fred Drake8cef4cf2000-06-28 16:40:38 +000096
Tim Peters2344fae2001-01-15 00:50:52 +000097 master_fd, slave_fd = openpty()
98 pid = os.fork()
99 if pid == CHILD:
100 # Establish a new session.
101 os.setsid()
102 os.close(master_fd)
Guido van Rossum23cb2a81994-09-12 10:36:35 +0000103
Tim Peters2344fae2001-01-15 00:50:52 +0000104 # Slave becomes stdin/stdout/stderr of child.
105 os.dup2(slave_fd, STDIN_FILENO)
106 os.dup2(slave_fd, STDOUT_FILENO)
107 os.dup2(slave_fd, STDERR_FILENO)
108 if (slave_fd > STDERR_FILENO):
109 os.close (slave_fd)
Guido van Rossum23cb2a81994-09-12 10:36:35 +0000110
Thomas Wouters89f507f2006-12-13 04:49:30 +0000111 # Explicitly open the tty to make it become a controlling tty.
112 tmp_fd = os.open(os.ttyname(STDOUT_FILENO), os.O_RDWR)
113 os.close(tmp_fd)
Thomas Wouters902d6eb2007-01-09 23:18:33 +0000114 else:
115 os.close(slave_fd)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000116
Tim Peters2344fae2001-01-15 00:50:52 +0000117 # Parent and child process.
118 return pid, master_fd
Guido van Rossum23cb2a81994-09-12 10:36:35 +0000119
Fred Drake8cef4cf2000-06-28 16:40:38 +0000120def _writen(fd, data):
Tim Peters2344fae2001-01-15 00:50:52 +0000121 """Write all the data to a descriptor."""
Antoine Pitrou9cadb1b2008-09-15 23:02:56 +0000122 while data:
Tim Peters2344fae2001-01-15 00:50:52 +0000123 n = os.write(fd, data)
124 data = data[n:]
Guido van Rossum23cb2a81994-09-12 10:36:35 +0000125
Fred Drake8cef4cf2000-06-28 16:40:38 +0000126def _read(fd):
Tim Peters2344fae2001-01-15 00:50:52 +0000127 """Default read function."""
128 return os.read(fd, 1024)
Guido van Rossum23cb2a81994-09-12 10:36:35 +0000129
Fred Drake8cef4cf2000-06-28 16:40:38 +0000130def _copy(master_fd, master_read=_read, stdin_read=_read):
Tim Peters2344fae2001-01-15 00:50:52 +0000131 """Parent copy loop.
132 Copies
133 pty master -> standard output (master_read)
134 standard input -> pty master (stdin_read)"""
Gregory P. Smith05f59532012-02-16 00:29:12 -0800135 fds = [master_fd, STDIN_FILENO]
136 while True:
137 rfds, wfds, xfds = select(fds, [], [])
Tim Peters2344fae2001-01-15 00:50:52 +0000138 if master_fd in rfds:
139 data = master_read(master_fd)
Gregory P. Smith05f59532012-02-16 00:29:12 -0800140 if not data: # Reached EOF.
141 fds.remove(master_fd)
142 else:
143 os.write(STDOUT_FILENO, data)
Tim Peters2344fae2001-01-15 00:50:52 +0000144 if STDIN_FILENO in rfds:
145 data = stdin_read(STDIN_FILENO)
Gregory P. Smith05f59532012-02-16 00:29:12 -0800146 if not data:
147 fds.remove(STDIN_FILENO)
148 else:
149 _writen(master_fd, data)
Guido van Rossum23cb2a81994-09-12 10:36:35 +0000150
Fred Drake8cef4cf2000-06-28 16:40:38 +0000151def spawn(argv, master_read=_read, stdin_read=_read):
Tim Peters2344fae2001-01-15 00:50:52 +0000152 """Create a spawned process."""
153 if type(argv) == type(''):
154 argv = (argv,)
Saiyang Gou95f60012020-02-04 16:15:00 -0800155 sys.audit('pty.spawn', argv)
Tim Peters2344fae2001-01-15 00:50:52 +0000156 pid, master_fd = fork()
157 if pid == CHILD:
Guido van Rossum68468eb2003-02-27 20:14:51 +0000158 os.execlp(argv[0], *argv)
Martin v. Löwis6c611fa2002-07-28 09:42:57 +0000159 try:
160 mode = tty.tcgetattr(STDIN_FILENO)
161 tty.setraw(STDIN_FILENO)
162 restore = 1
163 except tty.error: # This is the same as termios.error
164 restore = 0
Tim Peters2344fae2001-01-15 00:50:52 +0000165 try:
166 _copy(master_fd, master_read, stdin_read)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200167 except OSError:
Martin v. Löwis6c611fa2002-07-28 09:42:57 +0000168 if restore:
169 tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
Andrew M. Kuchlinga2c9a982004-06-05 16:27:16 +0000170
171 os.close(master_fd)
Gregory P. Smith0f21adf72012-09-29 12:41:03 -0700172 return os.waitpid(pid, 0)[1]