kernel32: Separate the exec process functionality.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2018-10-22 11:45:54 +02:00
parent bff3255703
commit 7e96514029
1 changed files with 146 additions and 76 deletions

View File

@ -2033,11 +2033,11 @@ static BOOL terminate_main_thread(void)
#endif
/***********************************************************************
* exec_loader
* spawn_loader
*/
static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned int flags, int socketfd,
static pid_t spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned int flags, int socketfd,
int stdin_fd, int stdout_fd, const char *unixdir, char *winedebug,
const pe_image_info_t *pe_info, int exec_only )
const pe_image_info_t *pe_info )
{
pid_t pid;
char *wineloader = NULL;
@ -2049,9 +2049,9 @@ static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned in
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
loader = get_alternate_loader( &wineloader );
if (exec_only || !(pid = fork())) /* child */
if (!(pid = fork())) /* child */
{
if (exec_only || !(pid = fork())) /* grandchild */
if (!(pid = fork())) /* grandchild */
{
char preloader_reserve[64], socket_env[64];
ULONGLONG res_start = pe_info->base;
@ -2091,18 +2091,7 @@ static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned in
if (wineloader) putenv( wineloader );
if (unixdir) chdir(unixdir);
if (argv)
{
do
{
wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
}
#ifdef __APPLE__
while (errno == ENOTSUP && exec_only && terminate_main_thread());
#else
while (0);
#endif
}
if (argv) wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
_exit(1);
}
@ -2123,6 +2112,50 @@ static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned in
return pid;
}
/***********************************************************************
* exec_loader
*/
static NTSTATUS exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
const pe_image_info_t *pe_info )
{
char *wineloader = NULL;
const char *loader = NULL;
char **argv;
char preloader_reserve[64], socket_env[64];
ULONGLONG res_start = pe_info->base;
ULONGLONG res_end = pe_info->base + pe_info->map_size;
if (!(argv = build_argv( params->CommandLine.Buffer, 1 ))) return STATUS_NO_MEMORY;
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
loader = get_alternate_loader( &wineloader );
/* Reset signals that we previously set to SIG_IGN */
signal( SIGPIPE, SIG_DFL );
sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
(ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end );
putenv( preloader_reserve );
putenv( socket_env );
if (wineloader) putenv( wineloader );
do
{
wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
}
#ifdef __APPLE__
while (errno == ENOTSUP && exec_only && terminate_main_thread());
#else
while (0);
#endif
HeapFree( GetProcessHeap(), 0, wineloader );
HeapFree( GetProcessHeap(), 0, argv );
return STATUS_INVALID_IMAGE_FORMAT;
}
/* creates a struct security_descriptor and contained information in one contiguous piece of memory */
static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct object_attributes **ret,
data_size_t *ret_len )
@ -2185,6 +2218,61 @@ static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct
return STATUS_SUCCESS;
}
/***********************************************************************
* replace_process
*
* Replace the existing process by exec'ing a new one.
*/
static BOOL replace_process( HANDLE handle, const RTL_USER_PROCESS_PARAMETERS *params,
const pe_image_info_t *pe_info )
{
NTSTATUS status;
int socketfd[2];
if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
{
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
return FALSE;
}
#ifdef SO_PASSCRED
else
{
int enable = 1;
setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
}
#endif
wine_server_send_fd( socketfd[1] );
close( socketfd[1] );
SERVER_START_REQ( exec_process )
{
req->socket_fd = socketfd[1];
req->exe_file = wine_server_obj_handle( handle );
req->cpu = pe_info->cpu;
status = wine_server_call( req );
}
SERVER_END_REQ;
switch (status)
{
case STATUS_INVALID_IMAGE_WIN_64:
ERR( "64-bit application %s not supported in 32-bit prefix\n",
debugstr_w( params->ImagePathName.Buffer ));
break;
case STATUS_INVALID_IMAGE_FORMAT:
ERR( "%s not supported on this installation (%s binary)\n",
debugstr_w( params->ImagePathName.Buffer ), cpu_names[pe_info->cpu] );
break;
case STATUS_SUCCESS:
status = exec_loader( params, socketfd[0], pe_info );
break;
}
close( socketfd[0] );
SetLastError( RtlNtStatusToDosError( status ));
return FALSE;
}
/***********************************************************************
* create_process
*
@ -2193,8 +2281,7 @@ static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct
*/
static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
LPPROCESS_INFORMATION info, LPCSTR unixdir,
const pe_image_info_t *pe_info, int exec_only )
LPPROCESS_INFORMATION info, LPCSTR unixdir, const pe_image_info_t *pe_info )
{
NTSTATUS status;
BOOL success = FALSE;
@ -2224,38 +2311,6 @@ static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_
}
#endif
if (exec_only) /* things are much simpler in this case */
{
wine_server_send_fd( socketfd[1] );
close( socketfd[1] );
SERVER_START_REQ( exec_process )
{
req->socket_fd = socketfd[1];
req->exe_file = wine_server_obj_handle( hFile );
req->cpu = pe_info->cpu;
status = wine_server_call( req );
}
SERVER_END_REQ;
switch (status)
{
case STATUS_INVALID_IMAGE_WIN_64:
ERR( "64-bit application %s not supported in 32-bit prefix\n",
debugstr_w( params->ImagePathName.Buffer ));
break;
case STATUS_INVALID_IMAGE_FORMAT:
ERR( "%s not supported on this installation (%s binary)\n",
debugstr_w( params->ImagePathName.Buffer ), cpu_names[pe_info->cpu] );
break;
case STATUS_SUCCESS:
exec_loader( params, flags, socketfd[0], stdin_fd, stdout_fd, unixdir,
winedebug, pe_info, TRUE );
}
close( socketfd[0] );
SetLastError( RtlNtStatusToDosError( status ));
return FALSE;
}
if (!(startup_info = create_startup_info( params, &startup_info_size )))
{
close( socketfd[0] );
@ -2359,8 +2414,7 @@ static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_
/* create the child process */
pid = exec_loader( params, flags, socketfd[0], stdin_fd, stdout_fd, unixdir,
winedebug, pe_info, FALSE );
pid = spawn_loader( params, flags, socketfd[0], stdin_fd, stdout_fd, unixdir, winedebug, pe_info );
if (stdin_fd != -1) close( stdin_fd );
if (stdout_fd != -1) close( stdout_fd );
@ -2403,19 +2457,16 @@ error:
/***********************************************************************
* create_vdm_process
* get_vdm_params
*
* Create a new VDM process for a 16-bit or DOS application.
* Build the parameters needed to launch a new VDM process.
*/
static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
LPPROCESS_INFORMATION info, LPCSTR unixdir, int exec_only )
static RTL_USER_PROCESS_PARAMETERS *get_vdm_params( const RTL_USER_PROCESS_PARAMETERS *params,
pe_image_info_t *pe_info )
{
static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0};
BOOL ret;
LPWSTR new_cmd_line;
pe_image_info_t pe_info;
WCHAR *new_cmd_line;
RTL_USER_PROCESS_PARAMETERS *new_params;
UNICODE_STRING imageW, cmdlineW;
@ -2426,7 +2477,7 @@ static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES
if (!new_cmd_line)
{
SetLastError( ERROR_OUTOFMEMORY );
return FALSE;
return NULL;
}
sprintfW( new_cmd_line, argsW, winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer );
RtlInitUnicodeString( &imageW, winevdm );
@ -2454,11 +2505,29 @@ static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES
new_params->dwFlags = params->dwFlags;
new_params->wShowWindow = params->wShowWindow;
memset( &pe_info, 0, sizeof(pe_info) );
pe_info.cpu = CPU_x86;
ret = create_process( 0, psa, tsa, inherit, flags, new_params, info, unixdir, &pe_info, exec_only );
memset( pe_info, 0, sizeof(*pe_info) );
pe_info->cpu = CPU_x86;
return new_params;
}
/***********************************************************************
* create_vdm_process
*
* Create a new VDM process for a 16-bit or DOS application.
*/
static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
LPPROCESS_INFORMATION info, LPCSTR unixdir )
{
BOOL ret;
pe_image_info_t pe_info;
RTL_USER_PROCESS_PARAMETERS *new_params;
if (!(new_params = get_vdm_params( params, &pe_info ))) return FALSE;
ret = create_process( 0, psa, tsa, inherit, flags, new_params, info, unixdir, &pe_info );
RtlDestroyProcessParameters( new_params );
HeapFree( GetProcessHeap(), 0, new_cmd_line );
return ret;
}
@ -2678,18 +2747,17 @@ static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_A
wine_dbgstr_longlong(pe_info.base), wine_dbgstr_longlong(pe_info.base + pe_info.map_size),
cpu_names[pe_info.cpu] );
retv = create_process( hFile, process_attr, thread_attr,
inherit, flags, params, info, unixdir, &pe_info, FALSE );
inherit, flags, params, info, unixdir, &pe_info );
break;
case BINARY_WIN16:
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
retv = create_vdm_process( process_attr, thread_attr,
inherit, flags, params, info, unixdir, FALSE );
retv = create_vdm_process( process_attr, thread_attr, inherit, flags, params, info, unixdir );
break;
case BINARY_UNIX_LIB:
TRACE( "starting %s as %d-bit Winelib app\n",
debugstr_w(name), is_64bit_arch(pe_info.cpu) ? 64 : 32 );
retv = create_process( hFile, process_attr, thread_attr,
inherit, flags, params, info, unixdir, &pe_info, FALSE );
inherit, flags, params, info, unixdir, &pe_info );
break;
case BINARY_UNKNOWN:
/* check for .com or .bat extension */
@ -2699,7 +2767,7 @@ static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_A
{
TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
retv = create_vdm_process( process_attr, thread_attr,
inherit, flags, params, info, unixdir, FALSE );
inherit, flags, params, info, unixdir );
break;
}
if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ) )
@ -2792,8 +2860,7 @@ static void exec_process( LPCWSTR name )
HANDLE hFile;
WCHAR *p;
STARTUPINFOW startup_info = { sizeof(startup_info) };
RTL_USER_PROCESS_PARAMETERS *params;
PROCESS_INFORMATION info;
RTL_USER_PROCESS_PARAMETERS *params, *new_params;
pe_image_info_t pe_info;
BOOL is_64bit;
@ -2813,11 +2880,11 @@ static void exec_process( LPCWSTR name )
debugstr_w(name), is_64bit_arch(pe_info.cpu) ? 64 : 32,
wine_dbgstr_longlong(pe_info.base), wine_dbgstr_longlong(pe_info.base + pe_info.map_size),
cpu_names[pe_info.cpu] );
create_process( hFile, NULL, NULL, FALSE, 0, params, &info, NULL, &pe_info, TRUE );
replace_process( hFile, params, &pe_info );
break;
case BINARY_UNIX_LIB:
TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
create_process( hFile, NULL, NULL, FALSE, 0, params, &info, NULL, &pe_info, TRUE );
replace_process( hFile, params, &pe_info );
break;
case BINARY_UNKNOWN:
/* check for .com or .pif extension */
@ -2826,12 +2893,15 @@ static void exec_process( LPCWSTR name )
/* fall through */
case BINARY_WIN16:
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
create_vdm_process( NULL, NULL, FALSE, 0, params, &info, NULL, TRUE );
if (!(new_params = get_vdm_params( params, &pe_info ))) break;
replace_process( 0, new_params, &pe_info );
RtlDestroyProcessParameters( new_params );
break;
default:
break;
}
CloseHandle( hFile );
RtlDestroyProcessParameters( params );
}