home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activepython / ActivePython-2.1.1.msi / Python21_Lib_pty.py < prev    next >
Encoding:
Python Source  |  2001-07-26  |  4.3 KB  |  152 lines

  1. """Pseudo terminal utilities."""
  2.  
  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.
  8.  
  9. from select import select
  10. import os, FCNTL
  11. import tty
  12.  
  13. __all__ = ["openpty","fork","spawn"]
  14.  
  15. STDIN_FILENO = 0
  16. STDOUT_FILENO = 1
  17. STDERR_FILENO = 2
  18.  
  19. CHILD = 0
  20.  
  21. def openpty():
  22.     """openpty() -> (master_fd, slave_fd)
  23.     Open a pty master/slave pair, using os.openpty() if possible."""
  24.  
  25.     try:
  26.         return os.openpty()
  27.     except (AttributeError, OSError):
  28.         pass
  29.     master_fd, slave_name = _open_terminal()
  30.     slave_fd = slave_open(slave_name)
  31.     return master_fd, slave_fd
  32.  
  33. def master_open():
  34.     """master_open() -> (master_fd, slave_name)
  35.     Open a pty master and return the fd, and the filename of the slave end.
  36.     Deprecated, use openpty() instead."""
  37.  
  38.     try:
  39.         master_fd, slave_fd = os.openpty()
  40.     except (AttributeError, OSError):
  41.         pass
  42.     else:
  43.         slave_name = os.ttyname(slave_fd)
  44.         os.close(slave_fd)
  45.         return master_fd, slave_name
  46.  
  47.     return _open_terminal()
  48.  
  49. def _open_terminal():
  50.     """Open pty master and return (master_fd, tty_name).
  51.     SGI and generic BSD version, for when openpty() fails."""
  52.     try:
  53.         import sgi
  54.     except ImportError:
  55.         pass
  56.     else:
  57.         try:
  58.             tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
  59.         except IOError, msg:
  60.             raise os.error, msg
  61.         return master_fd, tty_name
  62.     for x in 'pqrstuvwxyzPQRST':
  63.         for y in '0123456789abcdef':
  64.             pty_name = '/dev/pty' + x + y
  65.             try:
  66.                 fd = os.open(pty_name, FCNTL.O_RDWR)
  67.             except os.error:
  68.                 continue
  69.             return (fd, '/dev/tty' + x + y)
  70.     raise os.error, 'out of pty devices'
  71.  
  72. def slave_open(tty_name):
  73.     """slave_open(tty_name) -> slave_fd
  74.     Open the pty slave and acquire the controlling terminal, returning
  75.     opened filedescriptor.
  76.     Deprecated, use openpty() instead."""
  77.  
  78.     return os.open(tty_name, FCNTL.O_RDWR)
  79.  
  80. def fork():
  81.     """fork() -> (pid, master_fd)
  82.     Fork and make the child a session leader with a controlling terminal."""
  83.  
  84.     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
  96.  
  97.     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)
  103.  
  104.         # 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)
  110.  
  111.     # Parent and child process.
  112.     return pid, master_fd
  113.  
  114. def _writen(fd, data):
  115.     """Write all the data to a descriptor."""
  116.     while data != '':
  117.         n = os.write(fd, data)
  118.         data = data[n:]
  119.  
  120. def _read(fd):
  121.     """Default read function."""
  122.     return os.read(fd, 1024)
  123.  
  124. def _copy(master_fd, master_read=_read, stdin_read=_read):
  125.     """Parent copy loop.
  126.     Copies
  127.             pty master -> standard output   (master_read)
  128.             standard input -> pty master    (stdin_read)"""
  129.     while 1:
  130.         rfds, wfds, xfds = select(
  131.                 [master_fd, STDIN_FILENO], [], [])
  132.         if master_fd in rfds:
  133.             data = master_read(master_fd)
  134.             os.write(STDOUT_FILENO, data)
  135.         if STDIN_FILENO in rfds:
  136.             data = stdin_read(STDIN_FILENO)
  137.             _writen(master_fd, data)
  138.  
  139. def spawn(argv, master_read=_read, stdin_read=_read):
  140.     """Create a spawned process."""
  141.     if type(argv) == type(''):
  142.         argv = (argv,)
  143.     pid, master_fd = fork()
  144.     if pid == CHILD:
  145.         apply(os.execlp, (argv[0],) + argv)
  146.     mode = tty.tcgetattr(STDIN_FILENO)
  147.     tty.setraw(STDIN_FILENO)
  148.     try:
  149.         _copy(master_fd, master_read, stdin_read)
  150.     except:
  151.         tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
  152.