Made the server listen for new clients on a Unix socket in
$HOME/.wine. Newly started wine processes now attach to an existing server if one is running.
This commit is contained in:
parent
647876e598
commit
2fe57779fb
@ -100,7 +100,6 @@ LIBSUBDIRS = \
|
|||||||
relay32 \
|
relay32 \
|
||||||
resources \
|
resources \
|
||||||
scheduler \
|
scheduler \
|
||||||
server \
|
|
||||||
win32 \
|
win32 \
|
||||||
windows \
|
windows \
|
||||||
windows/ttydrv
|
windows/ttydrv
|
||||||
@ -112,7 +111,8 @@ X11SUBDIRS = \
|
|||||||
|
|
||||||
EMUSUBDIRS = \
|
EMUSUBDIRS = \
|
||||||
debugger \
|
debugger \
|
||||||
miscemu
|
miscemu \
|
||||||
|
server
|
||||||
|
|
||||||
PROGSUBDIRS = libtest programs
|
PROGSUBDIRS = libtest programs
|
||||||
|
|
||||||
@ -213,7 +213,6 @@ LIBOBJS = \
|
|||||||
relay32/relay32.o \
|
relay32/relay32.o \
|
||||||
resources/resources.o \
|
resources/resources.o \
|
||||||
scheduler/scheduler.o \
|
scheduler/scheduler.o \
|
||||||
server/server.o \
|
|
||||||
win32/win32.o \
|
win32/win32.o \
|
||||||
windows/windows.o \
|
windows/windows.o \
|
||||||
windows/ttydrv/ttydrv.o
|
windows/ttydrv/ttydrv.o
|
||||||
@ -231,7 +230,7 @@ LIB_TARGET = @LIB_TARGET@
|
|||||||
|
|
||||||
ALT_LINK = @ALT_LINK@
|
ALT_LINK = @ALT_LINK@
|
||||||
|
|
||||||
all: Makefile Make.rules $(MAIN_TARGET)
|
all: Makefile Make.rules server $(MAIN_TARGET)
|
||||||
@echo "Wine build complete."
|
@echo "Wine build complete."
|
||||||
|
|
||||||
LIBLINTS = $(LIBOBJS:.o=.ln)
|
LIBLINTS = $(LIBOBJS:.o=.ln)
|
||||||
|
@ -121,7 +121,9 @@ struct new_process_request
|
|||||||
IN int cmd_show; /* main window show mode */
|
IN int cmd_show; /* main window show mode */
|
||||||
IN void* env_ptr; /* pointer to environment (FIXME: hack) */
|
IN void* env_ptr; /* pointer to environment (FIXME: hack) */
|
||||||
OUT void* pid; /* process id */
|
OUT void* pid; /* process id */
|
||||||
OUT int handle; /* process handle (in the current process) */
|
OUT int phandle; /* process handle (in the current process) */
|
||||||
|
OUT void* tid; /* thread id */
|
||||||
|
OUT int thandle; /* thread handle (in the current process) */
|
||||||
IN char cmdline[1]; /* command line */
|
IN char cmdline[1]; /* command line */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,7 +131,6 @@ struct new_process_request
|
|||||||
/* Create a new thread from the context of the parent */
|
/* Create a new thread from the context of the parent */
|
||||||
struct new_thread_request
|
struct new_thread_request
|
||||||
{
|
{
|
||||||
IN void* pid; /* process id for the new thread */
|
|
||||||
IN int suspend; /* new thread should be suspended on creation */
|
IN int suspend; /* new thread should be suspended on creation */
|
||||||
IN int inherit; /* inherit flag */
|
IN int inherit; /* inherit flag */
|
||||||
OUT void* tid; /* thread id */
|
OUT void* tid; /* thread id */
|
||||||
@ -137,10 +138,10 @@ struct new_thread_request
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Set the server debug level */
|
/* Signal that we are finished booting on the client side */
|
||||||
struct set_debug_request
|
struct boot_done_request
|
||||||
{
|
{
|
||||||
IN int level; /* New debug level */
|
IN int debug_level; /* new debug level */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -171,6 +172,7 @@ struct init_thread_request
|
|||||||
IN void* teb; /* TEB of new thread (in thread address space) */
|
IN void* teb; /* TEB of new thread (in thread address space) */
|
||||||
OUT void* pid; /* process id of the new thread's process */
|
OUT void* pid; /* process id of the new thread's process */
|
||||||
OUT void* tid; /* thread id of the new thread */
|
OUT void* tid; /* thread id of the new thread */
|
||||||
|
OUT int boot; /* is this the boot thread? */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1036,7 +1038,7 @@ enum request
|
|||||||
{
|
{
|
||||||
REQ_NEW_PROCESS,
|
REQ_NEW_PROCESS,
|
||||||
REQ_NEW_THREAD,
|
REQ_NEW_THREAD,
|
||||||
REQ_SET_DEBUG,
|
REQ_BOOT_DONE,
|
||||||
REQ_INIT_PROCESS,
|
REQ_INIT_PROCESS,
|
||||||
REQ_INIT_PROCESS_DONE,
|
REQ_INIT_PROCESS_DONE,
|
||||||
REQ_INIT_THREAD,
|
REQ_INIT_THREAD,
|
||||||
@ -1189,7 +1191,8 @@ static inline void server_strcpyAtoW( WCHAR *dst, const char *src )
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern int CLIENT_InitServer(void);
|
extern int CLIENT_InitServer(void);
|
||||||
extern int CLIENT_SetDebug( int level );
|
extern int CLIENT_BootDone( int debug_level );
|
||||||
|
extern int CLIENT_IsBootThread(void);
|
||||||
extern int CLIENT_DebuggerRequest( int op );
|
extern int CLIENT_DebuggerRequest( int op );
|
||||||
extern int CLIENT_InitThread(void);
|
extern int CLIENT_InitThread(void);
|
||||||
#endif /* __WINE_SERVER__ */
|
#endif /* __WINE_SERVER__ */
|
||||||
|
@ -121,7 +121,7 @@ typedef struct _TEB
|
|||||||
|
|
||||||
/* scheduler/thread.c */
|
/* scheduler/thread.c */
|
||||||
extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd );
|
extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd );
|
||||||
extern TEB *THREAD_Create( struct _PDB *pdb, DWORD flags,
|
extern TEB *THREAD_Create( struct _PDB *pdb, int fd, DWORD flags,
|
||||||
DWORD stack_size, BOOL alloc_stack16,
|
DWORD stack_size, BOOL alloc_stack16,
|
||||||
LPSECURITY_ATTRIBUTES sa, int *server_handle );
|
LPSECURITY_ATTRIBUTES sa, int *server_handle );
|
||||||
extern BOOL THREAD_IsWin16( TEB *thdb );
|
extern BOOL THREAD_IsWin16( TEB *thdb );
|
||||||
|
@ -67,24 +67,27 @@ BOOL MAIN_MainInit( int *argc, char *argv[] )
|
|||||||
/* Parse command line arguments */
|
/* Parse command line arguments */
|
||||||
MAIN_WineInit( argc, argv );
|
MAIN_WineInit( argc, argv );
|
||||||
|
|
||||||
/* Set server debug level */
|
|
||||||
CLIENT_SetDebug( TRACE_ON(server) );
|
|
||||||
|
|
||||||
/* Load the configuration file */
|
/* Load the configuration file */
|
||||||
if (!PROFILE_LoadWineIni()) return FALSE;
|
if (!PROFILE_LoadWineIni()) return FALSE;
|
||||||
|
|
||||||
/* Initialize module loadorder */
|
|
||||||
if (!MODULE_InitLoadOrder()) return FALSE;
|
|
||||||
|
|
||||||
/* Initialize DOS memory */
|
|
||||||
if (!DOSMEM_Init(0)) return FALSE;
|
|
||||||
|
|
||||||
/* Initialise DOS drives */
|
/* Initialise DOS drives */
|
||||||
if (!DRIVE_Init()) return FALSE;
|
if (!DRIVE_Init()) return FALSE;
|
||||||
|
|
||||||
/* Initialise DOS directories */
|
/* Initialise DOS directories */
|
||||||
if (!DIR_Init()) return FALSE;
|
if (!DIR_Init()) return FALSE;
|
||||||
|
|
||||||
|
/* Registry initialisation */
|
||||||
|
SHELL_LoadRegistry();
|
||||||
|
|
||||||
|
/* Global boot finished, the rest is process-local */
|
||||||
|
CLIENT_BootDone( TRACE_ON(server) );
|
||||||
|
|
||||||
|
/* Initialize module loadorder */
|
||||||
|
if (!MODULE_InitLoadOrder()) return FALSE;
|
||||||
|
|
||||||
|
/* Initialize DOS memory */
|
||||||
|
if (!DOSMEM_Init(0)) return FALSE;
|
||||||
|
|
||||||
/* Initialize event handling */
|
/* Initialize event handling */
|
||||||
if (!EVENT_Init()) return FALSE;
|
if (!EVENT_Init()) return FALSE;
|
||||||
|
|
||||||
@ -94,9 +97,6 @@ BOOL MAIN_MainInit( int *argc, char *argv[] )
|
|||||||
/* Initialize IO-port permissions */
|
/* Initialize IO-port permissions */
|
||||||
IO_port_init();
|
IO_port_init();
|
||||||
|
|
||||||
/* registry initialisation */
|
|
||||||
SHELL_LoadRegistry();
|
|
||||||
|
|
||||||
/* Read DOS config.sys */
|
/* Read DOS config.sys */
|
||||||
if (!DOSCONF_ReadConfig()) return FALSE;
|
if (!DOSCONF_ReadConfig()) return FALSE;
|
||||||
|
|
||||||
|
@ -1486,6 +1486,8 @@ void SHELL_LoadRegistry( void )
|
|||||||
|
|
||||||
TRACE("(void)\n");
|
TRACE("(void)\n");
|
||||||
|
|
||||||
|
if (!CLIENT_IsBootThread()) return; /* already loaded */
|
||||||
|
|
||||||
REGISTRY_Init();
|
REGISTRY_Init();
|
||||||
SetLoadLevel(0);
|
SetLoadLevel(0);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -15,9 +16,11 @@
|
|||||||
#ifdef HAVE_SYS_SOCKET_H
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <sys/un.h>
|
||||||
#ifdef HAVE_SYS_MMAN_H
|
#ifdef HAVE_SYS_MMAN_H
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -26,12 +29,17 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
/* Some versions of glibc don't define this */
|
/* Some versions of glibc don't define this */
|
||||||
#ifndef SCM_RIGHTS
|
#ifndef SCM_RIGHTS
|
||||||
#define SCM_RIGHTS 1
|
#define SCM_RIGHTS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SERVERDIR "/wineserver-" /* server socket directory (hostname appended) */
|
||||||
|
#define SOCKETNAME "socket" /* name of the socket file */
|
||||||
|
|
||||||
/* data structure used to pass an fd with sendmsg/recvmsg */
|
/* data structure used to pass an fd with sendmsg/recvmsg */
|
||||||
struct cmsg_fd
|
struct cmsg_fd
|
||||||
{
|
{
|
||||||
@ -41,6 +49,34 @@ struct cmsg_fd
|
|||||||
int fd; /* fd to pass */
|
int fd; /* fd to pass */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void *boot_thread_id;
|
||||||
|
|
||||||
|
|
||||||
|
/* die on a fatal error; use only during initialization */
|
||||||
|
static void fatal_error( const char *err, ... )
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start( args, err );
|
||||||
|
fprintf( stderr, "wine: " );
|
||||||
|
vfprintf( stderr, err, args );
|
||||||
|
va_end( args );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* die on a fatal error; use only during initialization */
|
||||||
|
static void fatal_perror( const char *err, ... )
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start( args, err );
|
||||||
|
fprintf( stderr, "wine: " );
|
||||||
|
vfprintf( stderr, err, args );
|
||||||
|
perror( " " );
|
||||||
|
va_end( args );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CLIENT_Die
|
* CLIENT_Die
|
||||||
*
|
*
|
||||||
@ -257,6 +293,76 @@ unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* start_server
|
||||||
|
*
|
||||||
|
* Start a new wine server.
|
||||||
|
*/
|
||||||
|
static void start_server( const char *oldcwd )
|
||||||
|
{
|
||||||
|
static int started; /* we only try once */
|
||||||
|
if (!started)
|
||||||
|
{
|
||||||
|
int pid = fork();
|
||||||
|
if (pid == -1) fatal_perror( "fork" );
|
||||||
|
if (!pid)
|
||||||
|
{
|
||||||
|
execl( BINDIR "/wineserver", "wineserver", NULL );
|
||||||
|
if (oldcwd) chdir( oldcwd );
|
||||||
|
execlp( "wineserver", "wineserver", NULL );
|
||||||
|
execl( "./server/wineserver", "wineserver", NULL );
|
||||||
|
fatal_error( "could not exec wineserver\n" );
|
||||||
|
}
|
||||||
|
started = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* server_connect
|
||||||
|
*
|
||||||
|
* Attempt to connect to an existing server socket.
|
||||||
|
* We need to be in the server directory already.
|
||||||
|
*/
|
||||||
|
static int server_connect( const char *oldcwd, const char *serverdir )
|
||||||
|
{
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
struct stat st;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if (chdir( serverdir ) == -1)
|
||||||
|
{
|
||||||
|
if (errno != ENOENT) fatal_perror( "chdir to %s", serverdir );
|
||||||
|
start_server( NULL );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (stat( ".", &st ) == -1) fatal_perror( "stat %s", 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 );
|
||||||
|
|
||||||
|
if (lstat( SOCKETNAME, &st ) == -1)
|
||||||
|
{
|
||||||
|
if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
|
||||||
|
start_server( oldcwd );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
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 );
|
||||||
|
|
||||||
|
if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy( addr.sun_path, SOCKETNAME );
|
||||||
|
if (connect( s, &addr, sizeof(addr.sun_family) + strlen(addr.sun_path) ) == -1)
|
||||||
|
{
|
||||||
|
close( s );
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CLIENT_InitServer
|
* CLIENT_InitServer
|
||||||
*
|
*
|
||||||
@ -264,34 +370,62 @@ unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
|
|||||||
*/
|
*/
|
||||||
int CLIENT_InitServer(void)
|
int CLIENT_InitServer(void)
|
||||||
{
|
{
|
||||||
int fd[2];
|
int delay, fd, size;
|
||||||
char buffer[16];
|
const char *env_fd;
|
||||||
extern void create_initial_thread( int fd );
|
char hostname[64];
|
||||||
|
char *oldcwd, *serverdir;
|
||||||
|
const char *configdir;
|
||||||
|
|
||||||
if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
|
/* first check if we inherited the socket fd */
|
||||||
|
if ((env_fd = getenv( "__WINE_FD" )) && isdigit(env_fd[0]))
|
||||||
{
|
{
|
||||||
perror("socketpair");
|
fd = atoi( env_fd );
|
||||||
exit(1);
|
if (fcntl( fd, F_GETFL, 0 ) != -1) return fd;
|
||||||
}
|
}
|
||||||
switch(fork())
|
|
||||||
|
/* retrieve the current directory */
|
||||||
|
for (size = 512; ; size *= 2)
|
||||||
{
|
{
|
||||||
case -1: /* error */
|
oldcwd = xmalloc( size );
|
||||||
perror("fork");
|
if (getcwd( oldcwd, size )) break;
|
||||||
exit(1);
|
free( oldcwd );
|
||||||
case 0: /* child */
|
if (errno == ERANGE) continue;
|
||||||
close( fd[1] );
|
oldcwd = NULL;
|
||||||
fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
|
|
||||||
break;
|
break;
|
||||||
default: /* parent */
|
|
||||||
close( fd[0] );
|
|
||||||
sprintf( buffer, "%d", fd[1] );
|
|
||||||
execl( BINDIR "/wineserver", "wineserver", buffer, NULL );
|
|
||||||
execlp( "wineserver", "wineserver", buffer, NULL );
|
|
||||||
execl( "./server/wineserver", "wineserver", buffer, NULL );
|
|
||||||
create_initial_thread( fd[1] );
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
return fd[0];
|
|
||||||
|
/* get the server directory name */
|
||||||
|
if (gethostname( hostname, sizeof(hostname) ) == -1) fatal_perror( "gethostname" );
|
||||||
|
configdir = PROFILE_GetConfigDir();
|
||||||
|
serverdir = xmalloc( strlen(configdir) + strlen(SERVERDIR) + strlen(hostname) + 1 );
|
||||||
|
strcpy( serverdir, configdir );
|
||||||
|
strcat( serverdir, SERVERDIR );
|
||||||
|
strcat( serverdir, hostname );
|
||||||
|
|
||||||
|
/* try to connect, leaving some time for the server to start up */
|
||||||
|
for (delay = 10000; delay < 500000; delay += delay / 2)
|
||||||
|
{
|
||||||
|
if ((fd = server_connect( oldcwd, serverdir )) >= 0) goto done;
|
||||||
|
usleep( delay );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == -2)
|
||||||
|
{
|
||||||
|
fatal_error( "'%s/%s' exists,\n"
|
||||||
|
" but I cannot connect to it; maybe the server has crashed?\n"
|
||||||
|
" If this is the case, you should remove the socket file and try again.\n",
|
||||||
|
serverdir, SOCKETNAME );
|
||||||
|
}
|
||||||
|
fatal_error( "could not start wineserver, giving up\n" );
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* switch back to the starting directory */
|
||||||
|
if (oldcwd)
|
||||||
|
{
|
||||||
|
chdir( oldcwd );
|
||||||
|
free( oldcwd );
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -319,20 +453,32 @@ int CLIENT_InitThread(void)
|
|||||||
if (server_call( REQ_INIT_THREAD )) return -1;
|
if (server_call( REQ_INIT_THREAD )) return -1;
|
||||||
teb->process->server_pid = req->pid;
|
teb->process->server_pid = req->pid;
|
||||||
teb->tid = req->tid;
|
teb->tid = req->tid;
|
||||||
|
if (req->boot) boot_thread_id = req->tid;
|
||||||
|
else if (boot_thread_id == req->tid) boot_thread_id = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* CLIENT_BootDone
|
||||||
|
*
|
||||||
|
* Signal that we have finished booting, and set debug level.
|
||||||
|
*/
|
||||||
|
int CLIENT_BootDone( int debug_level )
|
||||||
|
{
|
||||||
|
struct boot_done_request *req = get_req_buffer();
|
||||||
|
req->debug_level = debug_level;
|
||||||
|
return server_call( REQ_BOOT_DONE );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CLIENT_SetDebug
|
* CLIENT_IsBootThread
|
||||||
*
|
*
|
||||||
* Send a set debug level request. Return 0 if OK.
|
* Return TRUE if current thread is the boot thread.
|
||||||
*/
|
*/
|
||||||
int CLIENT_SetDebug( int level )
|
int CLIENT_IsBootThread(void)
|
||||||
{
|
{
|
||||||
struct set_debug_request *req = get_req_buffer();
|
return (GetCurrentThreadId() == (DWORD)boot_thread_id);
|
||||||
req->level = level;
|
|
||||||
return server_call( REQ_SET_DEBUG );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
@ -346,4 +492,3 @@ int CLIENT_DebuggerRequest( int op )
|
|||||||
req->op = op;
|
req->op = op;
|
||||||
return server_call( REQ_DEBUGGER );
|
return server_call( REQ_DEBUGGER );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -241,13 +242,13 @@ static BOOL PROCESS_CreateEnvDB(void)
|
|||||||
|
|
||||||
/* Allocate the env DB */
|
/* Allocate the env DB */
|
||||||
|
|
||||||
if (!(env_db = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
|
if (!(env_db = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
pdb->env_db = env_db;
|
pdb->env_db = env_db;
|
||||||
InitializeCriticalSection( &env_db->section );
|
InitializeCriticalSection( &env_db->section );
|
||||||
|
|
||||||
/* Allocate and fill the startup info */
|
/* Allocate and fill the startup info */
|
||||||
if (!(startup = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
|
if (!(startup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
env_db->startup_info = startup;
|
env_db->startup_info = startup;
|
||||||
|
|
||||||
@ -263,11 +264,11 @@ static BOOL PROCESS_CreateEnvDB(void)
|
|||||||
|
|
||||||
/* Copy the parent environment */
|
/* Copy the parent environment */
|
||||||
|
|
||||||
if (!ENV_InheritEnvironment( pdb, req->env_ptr )) return FALSE;
|
if (!ENV_InheritEnvironment( req->env_ptr )) return FALSE;
|
||||||
|
|
||||||
/* Copy the command line */
|
/* Copy the command line */
|
||||||
|
|
||||||
if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
|
if (!(pdb->env_db->cmd_line = HEAP_strdupA( GetProcessHeap(), 0, cmd_line )))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -286,7 +287,6 @@ void PROCESS_FreePDB( PDB *pdb )
|
|||||||
ENV_FreeEnvironment( pdb );
|
ENV_FreeEnvironment( pdb );
|
||||||
while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
|
while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
|
||||||
if (*pptr) *pptr = pdb->next;
|
if (*pptr) *pptr = pdb->next;
|
||||||
if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
|
|
||||||
HeapFree( SystemHeap, 0, pdb );
|
HeapFree( SystemHeap, 0, pdb );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,11 +306,9 @@ static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
|
|||||||
pdb->threads = 1;
|
pdb->threads = 1;
|
||||||
pdb->running_threads = 1;
|
pdb->running_threads = 1;
|
||||||
pdb->ring0_threads = 1;
|
pdb->ring0_threads = 1;
|
||||||
pdb->system_heap = SystemHeap;
|
|
||||||
pdb->parent = parent;
|
pdb->parent = parent;
|
||||||
pdb->group = pdb;
|
pdb->group = pdb;
|
||||||
pdb->priority = 8; /* Normal */
|
pdb->priority = 8; /* Normal */
|
||||||
pdb->heap = pdb->system_heap; /* will be changed later on */
|
|
||||||
pdb->next = PROCESS_First;
|
pdb->next = PROCESS_First;
|
||||||
pdb->winver = 0xffff; /* to be determined */
|
pdb->winver = 0xffff; /* to be determined */
|
||||||
pdb->main_queue = INVALID_HANDLE_VALUE16;
|
pdb->main_queue = INVALID_HANDLE_VALUE16;
|
||||||
@ -350,9 +348,9 @@ BOOL PROCESS_Init(void)
|
|||||||
/* Remember TEB selector of initial process for emergency use */
|
/* Remember TEB selector of initial process for emergency use */
|
||||||
SYSLEVEL_EmergencyTeb = teb->teb_sel;
|
SYSLEVEL_EmergencyTeb = teb->teb_sel;
|
||||||
|
|
||||||
/* Create the system heap */
|
/* Create the system and process heaps */
|
||||||
if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
|
if (!HEAP_CreateSystemHeap()) return FALSE;
|
||||||
initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
|
initial_pdb.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
|
||||||
|
|
||||||
/* Create the idle event for the initial process
|
/* Create the idle event for the initial process
|
||||||
FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
|
FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
|
||||||
@ -406,11 +404,13 @@ void PROCESS_Start(void)
|
|||||||
InitializeCriticalSection( &pdb->crit_section );
|
InitializeCriticalSection( &pdb->crit_section );
|
||||||
|
|
||||||
/* Create the heap */
|
/* Create the heap */
|
||||||
if (!(pdb->heap = HeapCreate( HEAP_GROWABLE,
|
if (!(pdb->heap = GetProcessHeap()))
|
||||||
header? header->SizeOfHeapReserve : 0x10000,
|
{
|
||||||
header? header->SizeOfHeapCommit : 0 )))
|
if (!(pdb->heap = HeapCreate( HEAP_GROWABLE,
|
||||||
goto error;
|
header? header->SizeOfHeapReserve : 0x10000,
|
||||||
pdb->heap_list = pdb->heap;
|
header? header->SizeOfHeapCommit : 0 )))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create the environment db */
|
/* Create the environment db */
|
||||||
if (!PROCESS_CreateEnvDB()) goto error;
|
if (!PROCESS_CreateEnvDB()) goto error;
|
||||||
@ -492,7 +492,8 @@ void PROCESS_Start(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If requested, add entry point breakpoint */
|
/* If requested, add entry point breakpoint */
|
||||||
if ( Options.debug && TASK_AddTaskEntryBreakpoint )
|
if ( (Options.debug && TASK_AddTaskEntryBreakpoint) ||
|
||||||
|
(pdb->flags & PDB32_DEBUGGED))
|
||||||
TASK_AddTaskEntryBreakpoint( pdb->task );
|
TASK_AddTaskEntryBreakpoint( pdb->task );
|
||||||
|
|
||||||
/* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
|
/* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
|
||||||
@ -515,6 +516,7 @@ void PROCESS_Start(void)
|
|||||||
|
|
||||||
case PROC_WIN32:
|
case PROC_WIN32:
|
||||||
TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
|
TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
|
||||||
|
if (pdb->flags & PDB32_DEBUGGED) DebugBreak();
|
||||||
ExitProcess( entry(NULL) );
|
ExitProcess( entry(NULL) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +538,7 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
|
|||||||
HANDLE handles[2], load_done_evt = 0;
|
HANDLE handles[2], load_done_evt = 0;
|
||||||
DWORD exitcode, size;
|
DWORD exitcode, size;
|
||||||
BOOL alloc_stack16;
|
BOOL alloc_stack16;
|
||||||
int server_thandle;
|
int server_thandle, fd = -1;
|
||||||
struct new_process_request *req = get_req_buffer();
|
struct new_process_request *req = get_req_buffer();
|
||||||
TEB *teb = NULL;
|
TEB *teb = NULL;
|
||||||
PDB *parent = PROCESS_Current();
|
PDB *parent = PROCESS_Current();
|
||||||
@ -568,12 +570,15 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
|
|||||||
req->cmd_show = startup->wShowWindow;
|
req->cmd_show = startup->wShowWindow;
|
||||||
req->env_ptr = (void*)env; /* FIXME: hack */
|
req->env_ptr = (void*)env; /* FIXME: hack */
|
||||||
lstrcpynA( req->cmdline, cmd_line, server_remaining(req->cmdline) );
|
lstrcpynA( req->cmdline, cmd_line, server_remaining(req->cmdline) );
|
||||||
if (server_call( REQ_NEW_PROCESS )) goto error;
|
if (server_call_fd( REQ_NEW_PROCESS, -1, &fd )) goto error;
|
||||||
|
fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
|
||||||
pdb->server_pid = req->pid;
|
pdb->server_pid = req->pid;
|
||||||
info->hProcess = req->handle;
|
info->hProcess = req->phandle;
|
||||||
info->dwProcessId = (DWORD)pdb->server_pid;
|
info->dwProcessId = (DWORD)req->pid;
|
||||||
|
info->hThread = req->thandle;
|
||||||
|
info->dwThreadId = (DWORD)req->tid;
|
||||||
|
|
||||||
if ((flags & DEBUG_PROCESS) ||
|
if ((flags & (DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS)) ||
|
||||||
((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
|
((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
|
||||||
pdb->flags |= PDB32_DEBUGGED;
|
pdb->flags |= PDB32_DEBUGGED;
|
||||||
|
|
||||||
@ -600,11 +605,11 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
|
|||||||
|
|
||||||
/* Create the main thread */
|
/* Create the main thread */
|
||||||
|
|
||||||
if (!(teb = THREAD_Create( pdb, flags & CREATE_SUSPENDED, size,
|
if (!(teb = THREAD_Create( pdb, fd, flags & CREATE_SUSPENDED, size,
|
||||||
alloc_stack16, tsa, &server_thandle ))) goto error;
|
alloc_stack16, tsa, &server_thandle ))) goto error;
|
||||||
info->hThread = server_thandle;
|
teb->tid = (void *)info->dwThreadId;
|
||||||
info->dwThreadId = (DWORD)teb->tid;
|
|
||||||
teb->startup = PROCESS_Start;
|
teb->startup = PROCESS_Start;
|
||||||
|
fd = -1; /* don't close it */
|
||||||
|
|
||||||
/* Pass module to new process (FIXME: hack) */
|
/* Pass module to new process (FIXME: hack) */
|
||||||
pdb->module = pModule->self;
|
pdb->module = pModule->self;
|
||||||
@ -650,6 +655,7 @@ error:
|
|||||||
if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
|
if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
|
||||||
if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
|
if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
|
||||||
PROCESS_FreePDB( pdb );
|
PROCESS_FreePDB( pdb );
|
||||||
|
if (fd != -1) close( fd );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,16 +858,6 @@ DWORD WINAPI GetCurrentProcessId(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* GetProcessHeap (KERNEL32.259)
|
|
||||||
*/
|
|
||||||
HANDLE WINAPI GetProcessHeap(void)
|
|
||||||
{
|
|
||||||
PDB *pdb = PROCESS_Current();
|
|
||||||
return pdb->heap ? pdb->heap : SystemHeap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* GetThreadLocale (KERNEL32.295)
|
* GetThreadLocale (KERNEL32.295)
|
||||||
*/
|
*/
|
||||||
@ -1236,22 +1232,6 @@ BOOL WINAPI GetExitCodeProcess(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* GetProcessHeaps [KERNEL32.376]
|
|
||||||
*/
|
|
||||||
DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
|
|
||||||
FIXME_(win32)("(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
|
|
||||||
|
|
||||||
if (nrofheaps) {
|
|
||||||
heaps[0] = GetProcessHeap();
|
|
||||||
/* ... probably SystemHeap too ? */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* number of available heaps */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SetErrorMode (KERNEL32.486)
|
* SetErrorMode (KERNEL32.486)
|
||||||
*/
|
*/
|
||||||
|
@ -212,8 +212,8 @@ TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd )
|
|||||||
* allocate in this area and don't support a granularity of 4kb
|
* allocate in this area and don't support a granularity of 4kb
|
||||||
* yet we leave it to VirtualAlloc to choose an address.
|
* yet we leave it to VirtualAlloc to choose an address.
|
||||||
*/
|
*/
|
||||||
TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
|
TEB *THREAD_Create( PDB *pdb, int fd, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
|
||||||
LPSECURITY_ATTRIBUTES sa, int *server_handle )
|
LPSECURITY_ATTRIBUTES sa, int *server_handle )
|
||||||
{
|
{
|
||||||
struct new_thread_request *req = get_req_buffer();
|
struct new_thread_request *req = get_req_buffer();
|
||||||
HANDLE cleanup_object;
|
HANDLE cleanup_object;
|
||||||
@ -227,7 +227,7 @@ TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
|
|||||||
teb->tls_ptr = teb->tls_array;
|
teb->tls_ptr = teb->tls_array;
|
||||||
teb->process = pdb;
|
teb->process = pdb;
|
||||||
teb->exit_code = 0x103; /* STILL_ACTIVE */
|
teb->exit_code = 0x103; /* STILL_ACTIVE */
|
||||||
teb->socket = -1;
|
teb->socket = fd;
|
||||||
|
|
||||||
/* Allocate the TEB selector (%fs register) */
|
/* Allocate the TEB selector (%fs register) */
|
||||||
|
|
||||||
@ -237,13 +237,15 @@ TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
|
|||||||
|
|
||||||
/* Create the thread on the server side */
|
/* Create the thread on the server side */
|
||||||
|
|
||||||
req->pid = teb->process->server_pid;
|
if (teb->socket == -1)
|
||||||
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
|
{
|
||||||
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
|
||||||
if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error;
|
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||||
teb->tid = req->tid;
|
if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error;
|
||||||
*server_handle = req->handle;
|
teb->tid = req->tid;
|
||||||
fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */
|
*server_handle = req->handle;
|
||||||
|
fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */
|
||||||
|
}
|
||||||
|
|
||||||
/* Do the rest of the initialization */
|
/* Do the rest of the initialization */
|
||||||
|
|
||||||
@ -295,7 +297,7 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
|
|||||||
DWORD flags, LPDWORD id )
|
DWORD flags, LPDWORD id )
|
||||||
{
|
{
|
||||||
int handle = -1;
|
int handle = -1;
|
||||||
TEB *teb = THREAD_Create( PROCESS_Current(), flags, stack, TRUE, sa, &handle );
|
TEB *teb = THREAD_Create( PROCESS_Current(), -1, flags, stack, TRUE, sa, &handle );
|
||||||
if (!teb) return 0;
|
if (!teb) return 0;
|
||||||
teb->flags |= TEBF_WIN32;
|
teb->flags |= TEBF_WIN32;
|
||||||
teb->entry_point = start;
|
teb->entry_point = start;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
DEFS = @DLLFLAGS@ -D__WINE__ -D__WINE_SERVER__
|
DEFS = -D__WINE__ -D__WINE_SERVER__
|
||||||
TOPSRCDIR = @top_srcdir@
|
TOPSRCDIR = @top_srcdir@
|
||||||
TOPOBJDIR = ..
|
TOPOBJDIR = ..
|
||||||
SRCDIR = @srcdir@
|
SRCDIR = @srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
MODULE = server
|
MODULE = none
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
change.c \
|
change.c \
|
||||||
@ -14,6 +14,7 @@ C_SRCS = \
|
|||||||
event.c \
|
event.c \
|
||||||
file.c \
|
file.c \
|
||||||
handle.c \
|
handle.c \
|
||||||
|
main.c \
|
||||||
mapping.c \
|
mapping.c \
|
||||||
mutex.c \
|
mutex.c \
|
||||||
object.c \
|
object.c \
|
||||||
@ -31,16 +32,13 @@ C_SRCS = \
|
|||||||
trace.c \
|
trace.c \
|
||||||
unicode.c
|
unicode.c
|
||||||
|
|
||||||
EXTRA_SRCS = main.c
|
|
||||||
MAIN_OBJS = main.o
|
|
||||||
|
|
||||||
PROGRAMS = wineserver
|
PROGRAMS = wineserver
|
||||||
|
|
||||||
all: $(MODULE).o $(PROGRAMS)
|
all: $(PROGRAMS)
|
||||||
|
|
||||||
@MAKE_RULES@
|
@MAKE_RULES@
|
||||||
|
|
||||||
wineserver: $(OBJS) $(MAIN_OBJS)
|
wineserver: $(OBJS)
|
||||||
$(CC) -o $(PROGRAMS) $(OBJS) $(MAIN_OBJS) $(LIBS)
|
$(CC) -o $(PROGRAMS) $(OBJS) $(LIBS)
|
||||||
|
|
||||||
### Dependencies:
|
### Dependencies:
|
||||||
|
@ -4,39 +4,98 @@
|
|||||||
* Copyright (C) 1998 Alexandre Julliard
|
* Copyright (C) 1998 Alexandre Julliard
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
/* command-line options */
|
||||||
|
int debug_level = 0;
|
||||||
|
int persistent_server = 0;
|
||||||
|
|
||||||
|
/* parse-line args */
|
||||||
|
/* FIXME: should probably use getopt, and add a help option */
|
||||||
|
static void parse_args( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (argv[i][0] == '-')
|
||||||
|
{
|
||||||
|
switch(argv[i][1])
|
||||||
|
{
|
||||||
|
case 'd':
|
||||||
|
if (isdigit(argv[i][2])) debug_level = atoi( argv[i] + 2 );
|
||||||
|
else debug_level++;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
persistent_server = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf( stderr, "Unknown option '%s'\n", argv[i] );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf( stderr, "Unknown argument '%s'\n", argv[i] );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sigterm_handler()
|
||||||
|
{
|
||||||
|
exit(1); /* make sure atexit functions get called */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize signal handling */
|
||||||
|
static void signal_init(void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (!debug_level)
|
||||||
|
{
|
||||||
|
switch(fork())
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
setsid();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
signal( SIGPIPE, SIG_IGN );
|
||||||
|
signal( SIGHUP, sigterm_handler );
|
||||||
|
signal( SIGINT, sigterm_handler );
|
||||||
|
signal( SIGQUIT, sigterm_handler );
|
||||||
|
signal( SIGTERM, sigterm_handler );
|
||||||
|
signal( SIGABRT, sigterm_handler );
|
||||||
|
}
|
||||||
|
|
||||||
int main( int argc, char *argv[] )
|
int main( int argc, char *argv[] )
|
||||||
{
|
{
|
||||||
int fd;
|
parse_args( argc, argv );
|
||||||
|
signal_init();
|
||||||
if (argc != 2) goto error;
|
open_master_socket();
|
||||||
if (!isdigit( *argv[1] )) goto error;
|
|
||||||
fd = atoi( argv[1] );
|
|
||||||
/* make sure the fd is valid */
|
|
||||||
if (fcntl( fd, F_GETFL, 0 ) == -1) goto error;
|
|
||||||
|
|
||||||
/* debug_level = 1; */
|
|
||||||
|
|
||||||
if (debug_level) fprintf( stderr, "Server: starting (pid=%ld)\n", (long) getpid() );
|
if (debug_level) fprintf( stderr, "Server: starting (pid=%ld)\n", (long) getpid() );
|
||||||
create_initial_thread( fd );
|
select_loop();
|
||||||
if (debug_level) fprintf( stderr, "Server: exiting (pid=%ld)\n", (long) getpid() );
|
if (debug_level) fprintf( stderr, "Server: exiting (pid=%ld)\n", (long) getpid() );
|
||||||
|
|
||||||
close_registry();
|
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
|
close_registry();
|
||||||
dump_objects(); /* dump any remaining objects */
|
dump_objects(); /* dump any remaining objects */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
error:
|
|
||||||
fprintf( stderr, "%s: must be run from Wine.\n", argv[0] );
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
|
|
||||||
int debug_level = 0;
|
|
||||||
|
|
||||||
struct object_name
|
struct object_name
|
||||||
{
|
{
|
||||||
|
@ -165,6 +165,9 @@ extern int get_page_size(void);
|
|||||||
|
|
||||||
extern void close_registry(void);
|
extern void close_registry(void);
|
||||||
|
|
||||||
|
/* global variables (command-line options) */
|
||||||
|
|
||||||
extern int debug_level;
|
extern int debug_level;
|
||||||
|
extern int persistent_server;
|
||||||
|
|
||||||
#endif /* __WINE_SERVER_OBJECT_H */
|
#endif /* __WINE_SERVER_OBJECT_H */
|
||||||
|
197
server/process.c
197
server/process.c
@ -12,6 +12,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
@ -50,14 +51,89 @@ static const struct object_ops process_ops =
|
|||||||
process_destroy /* destroy */
|
process_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* set the process creation info */
|
||||||
|
static int set_creation_info( struct process *process, struct new_process_request *req,
|
||||||
|
const char *cmd_line, size_t len )
|
||||||
|
{
|
||||||
|
if (!(process->info = mem_alloc( sizeof(*process->info) + len ))) return 0;
|
||||||
|
if (req)
|
||||||
|
{
|
||||||
|
/* copy the request structure */
|
||||||
|
memcpy( process->info, req, sizeof(*req) );
|
||||||
|
}
|
||||||
|
else /* no request, use defaults */
|
||||||
|
{
|
||||||
|
req = process->info;
|
||||||
|
req->inherit = 0;
|
||||||
|
req->inherit_all = 0;
|
||||||
|
req->create_flags = CREATE_NEW_CONSOLE;
|
||||||
|
req->start_flags = STARTF_USESTDHANDLES;
|
||||||
|
req->hstdin = -1;
|
||||||
|
req->hstdout = -1;
|
||||||
|
req->hstderr = -1;
|
||||||
|
req->event = -1;
|
||||||
|
req->cmd_show = 0;
|
||||||
|
req->env_ptr = NULL;
|
||||||
|
}
|
||||||
|
memcpy( process->info->cmdline, cmd_line, len );
|
||||||
|
process->info->cmdline[len] = 0;
|
||||||
|
process->create_flags = process->info->create_flags;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* create a new process */
|
/* set the console and stdio handles for a newly created process */
|
||||||
static struct process *create_process( struct process *parent, struct new_process_request *req,
|
static int set_process_console( struct process *process, struct process *parent )
|
||||||
const char *cmd_line, size_t len )
|
{
|
||||||
|
struct new_process_request *info = process->info;
|
||||||
|
|
||||||
|
if (process->create_flags & CREATE_NEW_CONSOLE)
|
||||||
|
{
|
||||||
|
if (!alloc_console( process )) return 0;
|
||||||
|
}
|
||||||
|
else if (!(process->create_flags & DETACHED_PROCESS))
|
||||||
|
{
|
||||||
|
if (parent->console_in) process->console_in = grab_object( parent->console_in );
|
||||||
|
if (parent->console_out) process->console_out = grab_object( parent->console_out );
|
||||||
|
}
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
if (!info->inherit_all && !(info->start_flags & STARTF_USESTDHANDLES))
|
||||||
|
{
|
||||||
|
/* duplicate the handle from the parent into this process */
|
||||||
|
info->hstdin = duplicate_handle( parent, info->hstdin, process,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||||
|
info->hstdout = duplicate_handle( parent, info->hstdout, process,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||||
|
info->hstderr = duplicate_handle( parent, info->hstderr, process,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no parent, use handles to the console for stdio */
|
||||||
|
info->hstdin = alloc_handle( process, process->console_in,
|
||||||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||||
|
info->hstdout = alloc_handle( process, process->console_out,
|
||||||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||||
|
info->hstderr = alloc_handle( process, process->console_out,
|
||||||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new process and its main thread */
|
||||||
|
struct thread *create_process( int fd, struct process *parent,
|
||||||
|
struct new_process_request *req,
|
||||||
|
const char *cmd_line, size_t len )
|
||||||
{
|
{
|
||||||
struct process *process;
|
struct process *process;
|
||||||
|
struct thread *thread = NULL;
|
||||||
|
|
||||||
if (!(process = alloc_object( &process_ops, -1 ))) return NULL;
|
if (!(process = alloc_object( &process_ops, -1 )))
|
||||||
|
{
|
||||||
|
close( fd );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
process->next = NULL;
|
process->next = NULL;
|
||||||
process->prev = NULL;
|
process->prev = NULL;
|
||||||
process->thread_list = NULL;
|
process->thread_list = NULL;
|
||||||
@ -74,16 +150,13 @@ static struct process *create_process( struct process *parent, struct new_proces
|
|||||||
process->init_event = NULL;
|
process->init_event = NULL;
|
||||||
process->info = NULL;
|
process->info = NULL;
|
||||||
gettimeofday( &process->start_time, NULL );
|
gettimeofday( &process->start_time, NULL );
|
||||||
|
if ((process->next = first_process) != NULL) process->next->prev = process;
|
||||||
|
first_process = process;
|
||||||
|
|
||||||
/* copy the request structure */
|
/* copy the request structure */
|
||||||
if (!(process->info = mem_alloc( sizeof(*process->info) + len ))) goto error;
|
if (!set_creation_info( process, req, cmd_line, len )) goto error;
|
||||||
memcpy( process->info, req, sizeof(*req) );
|
|
||||||
memcpy( process->info->cmdline, cmd_line, len );
|
|
||||||
process->info->cmdline[len] = 0;
|
|
||||||
req = process->info; /* use the copy now */
|
|
||||||
process->create_flags = req->create_flags;
|
|
||||||
|
|
||||||
if (req->inherit_all)
|
if (process->info->inherit_all)
|
||||||
process->handles = copy_handle_table( process, parent );
|
process->handles = copy_handle_table( process, parent );
|
||||||
else
|
else
|
||||||
process->handles = alloc_handle_table( process, 0 );
|
process->handles = alloc_handle_table( process, 0 );
|
||||||
@ -93,32 +166,18 @@ static struct process *create_process( struct process *parent, struct new_proces
|
|||||||
alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
|
alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
|
||||||
|
|
||||||
/* get the init done event */
|
/* get the init done event */
|
||||||
if (req->event != -1)
|
if (process->info->event != -1)
|
||||||
{
|
{
|
||||||
if (!(process->init_event = get_event_obj( parent, req->event, EVENT_MODIFY_STATE )))
|
if (!(process->init_event = get_event_obj( parent, process->info->event,
|
||||||
goto error;
|
EVENT_MODIFY_STATE ))) goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the process console */
|
/* set the process console */
|
||||||
if (process->create_flags & CREATE_NEW_CONSOLE)
|
if (!set_process_console( process, parent )) goto error;
|
||||||
{
|
|
||||||
if (!alloc_console( process )) goto error;
|
|
||||||
}
|
|
||||||
else if (!(process->create_flags & DETACHED_PROCESS))
|
|
||||||
{
|
|
||||||
if (parent->console_in) process->console_in = grab_object( parent->console_in );
|
|
||||||
if (parent->console_out) process->console_out = grab_object( parent->console_out );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req->inherit_all && !(req->start_flags & STARTF_USESTDHANDLES))
|
/* create the main thread */
|
||||||
{
|
if (!(thread = create_thread( fd, process, (process->create_flags & CREATE_SUSPENDED) != 0)))
|
||||||
process->info->hstdin = duplicate_handle( parent, req->hstdin, process,
|
goto error;
|
||||||
0, TRUE, DUPLICATE_SAME_ACCESS );
|
|
||||||
process->info->hstdout = duplicate_handle( parent, req->hstdout, process,
|
|
||||||
0, TRUE, DUPLICATE_SAME_ACCESS );
|
|
||||||
process->info->hstderr = duplicate_handle( parent, req->hstderr, process,
|
|
||||||
0, TRUE, DUPLICATE_SAME_ACCESS );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* attach to the debugger if requested */
|
/* attach to the debugger if requested */
|
||||||
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
|
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
|
||||||
@ -126,45 +185,17 @@ static struct process *create_process( struct process *parent, struct new_proces
|
|||||||
else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
|
else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
|
||||||
debugger_attach( process, parent->debugger );
|
debugger_attach( process, parent->debugger );
|
||||||
|
|
||||||
if ((process->next = first_process) != NULL) process->next->prev = process;
|
release_object( process );
|
||||||
first_process = process;
|
return thread;
|
||||||
return process;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
close( fd );
|
||||||
free_console( process );
|
free_console( process );
|
||||||
if (process->handles) release_object( process->handles );
|
if (process->handles) release_object( process->handles );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the initial process */
|
|
||||||
struct process *create_initial_process(void)
|
|
||||||
{
|
|
||||||
struct process *process;
|
|
||||||
struct new_process_request req;
|
|
||||||
|
|
||||||
req.inherit = 0;
|
|
||||||
req.inherit_all = 0;
|
|
||||||
req.create_flags = CREATE_NEW_CONSOLE;
|
|
||||||
req.start_flags = STARTF_USESTDHANDLES;
|
|
||||||
req.hstdin = -1;
|
|
||||||
req.hstdout = -1;
|
|
||||||
req.hstderr = -1;
|
|
||||||
req.event = -1;
|
|
||||||
req.cmd_show = 0;
|
|
||||||
req.env_ptr = NULL;
|
|
||||||
if ((process = create_process( NULL, &req, "", 1 )))
|
|
||||||
{
|
|
||||||
process->info->hstdin = alloc_handle( process, process->console_in,
|
|
||||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
|
||||||
process->info->hstdout = alloc_handle( process, process->console_out,
|
|
||||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
|
||||||
process->info->hstderr = alloc_handle( process, process->console_out,
|
|
||||||
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
|
|
||||||
}
|
|
||||||
return process;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* destroy a process when its refcount is 0 */
|
/* destroy a process when its refcount is 0 */
|
||||||
static void process_destroy( struct object *obj )
|
static void process_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
@ -229,6 +260,8 @@ static void process_killed( struct process *process, int exit_code )
|
|||||||
{
|
{
|
||||||
/* last process died, close global handles */
|
/* last process died, close global handles */
|
||||||
close_global_handles();
|
close_global_handles();
|
||||||
|
/* this will cause the select loop to terminate */
|
||||||
|
if (!persistent_server) close_master_socket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,16 +488,40 @@ struct process_snapshot *process_snap( int *count )
|
|||||||
DECL_HANDLER(new_process)
|
DECL_HANDLER(new_process)
|
||||||
{
|
{
|
||||||
size_t len = get_req_strlen( req->cmdline );
|
size_t len = get_req_strlen( req->cmdline );
|
||||||
struct process *process;
|
struct thread *thread;
|
||||||
|
int sock[2];
|
||||||
|
|
||||||
req->handle = -1;
|
req->phandle = -1;
|
||||||
req->pid = NULL;
|
req->thandle = -1;
|
||||||
if ((process = create_process( current->process, req, req->cmdline, len )))
|
req->pid = NULL;
|
||||||
|
req->tid = NULL;
|
||||||
|
|
||||||
|
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) == -1)
|
||||||
{
|
{
|
||||||
req->handle = alloc_handle( current->process, process, PROCESS_ALL_ACCESS, req->inherit );
|
file_set_error();
|
||||||
req->pid = process;
|
return;
|
||||||
release_object( process );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((thread = create_process( sock[0], current->process, req, req->cmdline, len )))
|
||||||
|
{
|
||||||
|
int phandle = alloc_handle( current->process, thread->process,
|
||||||
|
PROCESS_ALL_ACCESS, req->inherit );
|
||||||
|
if ((req->phandle = phandle) != -1)
|
||||||
|
{
|
||||||
|
if ((req->thandle = alloc_handle( current->process, thread,
|
||||||
|
THREAD_ALL_ACCESS, req->inherit )) != -1)
|
||||||
|
{
|
||||||
|
/* thread object will be released when the thread gets killed */
|
||||||
|
set_reply_fd( current, sock[1] );
|
||||||
|
req->pid = thread->process;
|
||||||
|
req->tid = thread;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
close_handle( current->process, phandle );
|
||||||
|
}
|
||||||
|
release_object( thread );
|
||||||
|
}
|
||||||
|
close( sock[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize a new process */
|
/* initialize a new process */
|
||||||
|
@ -47,7 +47,9 @@ struct process_snapshot
|
|||||||
|
|
||||||
/* process functions */
|
/* process functions */
|
||||||
|
|
||||||
extern struct process *create_initial_process(void);
|
extern struct thread *create_process( int fd, struct process *parent,
|
||||||
|
struct new_process_request *req,
|
||||||
|
const char *cmd_line, size_t len );
|
||||||
extern struct process *get_process_from_id( void *id );
|
extern struct process *get_process_from_id( void *id );
|
||||||
extern struct process *get_process_from_handle( int handle, unsigned int access );
|
extern struct process *get_process_from_handle( int handle, unsigned int access );
|
||||||
extern int process_set_debugger( struct process *process, struct thread *thread );
|
extern int process_set_debugger( struct process *process, struct thread *thread );
|
||||||
|
197
server/request.c
197
server/request.c
@ -9,22 +9,27 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#ifdef HAVE_SYS_SOCKET_H
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
# include <sys/socket.h>
|
# include <sys/socket.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "winnt.h"
|
#include "winnt.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "wincon.h"
|
#include "wincon.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "process.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#define WANT_REQUEST_HANDLERS
|
#define WANT_REQUEST_HANDLERS
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
@ -34,9 +39,41 @@
|
|||||||
#define SCM_RIGHTS 1
|
#define SCM_RIGHTS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* path names for server master Unix socket */
|
||||||
|
#define CONFDIR "/.wine" /* directory for Wine config relative to $HOME */
|
||||||
|
#define SERVERDIR "/wineserver-" /* server socket directory (hostname appended) */
|
||||||
|
#define SOCKETNAME "socket" /* name of the socket file */
|
||||||
|
|
||||||
|
struct master_socket
|
||||||
|
{
|
||||||
|
struct object obj; /* object header */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void master_socket_dump( struct object *obj, int verbose );
|
||||||
|
static void master_socket_poll_event( struct object *obj, int event );
|
||||||
|
static void master_socket_destroy( struct object *obj );
|
||||||
|
|
||||||
|
static const struct object_ops master_socket_ops =
|
||||||
|
{
|
||||||
|
sizeof(struct master_socket), /* size */
|
||||||
|
master_socket_dump, /* dump */
|
||||||
|
no_add_queue, /* add_queue */
|
||||||
|
NULL, /* remove_queue */
|
||||||
|
NULL, /* signaled */
|
||||||
|
NULL, /* satisfied */
|
||||||
|
NULL, /* get_poll_events */
|
||||||
|
master_socket_poll_event, /* poll_event */
|
||||||
|
no_read_fd, /* get_read_fd */
|
||||||
|
no_write_fd, /* get_write_fd */
|
||||||
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
master_socket_destroy /* destroy */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct thread *current = NULL; /* thread handling the current request */
|
struct thread *current = NULL; /* thread handling the current request */
|
||||||
|
|
||||||
|
static struct master_socket *master_socket; /* the master socket object */
|
||||||
|
|
||||||
/* socket communication static structures */
|
/* socket communication static structures */
|
||||||
static struct iovec myiovec;
|
static struct iovec myiovec;
|
||||||
@ -64,6 +101,31 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
|
|||||||
kill_thread( thread, PROTOCOL_ERROR );
|
kill_thread( thread, PROTOCOL_ERROR );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* die on a fatal error */
|
||||||
|
static void fatal_error( const char *err, ... )
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start( args, err );
|
||||||
|
fprintf( stderr, "wineserver: " );
|
||||||
|
vfprintf( stderr, err, args );
|
||||||
|
va_end( args );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* die on a fatal error */
|
||||||
|
static void fatal_perror( const char *err, ... )
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start( args, err );
|
||||||
|
fprintf( stderr, "wineserver: " );
|
||||||
|
vfprintf( stderr, err, args );
|
||||||
|
perror( " " );
|
||||||
|
va_end( args );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* call a request handler */
|
/* call a request handler */
|
||||||
static void call_req_handler( struct thread *thread, enum request req, int fd )
|
static void call_req_handler( struct thread *thread, enum request req, int fd )
|
||||||
{
|
{
|
||||||
@ -187,12 +249,135 @@ int write_request( struct thread *thread )
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the debug level */
|
static void master_socket_dump( struct object *obj, int verbose )
|
||||||
DECL_HANDLER(set_debug)
|
|
||||||
{
|
{
|
||||||
debug_level = req->level;
|
struct master_socket *sock = (struct master_socket *)obj;
|
||||||
/* Make sure last_req is initialized */
|
assert( obj->ops == &master_socket_ops );
|
||||||
current->last_req = REQ_SET_DEBUG;
|
fprintf( stderr, "Master socket fd=%d\n", sock->obj.fd );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle a socket event */
|
||||||
|
static void master_socket_poll_event( struct object *obj, int event )
|
||||||
|
{
|
||||||
|
struct master_socket *sock = (struct master_socket *)obj;
|
||||||
|
assert( obj->ops == &master_socket_ops );
|
||||||
|
|
||||||
|
assert( sock == master_socket ); /* there is only one master socket */
|
||||||
|
|
||||||
|
if (event & (POLLERR | POLLHUP))
|
||||||
|
{
|
||||||
|
/* this is not supposed to happen */
|
||||||
|
fprintf( stderr, "wineserver: Error on master socket\n" );
|
||||||
|
release_object( obj );
|
||||||
|
}
|
||||||
|
else if (event & POLLIN)
|
||||||
|
{
|
||||||
|
struct sockaddr_un dummy;
|
||||||
|
int len = sizeof(dummy);
|
||||||
|
int client = accept( master_socket->obj.fd, &dummy, &len );
|
||||||
|
if (client != -1) create_process( client, NULL, NULL, "", 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove the socket upon exit */
|
||||||
|
static void socket_cleanup(void)
|
||||||
|
{
|
||||||
|
unlink( SOCKETNAME );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void master_socket_destroy( struct object *obj )
|
||||||
|
{
|
||||||
|
socket_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the configuration directory ($HOME/.wine) */
|
||||||
|
static const char *get_config_dir(void)
|
||||||
|
{
|
||||||
|
static char *confdir;
|
||||||
|
if (!confdir)
|
||||||
|
{
|
||||||
|
const char *home = getenv( "HOME" );
|
||||||
|
if (!home)
|
||||||
|
{
|
||||||
|
struct passwd *pwd = getpwuid( getuid() );
|
||||||
|
if (!pwd) fatal_error( "could not find your home directory\n" );
|
||||||
|
home = pwd->pw_dir;
|
||||||
|
}
|
||||||
|
if (!(confdir = malloc( strlen(home) + strlen(CONFDIR) + 1 )))
|
||||||
|
fatal_error( "out of memory\n" );
|
||||||
|
strcpy( confdir, home );
|
||||||
|
strcat( confdir, CONFDIR );
|
||||||
|
mkdir( confdir, 0755 ); /* just in case */
|
||||||
|
}
|
||||||
|
return confdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the server directory and chdir to it */
|
||||||
|
static void create_server_dir(void)
|
||||||
|
{
|
||||||
|
char hostname[64];
|
||||||
|
char *serverdir;
|
||||||
|
const char *confdir = get_config_dir();
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (gethostname( hostname, sizeof(hostname) ) == -1) fatal_perror( "gethostname" );
|
||||||
|
|
||||||
|
if (!(serverdir = malloc( strlen(confdir) + strlen(SERVERDIR) + strlen(hostname) + 1 )))
|
||||||
|
fatal_error( "out of memory\n" );
|
||||||
|
|
||||||
|
strcpy( serverdir, confdir );
|
||||||
|
strcat( serverdir, SERVERDIR );
|
||||||
|
strcat( serverdir, hostname );
|
||||||
|
|
||||||
|
if (chdir( serverdir ) == -1)
|
||||||
|
{
|
||||||
|
if (errno != ENOENT) fatal_perror( "chdir %s", serverdir );
|
||||||
|
if (mkdir( serverdir, 0700 ) == -1) fatal_perror( "mkdir %s", serverdir );
|
||||||
|
if (chdir( serverdir ) == -1) fatal_perror( "chdir %s", serverdir );
|
||||||
|
}
|
||||||
|
if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir );
|
||||||
|
if (!S_ISDIR(st.st_mode)) fatal_error( "%s is not a directory\n", 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the master server socket and start waiting for new clients */
|
||||||
|
void open_master_socket(void)
|
||||||
|
{
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
create_server_dir();
|
||||||
|
if ((fd = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy( addr.sun_path, "socket" );
|
||||||
|
if (bind( fd, &addr, sizeof(addr.sun_family) + strlen(addr.sun_path) ) == -1)
|
||||||
|
{
|
||||||
|
if ((errno == EEXIST) || (errno == EADDRINUSE))
|
||||||
|
fatal_error( "another server is already running\n" );
|
||||||
|
else
|
||||||
|
fatal_perror( "bind" );
|
||||||
|
}
|
||||||
|
atexit( socket_cleanup );
|
||||||
|
|
||||||
|
chmod( "socket", 0600 ); /* make sure no other user can connect */
|
||||||
|
if (listen( fd, 5 ) == -1) fatal_perror( "listen" );
|
||||||
|
|
||||||
|
if (!(master_socket = alloc_object( &master_socket_ops, fd )))
|
||||||
|
fatal_error( "out of memory\n" );
|
||||||
|
set_select_events( &master_socket->obj, POLLIN );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close the master socket and stop waiting for new clients */
|
||||||
|
void close_master_socket(void)
|
||||||
|
{
|
||||||
|
release_object( master_socket );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lock/unlock the master socket to stop accepting new clients */
|
||||||
|
void lock_master_socket( int locked )
|
||||||
|
{
|
||||||
|
set_select_events( &master_socket->obj, locked ? 0 : POLLIN );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* debugger support operations */
|
/* debugger support operations */
|
||||||
|
@ -31,6 +31,9 @@ extern int write_request( struct thread *thread );
|
|||||||
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
||||||
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
||||||
extern void send_reply( struct thread *thread );
|
extern void send_reply( struct thread *thread );
|
||||||
|
extern void open_master_socket(void);
|
||||||
|
extern void close_master_socket(void);
|
||||||
|
extern void lock_master_socket( int locked );
|
||||||
|
|
||||||
extern void trace_request( enum request req, int fd );
|
extern void trace_request( enum request req, int fd );
|
||||||
extern void trace_kill( struct thread *thread );
|
extern void trace_kill( struct thread *thread );
|
||||||
@ -69,7 +72,7 @@ static inline size_t get_req_strlenW( const WCHAR *str )
|
|||||||
|
|
||||||
DECL_HANDLER(new_process);
|
DECL_HANDLER(new_process);
|
||||||
DECL_HANDLER(new_thread);
|
DECL_HANDLER(new_thread);
|
||||||
DECL_HANDLER(set_debug);
|
DECL_HANDLER(boot_done);
|
||||||
DECL_HANDLER(init_process);
|
DECL_HANDLER(init_process);
|
||||||
DECL_HANDLER(init_process_done);
|
DECL_HANDLER(init_process_done);
|
||||||
DECL_HANDLER(init_thread);
|
DECL_HANDLER(init_thread);
|
||||||
@ -168,7 +171,7 @@ static const struct handler {
|
|||||||
} req_handlers[REQ_NB_REQUESTS] = {
|
} req_handlers[REQ_NB_REQUESTS] = {
|
||||||
{ (void(*)())req_new_process, sizeof(struct new_process_request) },
|
{ (void(*)())req_new_process, sizeof(struct new_process_request) },
|
||||||
{ (void(*)())req_new_thread, sizeof(struct new_thread_request) },
|
{ (void(*)())req_new_thread, sizeof(struct new_thread_request) },
|
||||||
{ (void(*)())req_set_debug, sizeof(struct set_debug_request) },
|
{ (void(*)())req_boot_done, sizeof(struct boot_done_request) },
|
||||||
{ (void(*)())req_init_process, sizeof(struct init_process_request) },
|
{ (void(*)())req_init_process, sizeof(struct init_process_request) },
|
||||||
{ (void(*)())req_init_process_done, sizeof(struct init_process_done_request) },
|
{ (void(*)())req_init_process_done, sizeof(struct init_process_done_request) },
|
||||||
{ (void(*)())req_init_thread, sizeof(struct init_thread_request) },
|
{ (void(*)())req_init_thread, sizeof(struct init_thread_request) },
|
||||||
|
@ -210,9 +210,6 @@ void select_loop(void)
|
|||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
|
|
||||||
setsid();
|
|
||||||
signal( SIGPIPE, SIG_IGN );
|
|
||||||
|
|
||||||
/* block the signals we use */
|
/* block the signals we use */
|
||||||
sigemptyset( &sigset );
|
sigemptyset( &sigset );
|
||||||
sigaddset( &sigset, SIGCHLD );
|
sigaddset( &sigset, SIGCHLD );
|
||||||
|
@ -87,6 +87,7 @@ static const struct object_ops thread_ops =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct thread *first_thread;
|
static struct thread *first_thread;
|
||||||
|
static struct thread *booting_thread;
|
||||||
|
|
||||||
/* allocate the buffer for the communication with the client */
|
/* allocate the buffer for the communication with the client */
|
||||||
static int alloc_client_buffer( struct thread *thread )
|
static int alloc_client_buffer( struct thread *thread )
|
||||||
@ -106,7 +107,7 @@ static int alloc_client_buffer( struct thread *thread )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create a new thread */
|
/* create a new thread */
|
||||||
static struct thread *create_thread( int fd, struct process *process, int suspend )
|
struct thread *create_thread( int fd, struct process *process, int suspend )
|
||||||
{
|
{
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
int buf_fd;
|
int buf_fd;
|
||||||
@ -135,14 +136,15 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
|
|||||||
thread->suspend = (suspend != 0);
|
thread->suspend = (suspend != 0);
|
||||||
thread->buffer = (void *)-1;
|
thread->buffer = (void *)-1;
|
||||||
thread->last_req = REQ_GET_THREAD_BUFFER;
|
thread->last_req = REQ_GET_THREAD_BUFFER;
|
||||||
|
thread->process = (struct process *)grab_object( process );
|
||||||
|
|
||||||
if (!first_thread) /* creating the first thread */
|
if (!current) current = thread;
|
||||||
|
|
||||||
|
if (!booting_thread) /* first thread ever */
|
||||||
{
|
{
|
||||||
current = thread;
|
booting_thread = thread;
|
||||||
thread->process = process = create_initial_process();
|
lock_master_socket(1);
|
||||||
assert( process );
|
|
||||||
}
|
}
|
||||||
else thread->process = (struct process *)grab_object( process );
|
|
||||||
|
|
||||||
if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
|
if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
|
||||||
first_thread = thread;
|
first_thread = thread;
|
||||||
@ -161,13 +163,6 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the initial thread and start the main server loop */
|
|
||||||
void create_initial_thread( int fd )
|
|
||||||
{
|
|
||||||
create_thread( fd, NULL, 0 );
|
|
||||||
select_loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* handle a client event */
|
/* handle a client event */
|
||||||
void thread_poll_event( struct object *obj, int event )
|
void thread_poll_event( struct object *obj, int event )
|
||||||
{
|
{
|
||||||
@ -543,25 +538,34 @@ void kill_thread( struct thread *thread, int exit_code )
|
|||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* signal that we are finished booting on the client side */
|
||||||
|
DECL_HANDLER(boot_done)
|
||||||
|
{
|
||||||
|
debug_level = req->debug_level;
|
||||||
|
/* Make sure last_req is initialized */
|
||||||
|
current->last_req = REQ_BOOT_DONE;
|
||||||
|
if (current == booting_thread)
|
||||||
|
{
|
||||||
|
booting_thread = (struct thread *)~0UL; /* make sure it doesn't match other threads */
|
||||||
|
lock_master_socket(0); /* allow other clients now */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* create a new thread */
|
/* create a new thread */
|
||||||
DECL_HANDLER(new_thread)
|
DECL_HANDLER(new_thread)
|
||||||
{
|
{
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
struct process *process;
|
|
||||||
int sock[2];
|
int sock[2];
|
||||||
|
|
||||||
if (!(process = get_process_from_id( req->pid ))) return;
|
|
||||||
|
|
||||||
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1)
|
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1)
|
||||||
{
|
{
|
||||||
if ((thread = create_thread( sock[0], process, req->suspend )))
|
if ((thread = create_thread( sock[0], current->process, req->suspend )))
|
||||||
{
|
{
|
||||||
req->tid = thread;
|
req->tid = thread;
|
||||||
if ((req->handle = alloc_handle( current->process, thread,
|
if ((req->handle = alloc_handle( current->process, thread,
|
||||||
THREAD_ALL_ACCESS, req->inherit )) != -1)
|
THREAD_ALL_ACCESS, req->inherit )) != -1)
|
||||||
{
|
{
|
||||||
set_reply_fd( current, sock[1] );
|
set_reply_fd( current, sock[1] );
|
||||||
release_object( process );
|
|
||||||
/* thread object will be released when the thread gets killed */
|
/* thread object will be released when the thread gets killed */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -570,7 +574,6 @@ DECL_HANDLER(new_thread)
|
|||||||
close( sock[1] );
|
close( sock[1] );
|
||||||
}
|
}
|
||||||
else file_set_error();
|
else file_set_error();
|
||||||
release_object( process );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* retrieve the thread buffer file descriptor */
|
/* retrieve the thread buffer file descriptor */
|
||||||
@ -590,8 +593,9 @@ DECL_HANDLER(init_thread)
|
|||||||
current->unix_pid = req->unix_pid;
|
current->unix_pid = req->unix_pid;
|
||||||
current->teb = req->teb;
|
current->teb = req->teb;
|
||||||
if (current->suspend + current->process->suspend > 0) stop_thread( current );
|
if (current->suspend + current->process->suspend > 0) stop_thread( current );
|
||||||
req->pid = current->process;
|
req->pid = current->process;
|
||||||
req->tid = current;
|
req->tid = current;
|
||||||
|
req->boot = (current == booting_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* terminate a thread */
|
/* terminate a thread */
|
||||||
|
@ -62,7 +62,7 @@ extern struct thread *current;
|
|||||||
|
|
||||||
/* thread functions */
|
/* thread functions */
|
||||||
|
|
||||||
extern void create_initial_thread( int fd );
|
extern struct thread *create_thread( int fd, struct process *process, int suspend );
|
||||||
extern struct thread *get_thread_from_id( void *id );
|
extern struct thread *get_thread_from_id( void *id );
|
||||||
extern struct thread *get_thread_from_handle( int handle, unsigned int access );
|
extern struct thread *get_thread_from_handle( int handle, unsigned int access );
|
||||||
extern struct thread *get_thread_from_pid( int pid );
|
extern struct thread *get_thread_from_pid( int pid );
|
||||||
|
@ -215,12 +215,13 @@ static void dump_new_process_request( const struct new_process_request *req )
|
|||||||
static void dump_new_process_reply( const struct new_process_request *req )
|
static void dump_new_process_reply( const struct new_process_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " pid=%p,", req->pid );
|
fprintf( stderr, " pid=%p,", req->pid );
|
||||||
fprintf( stderr, " handle=%d", req->handle );
|
fprintf( stderr, " phandle=%d,", req->phandle );
|
||||||
|
fprintf( stderr, " tid=%p,", req->tid );
|
||||||
|
fprintf( stderr, " thandle=%d", req->thandle );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_new_thread_request( const struct new_thread_request *req )
|
static void dump_new_thread_request( const struct new_thread_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " pid=%p,", req->pid );
|
|
||||||
fprintf( stderr, " suspend=%d,", req->suspend );
|
fprintf( stderr, " suspend=%d,", req->suspend );
|
||||||
fprintf( stderr, " inherit=%d", req->inherit );
|
fprintf( stderr, " inherit=%d", req->inherit );
|
||||||
}
|
}
|
||||||
@ -231,9 +232,9 @@ static void dump_new_thread_reply( const struct new_thread_request *req )
|
|||||||
fprintf( stderr, " handle=%d", req->handle );
|
fprintf( stderr, " handle=%d", req->handle );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_set_debug_request( const struct set_debug_request *req )
|
static void dump_boot_done_request( const struct boot_done_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " level=%d", req->level );
|
fprintf( stderr, " debug_level=%d", req->debug_level );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_init_process_request( const struct init_process_request *req )
|
static void dump_init_process_request( const struct init_process_request *req )
|
||||||
@ -265,7 +266,8 @@ static void dump_init_thread_request( const struct init_thread_request *req )
|
|||||||
static void dump_init_thread_reply( const struct init_thread_request *req )
|
static void dump_init_thread_reply( const struct init_thread_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " pid=%p,", req->pid );
|
fprintf( stderr, " pid=%p,", req->pid );
|
||||||
fprintf( stderr, " tid=%p", req->tid );
|
fprintf( stderr, " tid=%p,", req->tid );
|
||||||
|
fprintf( stderr, " boot=%d", req->boot );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_get_thread_buffer_request( const struct get_thread_buffer_request *req )
|
static void dump_get_thread_buffer_request( const struct get_thread_buffer_request *req )
|
||||||
@ -1168,7 +1170,7 @@ static void dump_set_thread_context_request( const struct set_thread_context_req
|
|||||||
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_new_process_request,
|
(dump_func)dump_new_process_request,
|
||||||
(dump_func)dump_new_thread_request,
|
(dump_func)dump_new_thread_request,
|
||||||
(dump_func)dump_set_debug_request,
|
(dump_func)dump_boot_done_request,
|
||||||
(dump_func)dump_init_process_request,
|
(dump_func)dump_init_process_request,
|
||||||
(dump_func)dump_init_process_done_request,
|
(dump_func)dump_init_process_done_request,
|
||||||
(dump_func)dump_init_thread_request,
|
(dump_func)dump_init_thread_request,
|
||||||
@ -1358,7 +1360,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||||||
static const char * const req_names[REQ_NB_REQUESTS] = {
|
static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
"new_process",
|
"new_process",
|
||||||
"new_thread",
|
"new_thread",
|
||||||
"set_debug",
|
"boot_done",
|
||||||
"init_process",
|
"init_process",
|
||||||
"init_process_done",
|
"init_process_done",
|
||||||
"init_thread",
|
"init_thread",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user