| """Pseudo terminal utilities.""" | 
 |  | 
 | # Bugs: No signal handling.  Doesn't set slave termios and window size. | 
 | #	Only tested on Linux. | 
 | # See:  W. Richard Stevens. 1992.  Advanced Programming in the  | 
 | #	UNIX Environment.  Chapter 19. | 
 | # Author: Steen Lumholt -- with additions by Guido. | 
 |  | 
 | from select import select | 
 | import os, FCNTL | 
 | import tty | 
 |  | 
 | STDIN_FILENO = 0 | 
 | STDOUT_FILENO = 1 | 
 | STDERR_FILENO = 2 | 
 |  | 
 | CHILD = 0 | 
 |  | 
 | def openpty(): | 
 | 	"""openpty() -> (master_fd, slave_fd) | 
 | 	Open a pty master/slave pair, using os.openpty() if possible.""" | 
 |  | 
 | 	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 | 
 |  | 
 | def master_open(): | 
 | 	"""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.""" | 
 |  | 
 | 	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 | 
 |  | 
 | 	return _open_terminal() | 
 |  | 
 | def _open_terminal(): | 
 | 	"""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: | 
 | 		    tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0) | 
 | 		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: | 
 | 				fd = os.open(pty_name, FCNTL.O_RDWR) | 
 | 			except os.error: | 
 | 				continue | 
 | 			return (fd, '/dev/tty' + x + y) | 
 | 	raise os.error, 'out of pty devices' | 
 |  | 
 | def slave_open(tty_name): | 
 | 	"""slave_open(tty_name) -> slave_fd | 
 | 	Open the pty slave and acquire the controlling terminal, returning | 
 | 	opened filedescriptor. | 
 | 	Deprecated, use openpty() instead.""" | 
 |  | 
 | 	return os.open(tty_name, FCNTL.O_RDWR) | 
 |  | 
 | def fork(): | 
 | 	"""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 | 
 |  | 
 | def _writen(fd, data): | 
 | 	"""Write all the data to a descriptor.""" | 
 | 	while data != '': | 
 | 		n = os.write(fd, data) | 
 | 		data = data[n:] | 
 |  | 
 | def _read(fd): | 
 | 	"""Default read function.""" | 
 | 	return os.read(fd, 1024) | 
 |  | 
 | def _copy(master_fd, master_read=_read, stdin_read=_read): | 
 | 	"""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) | 
 |  | 
 | def spawn(argv, master_read=_read, stdin_read=_read): | 
 | 	"""Create a spawned process.""" | 
 | 	if type(argv) == type(''): | 
 | 		argv = (argv,) | 
 | 	pid, master_fd = fork() | 
 | 	if pid == CHILD: | 
 | 		apply(os.execlp, (argv[0],) + argv) | 
 | 	mode = tty.tcgetattr(STDIN_FILENO) | 
 | 	tty.setraw(STDIN_FILENO) | 
 | 	try: | 
 | 		_copy(master_fd, master_read, stdin_read) | 
 | 	except: | 
 | 		tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode) |