I'm developing a simple service that binds to a port and spawns a pty for an application, dup()
ing STDIN
, STDOUT
, and STDERR
to the socket, so that the socket takes control over the pty
:
prevOutFd = os.dup(1)
prevInFd = os.dup(0)
prevErrFd = os.dup(2)
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
logging.info('Connected with ' + addr[0] + ':' + str(addr[1]))
# redirect stdout, stdin and stderr to socket fd
os.dup2(conn.fileno(),0)
os.dup2(conn.fileno(),1)
os.dup2(conn.fileno(),2)
p=pty.spawn("/usr/sbin/pppd")
# redirect stdout, stdin and stderr back to original fds
os.dup2(prevOutFd, 0)
os.dup2(prevInFd, 1)
os.dup2(prevErrFd, 2)
logging.info("Closing connection....")
conn.close()
This works just fine, except for when the client abruptly kills the connection. The server handles it just fine, but the spawned application is left defunct in the system:
root 9820 0.1 0.0 0 0 ? Zs 16:19 0:00 [pppd] <defunct>
I believe the solution is to either wait for the application to finish OR cleanly shut it down.
However, pty
does not seem to have a close()
method of some sort.
Anyone know how to cleanly shut a pty.spawn()
ed application?
You can wait() the exited process like this:
pty.spawn("cmd") # it returns nothing
os.wait()
You can also set a SIGCHLD handler so exited child processes can be automatically waited.
def sig_child(signum, bt):
os.waitpid(-1, os.WNOHANG)
signal.signal(SIGCHLD, sig_child)
pty.spawn("cmd")