| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  | """Pseudo terminal utilities.""" | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Bugs: No signal handling.  Doesn't set slave termios and window size. | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  | #       Only tested on Linux. | 
					
						
							|  |  |  | # See:  W. Richard Stevens. 1992.  Advanced Programming in the | 
					
						
							|  |  |  | #       UNIX Environment.  Chapter 19. | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | # Author: Steen Lumholt -- with additions by Guido. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from select import select | 
					
						
							| 
									
										
										
										
											2001-05-10 05:17:02 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2001-05-13 09:01:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Absurd:  import termios and then delete it.  This is to force an attempt | 
					
						
							|  |  |  | # to import pty to raise an ImportError on platforms that lack termios. | 
					
						
							|  |  |  | # Without this explicit import of termios here, some other module may | 
					
						
							|  |  |  | # import tty first, which in turn imports termios and dies with an | 
					
						
							|  |  |  | # ImportError then.  But since tty *does* exist across platforms, that | 
					
						
							|  |  |  | # leaves a damaged module object for tty in sys.modules, and the import | 
					
						
							|  |  |  | # of tty here then appears to work despite that the tty imported is junk. | 
					
						
							| 
									
										
										
										
											2001-05-29 06:06:54 +00:00
										 |  |  | import termios | 
					
						
							| 
									
										
										
										
											2001-05-13 09:01:06 +00:00
										 |  |  | del termios | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | import tty | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-02-12 02:00:42 +00:00
										 |  |  | __all__ = ["openpty","fork","spawn"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | STDIN_FILENO = 0 | 
					
						
							|  |  |  | STDOUT_FILENO = 1 | 
					
						
							|  |  |  | STDERR_FILENO = 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CHILD = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | def openpty(): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """openpty() -> (master_fd, slave_fd)
 | 
					
						
							|  |  |  |     Open a pty master/slave pair, using os.openpty() if possible."""
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         return os.openpty() | 
					
						
							|  |  |  |     except (AttributeError, OSError): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     master_fd, slave_name = _open_terminal() | 
					
						
							|  |  |  |     slave_fd = slave_open(slave_name) | 
					
						
							|  |  |  |     return master_fd, slave_fd | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | def master_open(): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """master_open() -> (master_fd, slave_name)
 | 
					
						
							|  |  |  |     Open a pty master and return the fd, and the filename of the slave end. | 
					
						
							|  |  |  |     Deprecated, use openpty() instead."""
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         master_fd, slave_fd = os.openpty() | 
					
						
							|  |  |  |     except (AttributeError, OSError): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         slave_name = os.ttyname(slave_fd) | 
					
						
							|  |  |  |         os.close(slave_fd) | 
					
						
							|  |  |  |         return master_fd, slave_name | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     return _open_terminal() | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def _open_terminal(): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """Open pty master and return (master_fd, tty_name).
 | 
					
						
							|  |  |  |     SGI and generic BSD version, for when openpty() fails."""
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import sgi | 
					
						
							|  |  |  |     except ImportError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2001-05-10 05:17:02 +00:00
										 |  |  |             tty_name, master_fd = sgi._getpty(os.O_RDWR, 0666, 0) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         except IOError, msg: | 
					
						
							|  |  |  |             raise os.error, msg | 
					
						
							|  |  |  |         return master_fd, tty_name | 
					
						
							|  |  |  |     for x in 'pqrstuvwxyzPQRST': | 
					
						
							|  |  |  |         for y in '0123456789abcdef': | 
					
						
							|  |  |  |             pty_name = '/dev/pty' + x + y | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2001-05-10 05:17:02 +00:00
										 |  |  |                 fd = os.open(pty_name, os.O_RDWR) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |             except os.error: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             return (fd, '/dev/tty' + x + y) | 
					
						
							|  |  |  |     raise os.error, 'out of pty devices' | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def slave_open(tty_name): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """slave_open(tty_name) -> slave_fd
 | 
					
						
							|  |  |  |     Open the pty slave and acquire the controlling terminal, returning | 
					
						
							|  |  |  |     opened filedescriptor. | 
					
						
							|  |  |  |     Deprecated, use openpty() instead."""
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-05-10 05:17:02 +00:00
										 |  |  |     return os.open(tty_name, os.O_RDWR) | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def fork(): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """fork() -> (pid, master_fd)
 | 
					
						
							|  |  |  |     Fork and make the child a session leader with a controlling terminal."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         pid, fd = os.forkpty() | 
					
						
							|  |  |  |     except (AttributeError, OSError): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         if pid == CHILD: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 os.setsid() | 
					
						
							|  |  |  |             except OSError: | 
					
						
							|  |  |  |                 # os.forkpty() already set us session leader | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |         return pid, fd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     master_fd, slave_fd = openpty() | 
					
						
							|  |  |  |     pid = os.fork() | 
					
						
							|  |  |  |     if pid == CHILD: | 
					
						
							|  |  |  |         # Establish a new session. | 
					
						
							|  |  |  |         os.setsid() | 
					
						
							|  |  |  |         os.close(master_fd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Slave becomes stdin/stdout/stderr of child. | 
					
						
							|  |  |  |         os.dup2(slave_fd, STDIN_FILENO) | 
					
						
							|  |  |  |         os.dup2(slave_fd, STDOUT_FILENO) | 
					
						
							|  |  |  |         os.dup2(slave_fd, STDERR_FILENO) | 
					
						
							|  |  |  |         if (slave_fd > STDERR_FILENO): | 
					
						
							|  |  |  |             os.close (slave_fd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Parent and child process. | 
					
						
							|  |  |  |     return pid, master_fd | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | def _writen(fd, data): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """Write all the data to a descriptor.""" | 
					
						
							|  |  |  |     while data != '': | 
					
						
							|  |  |  |         n = os.write(fd, data) | 
					
						
							|  |  |  |         data = data[n:] | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | def _read(fd): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """Default read function.""" | 
					
						
							|  |  |  |     return os.read(fd, 1024) | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | def _copy(master_fd, master_read=_read, stdin_read=_read): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """Parent copy loop.
 | 
					
						
							|  |  |  |     Copies | 
					
						
							|  |  |  |             pty master -> standard output   (master_read) | 
					
						
							|  |  |  |             standard input -> pty master    (stdin_read)"""
 | 
					
						
							|  |  |  |     while 1: | 
					
						
							|  |  |  |         rfds, wfds, xfds = select( | 
					
						
							|  |  |  |                 [master_fd, STDIN_FILENO], [], []) | 
					
						
							|  |  |  |         if master_fd in rfds: | 
					
						
							|  |  |  |             data = master_read(master_fd) | 
					
						
							|  |  |  |             os.write(STDOUT_FILENO, data) | 
					
						
							|  |  |  |         if STDIN_FILENO in rfds: | 
					
						
							|  |  |  |             data = stdin_read(STDIN_FILENO) | 
					
						
							|  |  |  |             _writen(master_fd, data) | 
					
						
							| 
									
										
										
										
											1994-09-12 10:36:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-06-28 16:40:38 +00:00
										 |  |  | def spawn(argv, master_read=_read, stdin_read=_read): | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """Create a spawned process.""" | 
					
						
							|  |  |  |     if type(argv) == type(''): | 
					
						
							|  |  |  |         argv = (argv,) | 
					
						
							|  |  |  |     pid, master_fd = fork() | 
					
						
							|  |  |  |     if pid == CHILD: | 
					
						
							|  |  |  |         apply(os.execlp, (argv[0],) + argv) | 
					
						
							| 
									
										
										
										
											2002-07-28 09:42:57 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         mode = tty.tcgetattr(STDIN_FILENO) | 
					
						
							|  |  |  |         tty.setraw(STDIN_FILENO) | 
					
						
							|  |  |  |         restore = 1 | 
					
						
							|  |  |  |     except tty.error:    # This is the same as termios.error | 
					
						
							|  |  |  |         restore = 0 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         _copy(master_fd, master_read, stdin_read) | 
					
						
							| 
									
										
										
										
											2002-07-28 09:42:57 +00:00
										 |  |  |     except (IOError, OSError): | 
					
						
							|  |  |  |         if restore: | 
					
						
							|  |  |  |             tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode) |