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 );
 }
 
 
diff --git a/server/request.c b/server/request.c
index cea639b..7f0cf64 100644
--- a/server/request.c
+++ b/server/request.c
@@ -296,7 +296,8 @@
 /* remove the socket upon exit */
 static void socket_cleanup(void)
 {
-    unlink( SOCKETNAME );
+    static int do_it_once;
+    if (!do_it_once++) unlink( SOCKETNAME );
 }
 
 static void master_socket_destroy( struct object *obj )
@@ -382,7 +383,7 @@
     if (bind( fd, (struct sockaddr *)&addr, slen ) == -1)
     {
         if ((errno == EEXIST) || (errno == EADDRINUSE))
-            fatal_error( "another server is already running\n" );
+            exit(0);  /* pretend we succeeded to start */
         else
             fatal_perror( "bind" );
     }
@@ -411,7 +412,9 @@
 /* close the master socket and stop waiting for new clients */
 void close_master_socket(void)
 {
-    release_object( master_socket );
+    /* if a new client is waiting, we keep on running */
+    if (!check_select_events( master_socket->obj.fd, POLLIN ))
+        release_object( master_socket );
 }
 
 /* lock/unlock the master socket to stop accepting new clients */