def posix_exec_cmd(cmd, debug=False): |
""" return output of executing 'cmd'. |
|
raise ExecutionFailed exeception if the command failed. |
the exception will provide an 'err' attribute containing |
the error-output from the command. |
""" |
__tracebackhide__ = True |
import popen2 |
import errno |
|
|
child = popen2.Popen3(cmd, 1) |
stdin, stdout, stderr = child.tochild, child.fromchild, child.childerr |
stdin.close() |
|
|
|
|
|
import fcntl |
def set_non_block(fd): |
flags = fcntl.fcntl(fd, fcntl.F_GETFL) |
flags = flags | os.O_NONBLOCK |
fcntl.fcntl(fd, fcntl.F_SETFL, flags) |
set_non_block(stdout.fileno()) |
set_non_block(stderr.fileno()) |
|
|
|
import select |
out, err = [], [] |
while 1: |
r_list = filter(lambda x: x and not x.closed, [stdout, stderr]) |
if not r_list: |
break |
try: |
r_list = select.select(r_list, [], [])[0] |
except (select.error, IOError), se: |
if se.args[0] == errno.EINTR: |
continue |
else: |
raise |
for r in r_list: |
try: |
data = r.read() |
except IOError, io: |
if io.args[0] == errno.EAGAIN: |
continue |
|
raise |
except OSError, ose: |
if ose.errno == errno.EPIPE: |
|
raise |
if ose.errno == errno.EAGAIN: |
continue |
raise |
|
if not data: |
r.close() |
continue |
if debug: |
sys.stderr.write(data) |
if r is stdout: |
out.append(data) |
else: |
err.append(data) |
pid, systemstatus = os.waitpid(child.pid, 0) |
if pid != child.pid: |
raise ExecutionFailed, "child process disappeared during: "+ cmd |
if systemstatus: |
if os.WIFSIGNALED(systemstatus): |
status = os.WTERMSIG(systemstatus) + 128 |
else: |
status = os.WEXITSTATUS(systemstatus) |
raise ExecutionFailed(status, systemstatus, cmd, |
''.join(out), ''.join(err)) |
return "".join(out) |