Made server startup more robust against races caused by a previous
server terminating at the same time.
This commit is contained in:
parent
e0df32ff4f
commit
c10c9ef4f1
|
@ -338,6 +338,7 @@ const char *get_config_dir(void)
|
|||
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 @@ static void start_server( const char *oldcwd )
|
|||
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, argv0 ), '/' )))
|
||||
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 */
|
||||
execl( "./server/wineserver", "wineserver", NULL );
|
||||
if (!(path = malloc( strlen(oldcwd) + 20 )))
|
||||
fatal_error( "out of memory\n" );
|
||||
if ((p = strrchr( strcpy( path, oldcwd ), '/' )))
|
||||
{
|
||||
strcpy( p, "/wineserver" );
|
||||
execl( path, "wineserver", NULL );
|
||||
strcpy( p, "/server/wineserver" );
|
||||
execl( path, "wineserver", NULL );
|
||||
}
|
||||
fatal_error( "could not exec wineserver\n" );
|
||||
}
|
||||
started = 1;
|
||||
|
@ -382,13 +395,13 @@ static int server_connect( const char *oldcwd, const char *serverdir )
|
|||
{
|
||||
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,6 +410,11 @@ static int server_connect( const char *oldcwd, const char *serverdir )
|
|||
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 );
|
||||
|
||||
for (retry = 0; retry < 3; retry++)
|
||||
{
|
||||
/* if not the first try, wait a bit to leave the server time to exit */
|
||||
if (retry) usleep( 100000 * retry * retry );
|
||||
|
||||
/* check for an existing socket */
|
||||
if (lstat( SOCKETNAME, &st ) == -1)
|
||||
{
|
||||
|
@ -419,20 +437,17 @@ static int server_connect( const char *oldcwd, const char *serverdir )
|
|||
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)
|
||||
if (connect( s, (struct sockaddr *)&addr, slen ) != -1)
|
||||
{
|
||||
fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
|
||||
return s;
|
||||
}
|
||||
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 );
|
||||
}
|
||||
fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -296,7 +296,8 @@ static void master_socket_poll_event( struct object *obj, int event )
|
|||
/* 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 @@ void open_master_socket(void)
|
|||
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,6 +412,8 @@ void open_master_socket(void)
|
|||
/* close the master socket and stop waiting for new clients */
|
||||
void close_master_socket(void)
|
||||
{
|
||||
/* if a new client is waiting, we keep on running */
|
||||
if (!check_select_events( master_socket->obj.fd, POLLIN ))
|
||||
release_object( master_socket );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue