[pkg-fso-commits] [SCM] Various useful tools for an FSO installation branch, master, updated. debian/0.git20080812.2-32-gb5a13bb
Jan Luebbe
jluebbe at debian.org
Sun Sep 27 16:11:45 UTC 2009
The following commit has been merged in the master branch:
commit 382de6e12a421536e26fbedcad425718773605dd
Author: Jan Luebbe <jluebbe at debian.org>
Date: Mon Feb 23 13:10:40 2009 +0100
pyc: support waiting until the child is done
diff --git a/pycd/pyc.c b/pycd/pyc.c
index 07b6f51..22ab1f3 100644
--- a/pycd/pyc.c
+++ b/pycd/pyc.c
@@ -14,7 +14,7 @@ void error(const char *msg) {
}
int main(int argc, char *argv[]) {
- int i, s, bufsize, bufpos, argsize, pid;
+ int i, s, bufsize, bufpos, argsize, pid, status;
struct sockaddr_un sa;
ssize_t len;
if ((s = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) {
@@ -48,17 +48,21 @@ int main(int argc, char *argv[]) {
}
if ((len = recv(s, &pid, sizeof(pid), 0)) < 0) {
- error("ERROR: could not recv");
+ error("ERROR: could not recv pid");
}
if (len != sizeof(pid)) {
- fprintf(stderr, "ERROR: invalid reply");
+ fprintf(stderr, "ERROR: invalid reply for pid\n");
}
- if (waitpid(pid, NULL, 0) < 0) {
- error("ERROR: could not wait for child");
+ if ((len = recv(s, &status, sizeof(status), 0)) < 0) {
+ error("ERROR: could not recv pid");
}
- return 0;
+ if (len != sizeof(status) ) {
+ fprintf(stderr, "ERROR: invalid reply for status\n");
+ }
+
+ return status;
}
diff --git a/pycd/pycd.py b/pycd/pycd.py
index c25d517..73ceb29 100755
--- a/pycd/pycd.py
+++ b/pycd/pycd.py
@@ -15,7 +15,7 @@ import os, socket, sys
import struct
-import atexit
+import atexit, errno, signal
import dbus
import dbus.service
@@ -41,6 +41,7 @@ class Prototype( object ):
logger.info( "starting prototype" )
self.down = os.pipe()
self.up = os.pipe()
+ self.state = os.pipe()
pid = os.fork()
if pid:
self.inParent( pid )
@@ -50,41 +51,73 @@ class Prototype( object ):
def inChild( self ):
logger.info( "in prototype" )
- sys.argv[0] = "pycd - prototype"
os.close( self.down[1] )
os.close( self.up[0] )
+ os.close( self.state[0] )
self.down = os.fdopen( self.down[0], 'r', 0 ) # read side
self.up = os.fdopen( self.up[1], 'w', 0 ) # write side
- line = self.down.readline().strip()
- while line:
- sender, argv = line.split(' ', 1)
+ self.state = os.fdopen( self.state[1], 'w', 0 ) # write side
+ data = ""
+ while True:
+ new = ""
+ signal.signal( signal.SIGCHLD, self.cleanupClone )
+ try:
+ new = os.read(self.down.fileno(), 1024)
+ if not new:
+ return
+ except OSError, e:
+ if e[0] == errno.EINTR:
+ continue
+ else:
+ raise
+ finally:
+ signal.signal( signal.SIGCHLD, signal.SIG_DFL )
+ data += new
+ if not '\n' in data:
+ continue
+ line, data = data.split( '\n', 1 )
+ sender, argv = line.strip().split(' ', 1)
sender = int( sender )
argv = eval( argv )
logger.info( "got command: %s", repr(( sender, argv )) )
self.doClone( sender, argv )
- line = self.down.readline().strip()
def inParent( self, child_pid ):
logger.info( "started prototype (child PID %s)", child_pid )
os.close( self.down[0] )
os.close( self.up[1] )
+ os.close( self.state[1] )
self.down = os.fdopen( self.down[1], 'w', 0) # write side
self.up = os.fdopen( self.up[0], 'r', 0) # read side
+ self.state = os.fdopen( self.state[0], 'r', 0) # read side
+ self.callbacks = {}
+ gobject.io_add_watch( self.state, gobject.IO_IN, self.handleState )
+
+ def handleState( self, source, condition ):
+ line = self.state.readline().strip()
+ state = eval( line )
+ logger.info( "got state: %s", repr( state ) )
+ cb = self.callbacks.get( state[1], None )
+ if cb:
+ cb[0]( state, cb[1] )
+ return True
- def requestClone( self, sender, argv ):
+ def requestClone( self, sender, argv, cb = None, cb_data = None ):
self.down.write( "%i %s\n" % ( sender, repr( argv ) ) )
reply = int( self.up.readline().strip() )
logger.info( "got reply: %s", repr(reply) )
+ if cb:
+ self.callbacks[reply] = ( cb, cb_data )
return int( reply )
def doClone( self, sender, argv ):
- pid = os.fork()
- if pid:
- os.waitpid( pid, 0 )
- return
+ #pid = os.fork()
+ #if pid:
+ # os.waitpid( pid, 0 )
+ # return
os.chdir( "/proc/%i/cwd" % sender )
- os.setsid()
+ #os.setsid()
os.umask(0)
for line in file( "/proc/%i/status" % sender, 'r' ):
@@ -111,10 +144,12 @@ class Prototype( object ):
pid = os.fork()
if pid:
- os._exit(0)
+ return
+ #os._exit(0)
logger.info( "in child" )
self.down.close()
+ self.state.close()
MAXFD = os.sysconf( 'SC_OPEN_MAX' )
for fd in xrange( 3, MAXFD ):
if fd == self.up.fileno():
@@ -141,6 +176,11 @@ class Prototype( object ):
sys.argv = argv
runpy.run_module(sys.argv[0], run_name="__main__", alter_sys=True)
+ def cleanupClone( self, sig, frame ):
+ w = os.wait3( 0 )
+ logger.info( "child quit (pid %i, status %i) " % ( w[0], w[1] ) )
+ self.state.write( "%s\n" % repr( ( "wait", w[0], w[1] ) ) )
+
#============================================================================#
class DBusAPI( dbus.service.Object ):
#============================================================================#
@@ -181,9 +221,9 @@ class SocketAPI( object ):
logger.info( "new socket connection" )
client, address = self.socket.accept()
cred = self.getPeerCred( client )
- self.clients[client] = { 'address': address, 'cred': cred, 'data': "" }
logger.info( "accepted connection from %i (uid %i, gid %i)" % cred )
- gobject.io_add_watch( client, gobject.IO_IN, self.handleClient )
+ watch = gobject.io_add_watch( client, gobject.IO_IN, self.handleClient )
+ self.clients[client] = { 'address': address, 'cred': cred, 'data': "", 'watch': watch }
return True
def handleClient( self, source, condition ):
@@ -191,7 +231,6 @@ class SocketAPI( object ):
if data:
logger.info( "new data from %i (uid %i, gid %i)" % self.clients[source]['cred'] )
self.clients[source]['data'] += data
- print repr(self.clients[source]['data'])
else:
logger.info( "hangup from %i (uid %i, gid %i)" % self.clients[source]['cred'] )
del self.clients[source]
@@ -216,8 +255,17 @@ class SocketAPI( object ):
command.append( data[4:4+size] )
data = data[4+size:]
logger.info( "command from %i (uid %i, gid %i): %s" % (cred[0], cred[1], cred[2], repr( command ) ) )
- result = struct.pack('I', prototype.requestClone( cred[0], command ) )
+ cpid = prototype.requestClone( cred[0], command, self.handleChildState, client )
+ result = struct.pack('I', cpid )
+ client.send( result )
+
+ def handleChildState( self, state, client ):
+ logger.info( "child state changed: %s " % repr( state ) )
+ result = struct.pack('I', state[2] )
client.send( result )
+ gobject.source_remove(self.clients[client]['watch'])
+ del self.clients[client]
+ client.close()
def atexit( self ):
os.unlink( SOCKET_PATH )
--
Various useful tools for an FSO installation
More information about the pkg-fso-commits
mailing list