home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / pty.py < prev    next >
Text File  |  2003-12-30  |  5KB  |  178 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
  11.  
  12. # Absurd:  import termios and then delete it.  This is to force an attempt
  13. # to import pty to raise an ImportError on platforms that lack termios.
  14. # Without this explicit import of termios here, some other module may
  15. # import tty first, which in turn imports termios and dies with an
  16. # ImportError then.  But since tty *does* exist across platforms, that
  17. # leaves a damaged module object for tty in sys.modules, and the import
  18. # of tty here then appears to work despite that the tty imported is junk.
  19. import termios
  20. del termios
  21.  
  22. import tty
  23.  
  24. __all__ = ["openpty","fork","spawn"]
  25.  
  26. STDIN_FILENO = 0
  27. STDOUT_FILENO = 1
  28. STDERR_FILENO = 2
  29.  
  30. CHILD = 0
  31.  
  32. def openpty():
  33.     """openpty() -> (master_fd, slave_fd)
  34.     Open a pty master/slave pair, using os.openpty() if possible."""
  35.  
  36.     try:
  37.         return os.openpty()
  38.     except (AttributeError, OSError):
  39.         pass
  40.     master_fd, slave_name = _open_terminal()
  41.     slave_fd = slave_open(slave_name)
  42.     return master_fd, slave_fd
  43.  
  44. def master_open():
  45.     """master_open() -> (master_fd, slave_name)
  46.     Open a pty master and return the fd, and the filename of the slave end.
  47.     Deprecated, use openpty() instead."""
  48.  
  49.     try:
  50.         master_fd, slave_fd = os.openpty()
  51.     except (AttributeError, OSError):
  52.         pass
  53.     else:
  54.         slave_name = os.ttyname(slave_fd)
  55.         os.close(slave_fd)
  56.         return master_fd, slave_name
  57.  
  58.     return _open_terminal()
  59.  
  60. def _open_terminal():
  61.     """Open pty master and return (master_fd, tty_name).
  62.     SGI and generic BSD version, for when openpty() fails."""
  63.     try:
  64.         import sgi
  65.     except ImportError:
  66.         pass
  67.     else:
  68.         try:
  69.             tty_name, master_fd = sgi._getpty(os.O_RDWR, 0666, 0)
  70.         except IOError, msg:
  71.             raise os.error, msg
  72.         return master_fd, tty_name
  73.     for x in 'pqrstuvwxyzPQRST':
  74.         for y in '0123456789abcdef':
  75.             pty_name = '/dev/pty' + x + y
  76.             try:
  77.                 fd = os.open(pty_name, os.O_RDWR)
  78.             except os.error:
  79.                 continue
  80.             return (fd, '/dev/tty' + x + y)
  81.     raise os.error, 'out of pty devices'
  82.  
  83. def slave_open(tty_name):
  84.     """slave_open(tty_name) -> slave_fd
  85.     Open the pty slave and acquire the controlling terminal, returning
  86.     opened filedescriptor.
  87.     Deprecated, use openpty() instead."""
  88.  
  89.     result = os.open(tty_name, os.O_RDWR)
  90.     try:
  91.         from fcntl import ioctl, I_PUSH
  92.     except ImportError:
  93.         return result
  94.     try:
  95.         ioctl(result, I_PUSH, "ptem")
  96.         ioctl(result, I_PUSH, "ldterm")
  97.     except IOError:
  98.         pass
  99.     return result
  100.  
  101. def fork():
  102.     """fork() -> (pid, master_fd)
  103.     Fork and make the child a session leader with a controlling terminal."""
  104.  
  105.     try:
  106.         pid, fd = os.forkpty()
  107.     except (AttributeError, OSError):
  108.         pass
  109.     else:
  110.         if pid == CHILD:
  111.             try:
  112.                 os.setsid()
  113.             except OSError:
  114.                 # os.forkpty() already set us session leader
  115.                 pass
  116.         return pid, fd
  117.  
  118.     master_fd, slave_fd = openpty()
  119.     pid = os.fork()
  120.     if pid == CHILD:
  121.         # Establish a new session.
  122.         os.setsid()
  123.         os.close(master_fd)
  124.  
  125.         # Slave becomes stdin/stdout/stderr of child.
  126.         os.dup2(slave_fd, STDIN_FILENO)
  127.         os.dup2(slave_fd, STDOUT_FILENO)
  128.         os.dup2(slave_fd, STDERR_FILENO)
  129.         if (slave_fd > STDERR_FILENO):
  130.             os.close (slave_fd)
  131.  
  132.     # Parent and child process.
  133.     return pid, master_fd
  134.  
  135. def _writen(fd, data):
  136.     """Write all the data to a descriptor."""
  137.     while data != '':
  138.         n = os.write(fd, data)
  139.         data = data[n:]
  140.  
  141. def _read(fd):
  142.     """Default read function."""
  143.     return os.read(fd, 1024)
  144.  
  145. def _copy(master_fd, master_read=_read, stdin_read=_read):
  146.     """Parent copy loop.
  147.     Copies
  148.             pty master -> standard output   (master_read)
  149.             standard input -> pty master    (stdin_read)"""
  150.     while 1:
  151.         rfds, wfds, xfds = select(
  152.                 [master_fd, STDIN_FILENO], [], [])
  153.         if master_fd in rfds:
  154.             data = master_read(master_fd)
  155.             os.write(STDOUT_FILENO, data)
  156.         if STDIN_FILENO in rfds:
  157.             data = stdin_read(STDIN_FILENO)
  158.             _writen(master_fd, data)
  159.  
  160. def spawn(argv, master_read=_read, stdin_read=_read):
  161.     """Create a spawned process."""
  162.     if type(argv) == type(''):
  163.         argv = (argv,)
  164.     pid, master_fd = fork()
  165.     if pid == CHILD:
  166.         os.execlp(argv[0], *argv)
  167.     try:
  168.         mode = tty.tcgetattr(STDIN_FILENO)
  169.         tty.setraw(STDIN_FILENO)
  170.         restore = 1
  171.     except tty.error:    # This is the same as termios.error
  172.         restore = 0
  173.     try:
  174.         _copy(master_fd, master_read, stdin_read)
  175.     except (IOError, OSError):
  176.         if restore:
  177.             tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode)
  178.