Make servers able to launch when a stale ctrl.sock from a pervious server remains.
[nepi.git] / src / nepi / util / server.py
index 5139756..0a95275 100644 (file)
@@ -24,6 +24,7 @@ import functools
 import collections
 
 CTRL_SOCK = "ctrl.sock"
+CTRL_PID = "ctrl.pid"
 STD_ERR = "stderr.log"
 MAX_FD = 1024
 
@@ -46,7 +47,7 @@ def shell_escape(s):
     else:
         # unsafe string - escape
         def escp(c):
-            if (32 <= ord(c) < 127 or c in ('\r','\n','\t')) and c not in ("'",):
+            if (32 <= ord(c) < 127 or c in ('\r','\n','\t')) and c not in ("'",'"'):
                 return c
             else:
                 return "'$'\\x%02x''" % (ord(c),)
@@ -198,8 +199,35 @@ class Server(object):
 
         # create control socket
         self._ctrl_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        self._ctrl_sock.bind(CTRL_SOCK)
+        try:
+            self._ctrl_sock.bind(CTRL_SOCK)
+        except socket.error:
+            # Address in use, check pidfile
+            pid = None
+            try:
+                pidfile = open(CTRL_PID, "r")
+                pid = pidfile.read()
+                pidfile.close()
+                pid = int(pid)
+            except:
+                # no pidfile
+                pass
+            
+            if pid is not None:
+                # Check process liveliness
+                if not os.path.exists("/proc/%d" % (pid,)):
+                    # Ok, it's dead, clean the socket
+                    os.remove(CTRL_SOCK)
+            
+            # try again
+            self._ctrl_sock.bind(CTRL_SOCK)
+            
         self._ctrl_sock.listen(0)
+        
+        # Save pidfile
+        pidfile = open(CTRL_PID, "w")
+        pidfile.write(str(os.getpid()))
+        pidfile.close()
 
         # let the parent process know that the daemonization is finished
         os.write(w, "\n")
@@ -230,7 +258,7 @@ class Server(object):
                 try:
                     msg = self.recv_msg(conn)
                 except socket.timeout, e:
-                    self.log_error("SERVER recv_msg: connection timedout ")
+                    #self.log_error("SERVER recv_msg: connection timedout ")
                     continue
                 
                 if not msg:
@@ -433,10 +461,15 @@ class Client(object):
                
         # Wait for the forwarder to be ready, otherwise nobody
         # will be able to connect to it
-        helo = self._process.stderr.readline()
-        if helo != 'FORWARDER_READY.\n':
-            raise AssertionError, "Expected 'FORWARDER_READY.', got %r: %s" % (helo,
-                    helo + self._process.stderr.read())
+        err = []
+        helo = "nope"
+        while helo:
+            helo = self._process.stderr.readline()
+            if helo == 'FORWARDER_READY.\n':
+                break
+            err.append(helo)
+        else:
+            raise AssertionError, "Expected 'FORWARDER_READY.', got: %s" % (''.join(err),)
         
     def send_msg(self, msg):
         encoded = base64.b64encode(msg)
@@ -841,10 +874,7 @@ def popen_python(python_code,
         sudo = False, 
         environment_setup = ""):
 
-    shell = False
     cmd = ""
-    if sudo:
-        cmd +="sudo "
     if python_path:
         python_path.replace("'", r"'\''")
         cmd = """PYTHONPATH="$PYTHONPATH":'%s' """ % python_path
@@ -858,10 +888,16 @@ def popen_python(python_code,
     #cmd += "$CMD "
     #cmd += "strace -f -tt -s 200 -o strace$$.out "
     import nepi
-    cmd += "python -c 'import sys; sys.path.append(%s); from nepi.util import server; server.decode_and_execute()'" % (
+    cmd += "python -c 'import sys; sys.path.insert(0,%s); from nepi.util import server; server.decode_and_execute()'" % (
         repr(os.path.dirname(os.path.dirname(nepi.__file__))).replace("'",'"'),
     )
 
+    if sudo:
+        if ';' in cmd:
+            cmd = "sudo bash -c " + shell_escape(cmd)
+        else:
+            cmd = "sudo " + cmd
+
     if communication == DC.ACCESS_SSH:
         tmp_known_hosts = None
         args = ['ssh',
@@ -882,12 +918,11 @@ def popen_python(python_code,
                 server_key, host, port, args)
         args.append(cmd)
     else:
-        args = [cmd]
-        shell = True
+        args = [ "/bin/bash", "-c", cmd ]
 
     # connects to the remote host and starts a remote
     proc = subprocess.Popen(args,
-            shell = shell
+            shell = False
             stdout = subprocess.PIPE,
             stdin = subprocess.PIPE, 
             stderr = subprocess.PIPE)