Made server startup more robust against races caused by a previous
server terminating at the same time.

diff --git a/scheduler/client.c b/scheduler/client.c
index 5888975..ef39a49 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -338,6 +338,7 @@
 static void start_server( const char *oldcwd )
 {
     static int started;  /* we only try once */
+    char *path, *p;
     if (!started)
     {
         int status;
@@ -345,24 +346,36 @@
         if (pid == -1) fatal_perror( "fork" );
         if (!pid)
         {
-            char *path, *p;
             /* first try the installation dir */
             execl( BINDIR "/wineserver", "wineserver", NULL );
-            if (oldcwd) chdir( oldcwd );
+
             /* now try the dir we were launched from */
-            if (!(path = malloc( strlen(argv0) + 20 )))
+            if (full_argv0)
+            {
+                if (!(path = malloc( strlen(full_argv0) + 20 )))
+                    fatal_error( "out of memory\n" );
+                if ((p = strrchr( strcpy( path, full_argv0 ), '/' )))
+                {
+                    strcpy( p, "/wineserver" );
+                    execl( path, "wineserver", NULL );
+                    strcpy( p, "/server/wineserver" );
+                    execl( path, "wineserver", NULL );
+                }
+            }
+
+            /* now try the path */
+            execlp( "wineserver", "wineserver", NULL );
+
+            /* and finally the current dir */
+            if (!(path = malloc( strlen(oldcwd) + 20 )))
                 fatal_error( "out of memory\n" );
-            if ((p = strrchr( strcpy( path, argv0 ), '/' )))
+            if ((p = strrchr( strcpy( path, oldcwd ), '/' )))
             {
                 strcpy( p, "/wineserver" );
                 execl( path, "wineserver", NULL );
                 strcpy( p, "/server/wineserver" );
                 execl( path, "wineserver", NULL );
             }
-            /* now try the path */
-            execlp( "wineserver", "wineserver", NULL );
-            /* and finally the current dir */
-            execl( "./server/wineserver", "wineserver", NULL );
             fatal_error( "could not exec wineserver\n" );
         }
         started = 1;
@@ -382,13 +395,13 @@
 {
     struct sockaddr_un addr;
     struct stat st;
-    int s, slen;
+    int s, slen, retry;
 
     /* chdir to the server directory */
     if (chdir( serverdir ) == -1)
     {
         if (errno != ENOENT) fatal_perror( "chdir to %s", serverdir );
-        start_server( NULL );
+        start_server( "." );
         if (chdir( serverdir ) == -1) fatal_perror( "chdir to %s", serverdir );
     }
 
@@ -397,42 +410,44 @@
     if (st.st_uid != getuid()) fatal_error( "'%s' is not owned by you\n", serverdir );
     if (st.st_mode & 077) fatal_error( "'%s' must not be accessible by other users\n", serverdir );
 
-    /* check for an existing socket */
-    if (lstat( SOCKETNAME, &st ) == -1)
+    for (retry = 0; retry < 3; retry++)
     {
-        if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
-        start_server( oldcwd );
-        if (lstat( SOCKETNAME, &st ) == -1) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
-    }
+        /* if not the first try, wait a bit to leave the server time to exit */
+        if (retry) usleep( 100000 * retry * retry );
 
-    /* make sure the socket is sane */
-    if (!S_ISSOCK(st.st_mode))
-        fatal_error( "'%s/%s' is not a socket\n", serverdir, SOCKETNAME );
-    if (st.st_uid != getuid())
-        fatal_error( "'%s/%s' is not owned by you\n", serverdir, SOCKETNAME );
+        /* check for an existing socket */
+        if (lstat( SOCKETNAME, &st ) == -1)
+        {
+            if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
+            start_server( oldcwd );
+            if (lstat( SOCKETNAME, &st ) == -1) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
+        }
 
-    /* try to connect to it */
-    addr.sun_family = AF_UNIX;
-    strcpy( addr.sun_path, SOCKETNAME );
-    slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1;
+        /* make sure the socket is sane */
+        if (!S_ISSOCK(st.st_mode))
+            fatal_error( "'%s/%s' is not a socket\n", serverdir, SOCKETNAME );
+        if (st.st_uid != getuid())
+            fatal_error( "'%s/%s' is not owned by you\n", serverdir, SOCKETNAME );
+
+        /* try to connect to it */
+        addr.sun_family = AF_UNIX;
+        strcpy( addr.sun_path, SOCKETNAME );
+        slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1;
 #ifdef HAVE_SOCKADDR_SUN_LEN
-    addr.sun_len = slen;
+        addr.sun_len = slen;
 #endif
-    if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
-    if (connect( s, (struct sockaddr *)&addr, slen ) == -1)
-    {
-        close( s );
-        /* wait a bit and retry with a new socket */
-        usleep( 50000 );
         if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
-        if (connect( s, (struct sockaddr *)&addr, slen ) == -1)
-            fatal_error( "file '%s/%s' exists,\n"
-                         "   but I cannot connect to it; maybe the server has crashed?\n"
-                         "   If this is the case, you should remove this socket file and try again.\n",
-                         serverdir, SOCKETNAME );
+        if (connect( s, (struct sockaddr *)&addr, slen ) != -1)
+        {
+            fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
+            return s;
+        }
+        close( s );
     }
-    fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
-    return s;
+    fatal_error( "file '%s/%s' exists,\n"
+                 "   but I cannot connect to it; maybe the server has crashed?\n"
+                 "   If this is the case, you should remove this socket file and try again.\n",
+                 serverdir, SOCKETNAME );
 }