home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / !!!python!!! / BeOpen-Python-2.0.exe / PTY.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  3.7 KB  |  150 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. STDIN_FILENO = 0
  14. STDOUT_FILENO = 1
  15. STDERR_FILENO = 2
  16.  
  17. CHILD = 0
  18.  
  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.  
  31. def 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():
  48.     """Open pty master and return (master_fd, tty_name).
  49.     SGI and generic BSD version, for when openpty() fails."""
  50.     try:
  51.         import sgi
  52.     except ImportError:
  53.         pass
  54.     else:
  55.         try:
  56.             tty_name, master_fd = sgi._getpty(FCNTL.O_RDWR, 0666, 0)
  57.         except IOError, msg:
  58.             raise os.error, msg
  59.         return master_fd, tty_name
  60.     for x in 'pqrstuvwxyzPQRST':
  61.         for y in '0123456789abcdef':
  62.             pty_name = '/dev/pty' + x + y
  63.             try:
  64.                 fd = os.open(pty_name, FCNTL.O_RDWR)
  65.             except os.error:
  66.                 continue
  67.             return (fd, '/dev/tty' + x + y)
  68.     raise os.error, 'out of pty devices'
  69.  
  70. def slave_open(tty_name):
  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.  
  76.     return os.open(tty_name, FCNTL.O_RDWR)
  77.  
  78. def fork():
  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() 
  96.     pid = os.fork()
  97.     if pid == CHILD:
  98.         # Establish a new session.
  99.         os.setsid()
  100.         os.close(master_fd)
  101.  
  102.         # Slave becomes stdin/stdout/stderr of child.
  103.         os.dup2(slave_fd, STDIN_FILENO)
  104.         os.dup2(slave_fd, STDOUT_FILENO)
  105.         os.dup2(slave_fd, STDERR_FILENO)
  106.         if (slave_fd > STDERR_FILENO):
  107.             os.close (slave_fd)
  108.  
  109.     # Parent and child process.
  110.     return pid, master_fd
  111.  
  112. def _writen(fd, data):
  113.     """Write all the data to a descriptor."""
  114.     while data != '':
  115.         n = os.write(fd, data)
  116.         data = data[n:]
  117.  
  118. def _read(fd):
  119.     """Default read function."""
  120.     return os.read(fd, 1024)
  121.  
  122. def _copy(master_fd, master_read=_read, stdin_read=_read):
  123.     """Parent copy loop.
  124.     Copies  
  125.           pty master -> standard output    (master_read)
  126.           standard input -> pty master    (stdin_read)"""
  127.     while 1:
  128.         rfds, wfds, xfds = select(
  129.             [master_fd, STDIN_FILENO], [], [])
  130.         if master_fd in rfds:
  131.             data = master_read(master_fd)
  132.             os.write(STDOUT_FILENO, data)
  133.         if STDIN_FILENO in rfds:
  134.             data = stdin_read(STDIN_FILENO)
  135.             _writen(master_fd, data)
  136.  
  137. def spawn(argv, master_read=_read, stdin_read=_read):
  138.     """Create a spawned process."""
  139.     if type(argv) == type(''):
  140.         argv = (argv,)
  141.     pid, master_fd = fork()
  142.     if pid == CHILD:
  143.         apply(os.execlp, (argv[0],) + argv)
  144.     mode = tty.tcgetattr(STDIN_FILENO)
  145.     tty.setraw(STDIN_FILENO)
  146.     try:
  147.         _copy(master_fd, master_read, stdin_read)
  148.     except:
  149.         tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
  150.