source: trunk/packages/xen-3.1/xen-3.1/tools/python/xen/util/xpopen.py @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 6.6 KB
Line 
1#
2# Copyright (c) 2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved
3#
4# PSF LICENSE AGREEMENT FOR PYTHON 2.3
5# ------------------------------------
6#
7# 1. This LICENSE AGREEMENT is between the Python Software Foundation
8# ("PSF"), and the Individual or Organization ("Licensee") accessing and
9# otherwise using Python 2.3 software in source or binary form and its
10# associated documentation.
11#
12# 2. Subject to the terms and conditions of this License Agreement, PSF
13# hereby grants Licensee a nonexclusive, royalty-free, world-wide
14# license to reproduce, analyze, test, perform and/or display publicly,
15# prepare derivative works, distribute, and otherwise use Python 2.3
16# alone or in any derivative version, provided, however, that PSF's
17# License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
18# 2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved" are
19# retained in Python 2.3 alone or in any derivative version prepared by
20# Licensee.
21#
22# 3. In the event Licensee prepares a derivative work that is based on
23# or incorporates Python 2.3 or any part thereof, and wants to make
24# the derivative work available to others as provided herein, then
25# Licensee hereby agrees to include in any such work a brief summary of
26# the changes made to Python 2.3.
27#
28# 4. PSF is making Python 2.3 available to Licensee on an "AS IS"
29# basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
30# IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
31# DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
32# FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT
33# INFRINGE ANY THIRD PARTY RIGHTS.
34#
35# 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
36# 2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
37# A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3,
38# OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
39#
40# 6. This License Agreement will automatically terminate upon a material
41# breach of its terms and conditions.
42#
43# 7. Nothing in this License Agreement shall be deemed to create any
44# relationship of agency, partnership, or joint venture between PSF and
45# Licensee.  This License Agreement does not grant permission to use PSF
46# trademarks or trade name in a trademark sense to endorse or promote
47# products or services of Licensee, or any third party.
48#
49# 8. By copying, installing or otherwise using Python 2.3, Licensee
50# agrees to be bound by the terms and conditions of this License
51# Agreement.
52#
53# Modifications: Copyright (c) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
54# - add support for excluding a list of file descriptors from being
55#   closed, allowing access to those file descriptors from the command.
56#
57
58"""Spawn a command with pipes to its stdin, stdout, and optionally stderr.
59
60The normal os.popen(cmd, mode) call spawns a shell command and provides a
61file interface to just the input or output of the process depending on
62whether mode is 'r' or 'w'.  This module provides the functions xpopen2(cmd)
63and xpopen3(cmd) which return two or three pipes to the spawned command.
64Optionally exclude a list of file descriptors from being closed, allowing
65access to those file descriptors from the command.
66"""
67
68import os
69import sys
70
71try:
72    MAXFD = os.sysconf('SC_OPEN_MAX')
73except (AttributeError, ValueError):
74    MAXFD = 256
75
76_active = []
77
78def _cleanup():
79    for inst in _active[:]:
80        inst.poll()
81
82class xPopen3:
83    """Class representing a child process.  Normally instances are created
84    by the factory functions popen2() and popen3()."""
85
86    sts = -1                    # Child not completed yet
87
88    def __init__(self, cmd, capturestderr=False, bufsize=-1, passfd=()):
89        """The parameter 'cmd' is the shell command to execute in a
90        sub-process.  The 'capturestderr' flag, if true, specifies that
91        the object should capture standard error output of the child process.
92        The default is false.  If the 'bufsize' parameter is specified, it
93        specifies the size of the I/O buffers to/from the child process."""
94        _cleanup()
95        self.passfd = passfd
96        p2cread, p2cwrite = os.pipe()
97        c2pread, c2pwrite = os.pipe()
98        if capturestderr:
99            errout, errin = os.pipe()
100        self.pid = os.fork()
101        if self.pid == 0:
102            # Child
103            os.dup2(p2cread, 0)
104            os.dup2(c2pwrite, 1)
105            if capturestderr:
106                os.dup2(errin, 2)
107            self._run_child(cmd)
108        os.close(p2cread)
109        self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
110        os.close(c2pwrite)
111        self.fromchild = os.fdopen(c2pread, 'r', bufsize)
112        if capturestderr:
113            os.close(errin)
114            self.childerr = os.fdopen(errout, 'r', bufsize)
115        else:
116            self.childerr = None
117        _active.append(self)
118
119    def _run_child(self, cmd):
120        if isinstance(cmd, basestring):
121            cmd = ['/bin/sh', '-c', cmd]
122        for i in range(3, MAXFD):
123            if i in self.passfd:
124                continue
125            try:
126                os.close(i)
127            except OSError:
128                pass
129        try:
130            os.execvp(cmd[0], cmd)
131        finally:
132            os._exit(127)
133
134    def poll(self):
135        """Return the exit status of the child process if it has finished,
136        or -1 if it hasn't finished yet."""
137        if self.sts < 0:
138            try:
139                pid, sts = os.waitpid(self.pid, os.WNOHANG)
140                if pid == self.pid:
141                    self.sts = sts
142                    _active.remove(self)
143            except os.error:
144                pass
145        return self.sts
146
147    def wait(self):
148        """Wait for and return the exit status of the child process."""
149        if self.sts < 0:
150            pid, sts = os.waitpid(self.pid, 0)
151            if pid == self.pid:
152                self.sts = sts
153                _active.remove(self)
154        return self.sts
155
156
157def xpopen2(cmd, bufsize=-1, mode='t', passfd=[]):
158    """Execute the shell command 'cmd' in a sub-process.  If 'bufsize' is
159    specified, it sets the buffer size for the I/O pipes.  The file objects
160    (child_stdout, child_stdin) are returned."""
161    inst = xPopen3(cmd, False, bufsize, passfd)
162    return inst.fromchild, inst.tochild
163
164def xpopen3(cmd, bufsize=-1, mode='t', passfd=[]):
165    """Execute the shell command 'cmd' in a sub-process.  If 'bufsize' is
166    specified, it sets the buffer size for the I/O pipes.  The file objects
167    (child_stdout, child_stdin, child_stderr) are returned."""
168    inst = xPopen3(cmd, True, bufsize, passfd)
169    return inst.fromchild, inst.tochild, inst.childerr
Note: See TracBrowser for help on using the repository browser.