diff --git a/pcl_expect/spawn.py b/pcl_expect/spawn.py index b79cbef8988cfcb29681d4054257214935a19ee4..8206a28afe83f7184c23f9efebb2edcac2e055a8 100644 --- a/pcl_expect/spawn.py +++ b/pcl_expect/spawn.py @@ -7,7 +7,8 @@ import pcl_expect __all__ = [ "inherit_stty", "stty_init", - "spawn", + "Spawn", + "spawn2", ] # When a new pty is created by spawn(), the terminal settings will be @@ -22,47 +23,71 @@ def set_cloexec_flag(fd): old = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC) -class Spawn(pcl_expect.Expectable): - def __init__(self, cmd): - if inherit_stty: - f = os.popen("stty -g") - settings = f.read() - f.close() +def _spawn(cmd, use_stderr_pipe): + if inherit_stty: + f = os.popen("stty -g") + settings = f.read() + f.close() - if isinstance(cmd, basestring): - cmd = cmd.split(" ") - (r, w) = os.pipe() - set_cloexec_flag(w) - self.__child, self.__pty = pty.fork() - if self.__child == 0: - try: - os.close(r) - if inherit_stty: - os.system("stty %s" % settings) - if stty_init is not None: - os.system("stty %s" % stty_init) - try: - os.execvp(cmd[0], cmd) - except OSError: - os.write(w, "exec failed\n") - finally: - os._exit(1) - else: - os.close(w) - res = os.read(r, 100) + if isinstance(cmd, basestring): + cmd = cmd.split(" ") + (r, w) = os.pipe() + if use_stderr_pipe: + (stderr_r, stderr_w) = os.pipe() + else: + stderr_r = None + set_cloexec_flag(w) + pid, fd = pty.fork() + if pid == 0: + try: os.close(r) - if res != "": - os.close(self.__pty) - os.waitpid(self.__child, 0) - raise OSError("exec failed") - pcl_expect.Expectable.__init__(self, self.__pty) + if inherit_stty: + os.system("stty %s" % settings) + if stty_init is not None: + os.system("stty %s" % stty_init) + if use_stderr_pipe: + os.close(stderr_r) + os.dup2(stderr_w, 2) + os.close(stderr_w) + try: + os.execvp(cmd[0], cmd) + except OSError: + # FIXME: transfer failure reason. + os.write(w, "exec failed\n") + finally: + os._exit(1) + + # In parent. + os.close(w) + if use_stderr_pipe: + os.close(stderr_w) + res = os.read(r, 100) + os.close(r) + if res != "": + os.close(fd) + os.waitpid(pid, 0) + raise OSError("exec failed") + return pid, fd, stderr_r + +class Spawn(pcl_expect.Expectable): + def __init__(self, cmd, use_stderr_pipe = False): + self.__child_pid, fd, stderr = _spawn(cmd, use_stderr_pipe) + pcl_expect.Expectable.__init__(self, fd) + if use_stderr_pipe: + self.stderr = pcl_expect.Expectable(stderr) def send(self, s): pcl_expect.debug("sending \"%s\" to fd %d" % (s, self.fileno())) - os.write(self.__pty, s) + os.write(self.fileno(), s) def close(self): + os.close(self.fileno()) pcl_expect.Expectable.close(self) - os.close(self.__pty) - return os.waitpid(self.__child, 0) + if hasattr(self, "stderr"): + os.close(self.stderr.fileno()) + self.stderr.close() + return os.waitpid(self.__child_pid, 0) +def spawn2(cmd): + proc = Spawn(cmd, True) + return proc, proc.stderr