home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / hplip / base / subproc.py < prev    next >
Encoding:
Python Source  |  2006-08-30  |  12.5 KB  |  391 lines

  1. # -*- coding: utf-8 -*-
  2. # subprocess - Subprocesses with accessible I/O streams
  3. #
  4. # For more information about this module, see PEP 324.
  5. #
  6. # Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
  7. #
  8. # By obtaining, using, and/or copying this software and/or its
  9. # associated documentation, you agree that you have read, understood,
  10. # and will comply with the following terms and conditions:
  11. #
  12. # Permission to use, copy, modify, and distribute this software and
  13. # its associated documentation for any purpose and without fee is
  14. # hereby granted, provided that the above copyright notice appears in
  15. # all copies, and that both that copyright notice and this permission
  16. # notice appear in supporting documentation, and that the name of the
  17. # author not be used in advertising or publicity pertaining to
  18. # distribution of the software without specific, written prior
  19. # permission.
  20. #
  21. # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  22. # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  23. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  24. # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  25. # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  26. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  27. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  28.  
  29. """subprocess - Subprocesses with accessible I/O streams
  30. This copy has been modified from the original in the Python std lib.
  31. Its been edited to be Linux-only. Used for compatibility with Python < v2.4"""
  32.  
  33. import sys
  34. import os
  35. import types
  36. import traceback
  37. import select
  38. import errno
  39. import fcntl
  40. import pickle
  41.  
  42. __all__ = ["Popen", "PIPE", "STDOUT", "call"]
  43.  
  44. try:
  45.     MAXFD = os.sysconf("SC_OPEN_MAX")
  46. except:
  47.     MAXFD = 256
  48.  
  49. # True/False does not exist on 2.2.0
  50. try:
  51.     False
  52. except NameError:
  53.     False = 0
  54.     True = 1
  55.  
  56. _active = []
  57.  
  58. def _cleanup():
  59.     for inst in _active[:]:
  60.         inst.poll()
  61.  
  62. PIPE = -1
  63. STDOUT = -2
  64.  
  65.  
  66. def call(*args, **kwargs):
  67.     return Popen(*args, **kwargs).wait()
  68.  
  69. class Popen(object):
  70.     def __init__(self, args, bufsize=0, executable=None,
  71.                  stdin=None, stdout=None, stderr=None,
  72.                  preexec_fn=None, close_fds=False, shell=False,
  73.                  cwd=None, env=None, universal_newlines=False,
  74.                  startupinfo=None, creationflags=0):
  75.         """Create new Popen instance."""
  76.         _cleanup()
  77.  
  78.         if not isinstance(bufsize, (int, long)):
  79.             raise TypeError("bufsize must be an integer")
  80.  
  81.         if startupinfo is not None:
  82.             raise ValueError("startupinfo is only supported on Windows "
  83.                              "platforms")
  84.         if creationflags != 0:
  85.             raise ValueError("creationflags is only supported on Windows "
  86.                              "platforms")
  87.  
  88.         self.stdin = None
  89.         self.stdout = None
  90.         self.stderr = None
  91.         self.pid = None
  92.         self.returncode = None
  93.         self.universal_newlines = universal_newlines
  94.  
  95.         (p2cread, p2cwrite,
  96.          c2pread, c2pwrite,
  97.          errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  98.  
  99.         self._execute_child(args, executable, preexec_fn, close_fds,
  100.                             cwd, env, universal_newlines,
  101.                             startupinfo, creationflags, shell,
  102.                             p2cread, p2cwrite,
  103.                             c2pread, c2pwrite,
  104.                             errread, errwrite)
  105.  
  106.         if p2cwrite:
  107.             self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
  108.         if c2pread:
  109.             if universal_newlines:
  110.                 self.stdout = os.fdopen(c2pread, 'rU', bufsize)
  111.             else:
  112.                 self.stdout = os.fdopen(c2pread, 'rb', bufsize)
  113.         if errread:
  114.             if universal_newlines:
  115.                 self.stderr = os.fdopen(errread, 'rU', bufsize)
  116.             else:
  117.                 self.stderr = os.fdopen(errread, 'rb', bufsize)
  118.  
  119.         _active.append(self)
  120.  
  121.  
  122.     def _translate_newlines(self, data):
  123.         data = data.replace("\r\n", "\n")
  124.         data = data.replace("\r", "\n")
  125.         return data
  126.  
  127.     def _get_handles(self, stdin, stdout, stderr):
  128.         """Construct and return tupel with IO objects:
  129.         p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
  130.         """
  131.         p2cread, p2cwrite = None, None
  132.         c2pread, c2pwrite = None, None
  133.         errread, errwrite = None, None
  134.  
  135.         if stdin == None:
  136.             pass
  137.         elif stdin == PIPE:
  138.             p2cread, p2cwrite = os.pipe()
  139.         elif type(stdin) == types.IntType:
  140.             p2cread = stdin
  141.         else:
  142.             # Assuming file-like object
  143.             p2cread = stdin.fileno()
  144.  
  145.         if stdout == None:
  146.             pass
  147.         elif stdout == PIPE:
  148.             c2pread, c2pwrite = os.pipe()
  149.         elif type(stdout) == types.IntType:
  150.             c2pwrite = stdout
  151.         else:
  152.             # Assuming file-like object
  153.             c2pwrite = stdout.fileno()
  154.  
  155.         if stderr == None:
  156.             pass
  157.         elif stderr == PIPE:
  158.             errread, errwrite = os.pipe()
  159.         elif stderr == STDOUT:
  160.             errwrite = c2pwrite
  161.         elif type(stderr) == types.IntType:
  162.             errwrite = stderr
  163.         else:
  164.             # Assuming file-like object
  165.             errwrite = stderr.fileno()
  166.  
  167.         return (p2cread, p2cwrite,
  168.                 c2pread, c2pwrite,
  169.                 errread, errwrite)
  170.  
  171.  
  172.     def _set_cloexec_flag(self, fd):
  173.         try:
  174.             cloexec_flag = fcntl.FD_CLOEXEC
  175.         except AttributeError:
  176.             cloexec_flag = 1
  177.  
  178.         old = fcntl.fcntl(fd, fcntl.F_GETFD)
  179.         fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
  180.  
  181.  
  182.     def _close_fds(self, but):
  183.         for i in range(3, MAXFD):
  184.             if i == but:
  185.                 continue
  186.             try:
  187.                 os.close(i)
  188.             except:
  189.                 pass
  190.  
  191.  
  192.     def _execute_child(self, args, executable, preexec_fn, close_fds,
  193.                        cwd, env, universal_newlines,
  194.                        startupinfo, creationflags, shell,
  195.                        p2cread, p2cwrite,
  196.                        c2pread, c2pwrite,
  197.                        errread, errwrite):
  198.         """Execute program (POSIX version)"""
  199.  
  200.         if isinstance(args, types.StringTypes):
  201.             args = [args]
  202.  
  203.         if shell:
  204.             args = ["/bin/sh", "-c"] + args
  205.  
  206.         if executable == None:
  207.             executable = args[0]
  208.  
  209.         # For transferring possible exec failure from child to parent
  210.         # The first char specifies the exception type: 0 means
  211.         # OSError, 1 means some other error.
  212.         errpipe_read, errpipe_write = os.pipe()
  213.         self._set_cloexec_flag(errpipe_write)
  214.  
  215.         self.pid = os.fork()
  216.         if self.pid == 0:
  217.             # Child
  218.             try:
  219.                 # Close parent's pipe ends
  220.                 if p2cwrite:
  221.                     os.close(p2cwrite)
  222.                 if c2pread:
  223.                     os.close(c2pread)
  224.                 if errread:
  225.                     os.close(errread)
  226.                 os.close(errpipe_read)
  227.  
  228.                 # Dup fds for child
  229.                 if p2cread:
  230.                     os.dup2(p2cread, 0)
  231.                 if c2pwrite:
  232.                     os.dup2(c2pwrite, 1)
  233.                 if errwrite:
  234.                     os.dup2(errwrite, 2)
  235.  
  236.                 # Close pipe fds.  Make sure we doesn't close the same
  237.                 # fd more than once.
  238.                 if p2cread:
  239.                     os.close(p2cread)
  240.                 if c2pwrite and c2pwrite not in (p2cread,):
  241.                     os.close(c2pwrite)
  242.                 if errwrite and errwrite not in (p2cread, c2pwrite):
  243.                     os.close(errwrite)
  244.  
  245.                 # Close all other fds, if asked for
  246.                 if close_fds:
  247.                     self._close_fds(but=errpipe_write)
  248.  
  249.                 if cwd != None:
  250.                     os.chdir(cwd)
  251.  
  252.                 if preexec_fn:
  253.                     apply(preexec_fn)
  254.  
  255.                 if env == None:
  256.                     os.execvp(executable, args)
  257.                 else:
  258.                     os.execvpe(executable, args, env)
  259.  
  260.             except:
  261.                 exc_type, exc_value, tb = sys.exc_info()
  262.                 # Save the traceback and attach it to the exception object
  263.                 exc_lines = traceback.format_exception(exc_type,
  264.                                                        exc_value,
  265.                                                        tb)
  266.                 exc_value.child_traceback = ''.join(exc_lines)
  267.                 os.write(errpipe_write, pickle.dumps(exc_value))
  268.  
  269.             # This exitcode won't be reported to applications, so it
  270.             # really doesn't matter what we return.
  271.             os._exit(255)
  272.  
  273.         # Parent
  274.         os.close(errpipe_write)
  275.         if p2cread and p2cwrite:
  276.             os.close(p2cread)
  277.         if c2pwrite and c2pread:
  278.             os.close(c2pwrite)
  279.         if errwrite and errread:
  280.             os.close(errwrite)
  281.  
  282.         # Wait for exec to fail or succeed; possibly raising exception
  283.         data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
  284.         os.close(errpipe_read)
  285.         if data != "":
  286.             os.waitpid(self.pid, 0)
  287.             child_exception = pickle.loads(data)
  288.             raise child_exception
  289.  
  290.  
  291.     def _handle_exitstatus(self, sts):
  292.         if os.WIFSIGNALED(sts):
  293.             self.returncode = -os.WTERMSIG(sts)
  294.         elif os.WIFEXITED(sts):
  295.             self.returncode = os.WEXITSTATUS(sts)
  296.         else:
  297.             # Should never happen
  298.             raise RuntimeError("Unknown child exit status!")
  299.  
  300.         _active.remove(self)
  301.  
  302.  
  303.     def poll(self):
  304.         """Check if child process has terminated.  Returns returncode
  305.         attribute."""
  306.         if self.returncode == None:
  307.             try:
  308.                 pid, sts = os.waitpid(self.pid, os.WNOHANG)
  309.                 if pid == self.pid:
  310.                     self._handle_exitstatus(sts)
  311.             except os.error:
  312.                 pass
  313.         return self.returncode
  314.  
  315.  
  316.     def wait(self):
  317.         """Wait for child process to terminate.  Returns returncode
  318.         attribute."""
  319.         if self.returncode == None:
  320.             pid, sts = os.waitpid(self.pid, 0)
  321.             self._handle_exitstatus(sts)
  322.         return self.returncode
  323.  
  324.  
  325.     def communicate(self, input=None):
  326.         read_set = []
  327.         write_set = []
  328.         stdout = None # Return
  329.         stderr = None # Return
  330.  
  331.         if self.stdin:
  332.             # Flush stdio buffer.  This might block, if the user has
  333.             # been writing to .stdin in an uncontrolled fashion.
  334.             self.stdin.flush()
  335.             if input:
  336.                 write_set.append(self.stdin)
  337.             else:
  338.                 self.stdin.close()
  339.         if self.stdout:
  340.             read_set.append(self.stdout)
  341.             stdout = []
  342.         if self.stderr:
  343.             read_set.append(self.stderr)
  344.             stderr = []
  345.  
  346.         while read_set or write_set:
  347.             rlist, wlist, xlist = select.select(read_set, write_set, [])
  348.  
  349.             if self.stdin in wlist:
  350.                 # When select has indicated that the file is writable,
  351.                 # we can write up to PIPE_BUF bytes without risk
  352.                 # blocking.  POSIX defines PIPE_BUF >= 512
  353.                 bytes_written = os.write(self.stdin.fileno(), input[:512])
  354.                 input = input[bytes_written:]
  355.                 if not input:
  356.                     self.stdin.close()
  357.                     write_set.remove(self.stdin)
  358.  
  359.             if self.stdout in rlist:
  360.                 data = os.read(self.stdout.fileno(), 1024)
  361.                 if data == "":
  362.                     self.stdout.close()
  363.                     read_set.remove(self.stdout)
  364.                 stdout.append(data)
  365.  
  366.             if self.stderr in rlist:
  367.                 data = os.read(self.stderr.fileno(), 1024)
  368.                 if data == "":
  369.                     self.stderr.close()
  370.                     read_set.remove(self.stderr)
  371.                 stderr.append(data)
  372.  
  373.         # All data exchanged.  Translate lists into strings.
  374.         if stdout != None:
  375.             stdout = ''.join(stdout)
  376.         if stderr != None:
  377.             stderr = ''.join(stderr)
  378.  
  379.         # Translate newlines, if requested.  We cannot let the file
  380.         # object do the translation: It is based on stdio, which is
  381.         # impossible to combine with select (unless forcing no
  382.         # buffering).
  383.         if self.universal_newlines and hasattr(open, 'newlines'):
  384.             if stdout:
  385.                 stdout = self._translate_newlines(stdout)
  386.             if stderr:
  387.                 stderr = self._translate_newlines(stderr)
  388.  
  389.         self.wait()
  390.         return (stdout, stderr)
  391.